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