VPP-48 Fixes for ip4/6 ttl checks and icmp responses
[vpp.git] / vnet / vnet / ip / udp_local.c
1 /*
2  * node.c: udp packet processing
3  *
4  * Copyright (c) 2013 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/ip/udp.h>
21 #include <vnet/ip/udp_packet.h>
22 #include <vppinfra/sparse_vec.h>
23
24 udp_main_t udp_main;
25
26 #define foreach_udp_input_next                  \
27   _ (PUNT, "error-punt")                        \
28   _ (DROP, "error-drop")                        \
29   _ (ICMP4_ERROR, "ip4-icmp-error")             \
30   _ (ICMP6_ERROR, "ip6-icmp-error")
31
32 typedef enum {
33 #define _(s,n) UDP_INPUT_NEXT_##s,
34   foreach_udp_input_next
35 #undef _
36   UDP_INPUT_N_NEXT,
37 } udp_input_next_t;
38
39 typedef struct {
40   u16 src_port;
41   u16 dst_port;
42   u8 bound;
43 } udp_rx_trace_t;
44
45 u8 * format_udp_rx_trace (u8 * s, va_list * args)
46 {
47   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
48   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
49   udp_rx_trace_t * t = va_arg (*args, udp_rx_trace_t *);
50     
51   s = format (s, "UDP: src-port %d dst-port %d%s",
52               clib_net_to_host_u16(t->src_port),
53               clib_net_to_host_u16(t->dst_port),
54               t->bound ? "" : " (no listener)");
55   return s;
56 }
57
58 typedef struct {
59   /* Sparse vector mapping udp dst_port in network byte order
60      to next index. */
61   u16 * next_by_dst_port;
62
63   u32 * sparse_index_by_next_index;
64 } udp_input_runtime_t;
65
66 vlib_node_registration_t udp4_input_node;
67 vlib_node_registration_t udp6_input_node;
68
69 always_inline uword
70 udp46_input_inline (vlib_main_t * vm,
71                     vlib_node_runtime_t * node,
72                     vlib_frame_t * from_frame,
73                     int is_ip4)
74 {
75   udp_input_runtime_t * rt = is_ip4 ?
76     (void *) vlib_node_get_runtime_data (vm, udp4_input_node.index)
77     : (void *) vlib_node_get_runtime_data (vm, udp6_input_node.index);
78   __attribute__((unused)) u32 n_left_from, next_index, i_next, * from, * to_next;
79   word n_no_listener = 0;
80
81   from = vlib_frame_vector_args (from_frame);
82   n_left_from = from_frame->n_vectors;
83
84   next_index = node->cached_next_index;
85   i_next = vec_elt (rt->sparse_index_by_next_index, next_index);
86
87   while (n_left_from > 0)
88     {
89       u32 n_left_to_next;
90
91       vlib_get_next_frame (vm, node, next_index,
92                            to_next, n_left_to_next);
93
94       while (n_left_from >= 4 && n_left_to_next >= 2)
95         {
96           u32 bi0, bi1;
97           vlib_buffer_t * b0, * b1;
98           udp_header_t * h0 = 0, * h1 = 0;
99           u32 i0, i1, dst_port0, dst_port1;
100           u32 advance0, advance1;
101           u32 error0, next0, error1, next1;
102
103           /* Prefetch next iteration. */
104           {
105             vlib_buffer_t * p2, * p3;
106
107             p2 = vlib_get_buffer (vm, from[2]);
108             p3 = vlib_get_buffer (vm, from[3]);
109
110             vlib_prefetch_buffer_header (p2, LOAD);
111             vlib_prefetch_buffer_header (p3, LOAD);
112
113             CLIB_PREFETCH (p2->data, sizeof (h0[0]), LOAD);
114             CLIB_PREFETCH (p3->data, sizeof (h1[0]), LOAD);
115           }
116
117           bi0 = from[0];
118           bi1 = from[1];
119           to_next[0] = bi0;
120           to_next[1] = bi1;
121           from += 2;
122           to_next += 2;
123           n_left_to_next -= 2;
124           n_left_from -= 2;
125
126           b0 = vlib_get_buffer (vm, bi0);
127           b1 = vlib_get_buffer (vm, bi1);
128
129           /* ip4/6_local hands us the ip header, not the udp header */
130           if (is_ip4) 
131             {
132               advance0 = sizeof(ip4_header_t);
133               advance1 = sizeof(ip4_header_t);
134             }
135           else
136             {
137               advance0 = sizeof(ip6_header_t);
138               advance1 = sizeof(ip6_header_t);
139             }          
140
141           if (PREDICT_FALSE(b0->current_length < advance0 + sizeof (*h0)))
142             {
143               error0 = UDP_ERROR_LENGTH_ERROR;
144               next0 = UDP_INPUT_NEXT_DROP;
145             }
146           else
147             {
148               vlib_buffer_advance (b0, advance0);
149               h0 = vlib_buffer_get_current (b0);
150               error0 = next0 = 0;
151               if (PREDICT_FALSE(clib_net_to_host_u16(h0->length) >
152                                 vlib_buffer_length_in_chain(vm, b0)))
153                 {
154                   error0 = UDP_ERROR_LENGTH_ERROR;
155                   next0 = UDP_INPUT_NEXT_DROP;
156                 }
157             }
158
159           if (PREDICT_FALSE(b1->current_length < advance1 + sizeof (*h1)))
160             {
161               error1 = UDP_ERROR_LENGTH_ERROR;
162               next1 = UDP_INPUT_NEXT_DROP;
163             }
164           else
165             {
166               vlib_buffer_advance (b1, advance1);
167               h1 = vlib_buffer_get_current (b1);
168               error1 = next1 = 0;
169               if (PREDICT_FALSE(clib_net_to_host_u16(h1->length) >
170                             vlib_buffer_length_in_chain(vm, b1)))
171                 {
172                   error1 = UDP_ERROR_LENGTH_ERROR;
173                   next1 = UDP_INPUT_NEXT_DROP;
174                 }
175             }
176
177           /* Index sparse array with network byte order. */
178           dst_port0 = (error0 == 0) ? h0->dst_port : 0;
179           dst_port1 = (error1 == 0) ? h1->dst_port : 0;
180           sparse_vec_index2 (rt->next_by_dst_port, dst_port0, dst_port1,
181                              &i0, &i1);
182           next0 = (error0 == 0) ? vec_elt(rt->next_by_dst_port, i0) : next0;
183           next1 = (error1 == 0) ? vec_elt(rt->next_by_dst_port, i1) : next1;
184
185           if (PREDICT_FALSE(next0 == SPARSE_VEC_INVALID_INDEX))
186             {
187               // move the pointer back so icmp-error can find the
188               // ip packet header
189               vlib_buffer_advance (b0, - (word)advance0);
190
191               if (is_ip4)
192                 {
193                   icmp4_error_set_vnet_buffer(b0, ICMP4_destination_unreachable,
194                         ICMP4_destination_unreachable_port_unreachable, 0);
195                   next0 = UDP_INPUT_NEXT_ICMP4_ERROR;
196                 }
197               else
198                 {
199                   icmp6_error_set_vnet_buffer(b0, ICMP6_destination_unreachable,
200                         ICMP6_destination_unreachable_port_unreachable, 0);
201                   next0 = UDP_INPUT_NEXT_ICMP6_ERROR;
202                 }
203                 n_no_listener ++;
204             }
205           else
206             {
207               b0->error = node->errors[UDP_ERROR_NONE];
208               // advance to the payload
209               vlib_buffer_advance (b0, sizeof (*h0));
210             }
211
212           if (PREDICT_FALSE(next1 == SPARSE_VEC_INVALID_INDEX))
213             {
214               // move the pointer back so icmp-error can find the
215               // ip packet header
216               vlib_buffer_advance (b1, - (word)advance1);
217
218               if (is_ip4)
219                 {
220                   icmp4_error_set_vnet_buffer(b1, ICMP4_destination_unreachable,
221                         ICMP4_destination_unreachable_port_unreachable, 0);
222                   next1 = UDP_INPUT_NEXT_ICMP4_ERROR;
223                 }
224               else
225                 {
226                   icmp6_error_set_vnet_buffer(b1, ICMP6_destination_unreachable,
227                         ICMP6_destination_unreachable_port_unreachable, 0);
228                   next1 = UDP_INPUT_NEXT_ICMP6_ERROR;
229                 }
230                 n_no_listener ++;
231             }
232           else
233             {
234               b1->error = node->errors[UDP_ERROR_NONE];
235               // advance to the payload
236               vlib_buffer_advance (b1, sizeof (*h1));
237             }
238           
239           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) 
240             {
241               udp_rx_trace_t *tr = vlib_add_trace (vm, node, 
242                                                    b0, sizeof (*tr));
243               if (b0->error != node->errors[UDP_ERROR_LENGTH_ERROR])
244                 {
245                   tr->src_port = h0->src_port;
246                   tr->dst_port = h0->dst_port;
247                   tr->bound = (next0 != UDP_INPUT_NEXT_ICMP4_ERROR &&
248                                next0 != UDP_INPUT_NEXT_ICMP6_ERROR);
249                 }
250             }
251           if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED)) 
252             {
253               udp_rx_trace_t *tr = vlib_add_trace (vm, node, 
254                                                    b1, sizeof (*tr));
255               if (b1->error != node->errors[UDP_ERROR_LENGTH_ERROR])
256                 {
257                   tr->src_port = h1->src_port;
258                   tr->dst_port = h1->dst_port;
259                   tr->bound = (next1 != UDP_INPUT_NEXT_ICMP4_ERROR &&
260                                next1 != UDP_INPUT_NEXT_ICMP6_ERROR);
261                 }
262             }
263
264           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
265                                            to_next, n_left_to_next,
266                                            bi0, bi1, next0, next1);
267         }
268     
269       while (n_left_from > 0 && n_left_to_next > 0)
270         {
271           u32 bi0;
272           vlib_buffer_t * b0;
273           udp_header_t * h0 = 0;
274           u32 i0, next0;
275           u32 advance0;
276
277           bi0 = from[0];
278           to_next[0] = bi0;
279           from += 1;
280           to_next += 1;
281           n_left_from -= 1;
282           n_left_to_next -= 1;
283
284           b0 = vlib_get_buffer (vm, bi0);
285
286           /* ip4/6_local hands us the ip header, not the udp header */
287           if (is_ip4) 
288             advance0 = sizeof(ip4_header_t);
289           else
290             advance0 = sizeof(ip6_header_t);
291
292           if (PREDICT_FALSE(b0->current_length < advance0 + sizeof (*h0)))
293             {
294               b0->error = node->errors[UDP_ERROR_LENGTH_ERROR];
295               next0 = UDP_INPUT_NEXT_DROP;
296               goto trace_x1;
297             }
298
299           vlib_buffer_advance (b0, advance0);
300
301           h0 = vlib_buffer_get_current (b0);
302
303           if (PREDICT_TRUE(clib_net_to_host_u16(h0->length) <= 
304                            vlib_buffer_length_in_chain(vm, b0)))
305             {
306               i0 = sparse_vec_index (rt->next_by_dst_port, h0->dst_port);
307               next0 = vec_elt(rt->next_by_dst_port, i0);
308
309               if (PREDICT_FALSE(next0 == SPARSE_VEC_INVALID_INDEX))
310                 {
311                   // move the pointer back so icmp-error can find the
312                   // ip packet header
313                   vlib_buffer_advance (b0, - (word)advance0);
314
315                   if (is_ip4)
316                     {
317                       icmp4_error_set_vnet_buffer(b0, ICMP4_destination_unreachable,
318                             ICMP4_destination_unreachable_port_unreachable, 0);
319                       next0 = UDP_INPUT_NEXT_ICMP4_ERROR;
320                     }
321                   else
322                     {
323                       icmp6_error_set_vnet_buffer(b0, ICMP6_destination_unreachable,
324                             ICMP6_destination_unreachable_port_unreachable, 0);
325                       next0 = UDP_INPUT_NEXT_ICMP6_ERROR;
326                     }
327                     n_no_listener ++;
328                 }
329               else
330                 {
331                   b0->error = node->errors[UDP_ERROR_NONE];
332                   // advance to the payload
333                   vlib_buffer_advance (b0, sizeof (*h0));
334                 }
335             }
336           else
337             {
338               b0->error = node->errors[UDP_ERROR_LENGTH_ERROR];
339               next0 = UDP_INPUT_NEXT_DROP;
340             }
341
342         trace_x1:
343           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) 
344             {
345               udp_rx_trace_t *tr = vlib_add_trace (vm, node, 
346                                                    b0, sizeof (*tr));
347               if (b0->error != node->errors[UDP_ERROR_LENGTH_ERROR])
348                 {
349                   tr->src_port = h0->src_port;
350                   tr->dst_port = h0->dst_port;
351                   tr->bound = (next0 != UDP_INPUT_NEXT_ICMP4_ERROR &&
352                                next0 != UDP_INPUT_NEXT_ICMP6_ERROR);
353                 }
354             }
355
356           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
357                                            to_next, n_left_to_next,
358                                            bi0, next0);
359         }
360
361       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
362     }
363   vlib_error_count(vm, node->node_index, UDP_ERROR_NO_LISTENER, n_no_listener);
364   return from_frame->n_vectors;
365 }
366
367 static char * udp_error_strings[] = {
368 #define udp_error(n,s) s,
369 #include "udp_error.def"
370 #undef udp_error
371 };
372
373 static uword
374 udp4_input (vlib_main_t * vm,
375             vlib_node_runtime_t * node,
376             vlib_frame_t * from_frame)
377 {
378   return udp46_input_inline (vm, node, from_frame, 1 /* is_ip4 */);
379 }
380
381 static uword
382 udp6_input (vlib_main_t * vm,
383             vlib_node_runtime_t * node,
384             vlib_frame_t * from_frame)
385 {
386   return udp46_input_inline (vm, node, from_frame, 0 /* is_ip4 */);
387 }
388
389
390 VLIB_REGISTER_NODE (udp4_input_node) = {
391   .function = udp4_input,
392   .name = "ip4-udp-lookup",
393   /* Takes a vector of packets. */
394   .vector_size = sizeof (u32),
395
396   .runtime_data_bytes = sizeof (udp_input_runtime_t),
397
398   .n_errors = UDP_N_ERROR,
399   .error_strings = udp_error_strings,
400
401   .n_next_nodes = UDP_INPUT_N_NEXT,
402   .next_nodes = {
403 #define _(s,n) [UDP_INPUT_NEXT_##s] = n,
404     foreach_udp_input_next
405 #undef _
406   },
407
408   .format_buffer = format_udp_header,
409   .format_trace = format_udp_rx_trace,
410   .unformat_buffer = unformat_udp_header,
411 };
412
413 VLIB_NODE_FUNCTION_MULTIARCH (udp4_input_node, udp4_input)
414
415 VLIB_REGISTER_NODE (udp6_input_node) = {
416   .function = udp6_input,
417   .name = "ip6-udp-lookup",
418   /* Takes a vector of packets. */
419   .vector_size = sizeof (u32),
420
421   .runtime_data_bytes = sizeof (udp_input_runtime_t),
422
423   .n_errors = UDP_N_ERROR,
424   .error_strings = udp_error_strings,
425
426   .n_next_nodes = UDP_INPUT_N_NEXT,
427   .next_nodes = {
428 #define _(s,n) [UDP_INPUT_NEXT_##s] = n,
429     foreach_udp_input_next
430 #undef _
431   },
432
433   .format_buffer = format_udp_header,
434   .format_trace = format_udp_rx_trace,
435   .unformat_buffer = unformat_udp_header,
436 };
437
438 VLIB_NODE_FUNCTION_MULTIARCH (udp6_input_node, udp6_input)
439
440 static void add_dst_port (udp_main_t * um,
441                           udp_dst_port_t dst_port,
442                           char * dst_port_name, u8 is_ip4)
443 {
444   udp_dst_port_info_t * pi;
445   u32 i;
446
447   vec_add2 (um->dst_port_infos[is_ip4], pi, 1);
448   i = pi - um->dst_port_infos[is_ip4];
449
450   pi->name = dst_port_name;
451   pi->dst_port = dst_port;
452   pi->next_index = pi->node_index = ~0;
453   
454   hash_set (um->dst_port_info_by_dst_port[is_ip4], dst_port, i);
455
456   if (pi->name)
457     hash_set_mem (um->dst_port_info_by_name[is_ip4], pi->name, i);
458 }
459
460 void
461 udp_register_dst_port (vlib_main_t * vm,
462                        udp_dst_port_t dst_port,
463                        u32 node_index, u8 is_ip4)
464 {
465   udp_main_t * um = &udp_main;
466   udp_dst_port_info_t * pi;
467   udp_input_runtime_t * rt;
468   u16 * n;
469   u32 i;
470
471   {
472     clib_error_t * error = vlib_call_init_function (vm, udp_local_init);
473     if (error)
474       clib_error_report (error);
475   }
476
477   pi = udp_get_dst_port_info (um, dst_port, is_ip4);
478   if (! pi) 
479     {
480       add_dst_port (um, dst_port, 0, is_ip4);
481       pi = udp_get_dst_port_info (um, dst_port, is_ip4);
482       ASSERT (pi);
483     }
484       
485   pi->node_index = node_index;
486   pi->next_index = vlib_node_add_next (vm, 
487                                        is_ip4 ? udp4_input_node.index
488                                        : udp6_input_node.index,
489                                        node_index);
490
491   /* Setup udp protocol -> next index sparse vector mapping. */
492   rt = vlib_node_get_runtime_data 
493     (vm, is_ip4 ? udp4_input_node.index: udp6_input_node.index);
494   n = sparse_vec_validate (rt->next_by_dst_port, 
495                            clib_host_to_net_u16 (dst_port));
496   n[0] = pi->next_index;
497
498   /* Rebuild next index -> sparse index inverse mapping when sparse vector
499      is updated. */
500   vec_validate (rt->sparse_index_by_next_index, pi->next_index);
501   for (i = 1; i < vec_len (rt->next_by_dst_port); i++)
502     rt->sparse_index_by_next_index[rt->next_by_dst_port[i]] = i;
503 }
504
505 /* Parse a UDP header. */
506 uword unformat_udp_header (unformat_input_t * input, va_list * args)
507 {
508   u8 ** result = va_arg (*args, u8 **);
509   udp_header_t * udp;
510   __attribute__((unused)) int old_length;
511   u16 src_port, dst_port;
512
513   /* Allocate space for IP header. */
514   {
515     void * p;
516
517     old_length = vec_len (*result);
518     vec_add2 (*result, p, sizeof (ip4_header_t));
519     udp = p;
520   }
521
522   memset (udp, 0, sizeof (udp[0]));
523   if (unformat (input, "src-port %d dst-port %d", 
524                 &src_port, &dst_port)) 
525     {
526       udp->src_port = clib_host_to_net_u16 (src_port);
527       udp->dst_port = clib_host_to_net_u16 (dst_port);
528       return 1;
529     }
530   return 0;
531 }
532
533 static void
534 udp_setup_node (vlib_main_t * vm, u32 node_index)
535 {
536   vlib_node_t * n = vlib_get_node (vm, node_index);
537   pg_node_t * pn = pg_get_node (node_index);
538
539   n->format_buffer = format_udp_header;
540   n->unformat_buffer = unformat_udp_header;
541   pn->unformat_edit = unformat_pg_udp_header;
542 }
543
544 clib_error_t * udp_local_init (vlib_main_t * vm)
545 {
546   udp_input_runtime_t * rt;
547   udp_main_t * um = &udp_main;
548   int i;
549
550   {
551     clib_error_t * error; 
552     error = vlib_call_init_function (vm, udp_init);
553     if (error)
554       clib_error_report (error);
555   }
556
557
558   for (i = 0; i < 2; i++)
559     {
560       um->dst_port_info_by_name[i] = hash_create_string (0, sizeof(uword));
561       um->dst_port_info_by_dst_port[i] = hash_create (0, sizeof(uword));
562     }
563
564   udp_setup_node (vm, udp4_input_node.index);
565   udp_setup_node (vm, udp6_input_node.index);
566
567   rt = vlib_node_get_runtime_data (vm, udp4_input_node.index);
568
569   rt->next_by_dst_port = sparse_vec_new
570     (/* elt bytes */ sizeof (rt->next_by_dst_port[0]),
571      /* bits in index */ BITS (((udp_header_t *) 0)->dst_port));
572
573   vec_validate (rt->sparse_index_by_next_index, UDP_INPUT_NEXT_DROP);
574   vec_validate (rt->sparse_index_by_next_index, UDP_INPUT_NEXT_PUNT);
575   rt->sparse_index_by_next_index[UDP_INPUT_NEXT_DROP]
576     = SPARSE_VEC_INVALID_INDEX;
577   rt->sparse_index_by_next_index[UDP_INPUT_NEXT_PUNT]
578     = SPARSE_VEC_INVALID_INDEX;
579
580 #define _(n,s) add_dst_port (um, UDP_DST_PORT_##s, #s, 1 /* is_ip4 */);
581   foreach_udp4_dst_port
582 #undef _
583
584   rt = vlib_node_get_runtime_data (vm, udp6_input_node.index);
585
586   rt->next_by_dst_port = sparse_vec_new
587     (/* elt bytes */ sizeof (rt->next_by_dst_port[0]),
588      /* bits in index */ BITS (((udp_header_t *) 0)->dst_port));
589
590   vec_validate (rt->sparse_index_by_next_index, UDP_INPUT_NEXT_DROP);
591   vec_validate (rt->sparse_index_by_next_index, UDP_INPUT_NEXT_PUNT);
592   rt->sparse_index_by_next_index[UDP_INPUT_NEXT_DROP]
593     = SPARSE_VEC_INVALID_INDEX;
594   rt->sparse_index_by_next_index[UDP_INPUT_NEXT_PUNT]
595     = SPARSE_VEC_INVALID_INDEX;
596
597 #define _(n,s) add_dst_port (um, UDP_DST_PORT_##s, #s, 0 /* is_ip4 */);
598   foreach_udp6_dst_port
599 #undef _
600
601   ip4_register_protocol (IP_PROTOCOL_UDP, udp4_input_node.index);
602   /* Note: ip6 differs from ip4, UDP is hotwired to ip6-udp-lookup */
603   return 0;
604 }
605
606 VLIB_INIT_FUNCTION (udp_local_init);