41938b8f1f7cc54f7e0abb682c158187b9ca8159
[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 /* *INDENT-OFF* */
397 VLIB_REGISTER_NODE (udp4_local_node) = {
398   .name = "ip4-udp-lookup",
399   /* Takes a vector of packets. */
400   .vector_size = sizeof (u32),
401
402   .n_errors = UDP_N_ERROR,
403   .error_counters = udp_error_counters,
404
405   .n_next_nodes = UDP_LOCAL_N_NEXT,
406   .next_nodes = {
407     [UDP_LOCAL_NEXT_PUNT]= "ip4-punt",
408     [UDP_LOCAL_NEXT_DROP]= "ip4-drop",
409     [UDP_LOCAL_NEXT_ICMP]= "ip4-icmp-error",
410   },
411
412   .format_buffer = format_udp_header,
413   .format_trace = format_udp_rx_trace,
414   .unformat_buffer = unformat_udp_header,
415 };
416 /* *INDENT-ON* */
417
418 /* *INDENT-OFF* */
419 VLIB_REGISTER_NODE (udp6_local_node) = {
420   .name = "ip6-udp-lookup",
421   /* Takes a vector of packets. */
422   .vector_size = sizeof (u32),
423
424   .n_errors = UDP_N_ERROR,
425   .error_counters = udp_error_counters,
426
427   .n_next_nodes = UDP_LOCAL_N_NEXT,
428   .next_nodes = {
429     [UDP_LOCAL_NEXT_PUNT]= "ip6-punt",
430     [UDP_LOCAL_NEXT_DROP]= "ip6-drop",
431     [UDP_LOCAL_NEXT_ICMP]= "ip6-icmp-error",
432   },
433
434   .format_buffer = format_udp_header,
435   .format_trace = format_udp_rx_trace,
436   .unformat_buffer = unformat_udp_header,
437 };
438 /* *INDENT-ON* */
439
440 #ifndef CLIB_MARCH_VARIANT
441 void
442 udp_add_dst_port (udp_main_t * um, udp_dst_port_t dst_port,
443                   char *dst_port_name, u8 is_ip4)
444 {
445   udp_dst_port_info_t *pi;
446   u32 i;
447
448   vec_add2 (um->dst_port_infos[is_ip4], pi, 1);
449   i = pi - um->dst_port_infos[is_ip4];
450
451   pi->name = dst_port_name;
452   pi->dst_port = dst_port;
453   pi->next_index = pi->node_index = ~0;
454
455   hash_set (um->dst_port_info_by_dst_port[is_ip4], dst_port, i);
456
457   if (pi->name)
458     hash_set_mem (um->dst_port_info_by_name[is_ip4], pi->name, i);
459 }
460
461 void
462 udp_register_dst_port (vlib_main_t * vm,
463                        udp_dst_port_t dst_port, u32 node_index, u8 is_ip4)
464 {
465   udp_main_t *um = &udp_main;
466   udp_dst_port_info_t *pi;
467   u16 *n;
468
469   {
470     clib_error_t *error = vlib_call_init_function (vm, udp_local_init);
471     if (error)
472       clib_error_report (error);
473   }
474
475   pi = udp_get_dst_port_info (um, dst_port, is_ip4);
476   if (!pi)
477     {
478       udp_add_dst_port (um, dst_port, 0, is_ip4);
479       pi = udp_get_dst_port_info (um, dst_port, is_ip4);
480       ASSERT (pi);
481     }
482
483   pi->node_index = node_index;
484   pi->next_index = vlib_node_add_next (vm,
485                                        is_ip4 ? udp4_local_node.index
486                                        : udp6_local_node.index, node_index);
487
488   /* Setup udp protocol -> next index sparse vector mapping. */
489   if (is_ip4)
490     n = sparse_vec_validate (um->next_by_dst_port4,
491                              clib_host_to_net_u16 (dst_port));
492   else
493     n = sparse_vec_validate (um->next_by_dst_port6,
494                              clib_host_to_net_u16 (dst_port));
495
496   n[0] = pi->next_index;
497 }
498
499 void
500 udp_unregister_dst_port (vlib_main_t * vm, udp_dst_port_t dst_port, u8 is_ip4)
501 {
502   udp_main_t *um = &udp_main;
503   udp_dst_port_info_t *pi;
504   u16 *n;
505
506   pi = udp_get_dst_port_info (um, dst_port, is_ip4);
507   /* Not registered? Fagedaboudit */
508   if (!pi)
509     return;
510
511   /* Kill the mapping. Don't bother killing the pi, it may be back. */
512   if (is_ip4)
513     n = sparse_vec_validate (um->next_by_dst_port4,
514                              clib_host_to_net_u16 (dst_port));
515   else
516     n = sparse_vec_validate (um->next_by_dst_port6,
517                              clib_host_to_net_u16 (dst_port));
518
519   n[0] = UDP_NO_NODE_SET;
520 }
521
522 u8
523 udp_is_valid_dst_port (udp_dst_port_t dst_port, u8 is_ip4)
524 {
525   udp_main_t *um = &udp_main;
526   u16 *n;
527
528   if (is_ip4)
529     n = sparse_vec_validate (um->next_by_dst_port4,
530                              clib_host_to_net_u16 (dst_port));
531   else
532     n = sparse_vec_validate (um->next_by_dst_port6,
533                              clib_host_to_net_u16 (dst_port));
534
535   return (n[0] != SPARSE_VEC_INVALID_INDEX && n[0] != UDP_NO_NODE_SET);
536 }
537
538 void
539 udp_punt_unknown (vlib_main_t * vm, u8 is_ip4, u8 is_add)
540 {
541   udp_main_t *um = &udp_main;
542   {
543     clib_error_t *error = vlib_call_init_function (vm, udp_local_init);
544     if (error)
545       clib_error_report (error);
546   }
547
548   if (is_ip4)
549     um->punt_unknown4 = is_add;
550   else
551     um->punt_unknown6 = is_add;
552 }
553
554 /* Parse a UDP header. */
555 uword
556 unformat_udp_header (unformat_input_t * input, va_list * args)
557 {
558   u8 **result = va_arg (*args, u8 **);
559   udp_header_t *udp;
560   __attribute__ ((unused)) int old_length;
561   u16 src_port, dst_port;
562
563   /* Allocate space for IP header. */
564   {
565     void *p;
566
567     old_length = vec_len (*result);
568     vec_add2 (*result, p, sizeof (ip4_header_t));
569     udp = p;
570   }
571
572   clib_memset (udp, 0, sizeof (udp[0]));
573   if (unformat (input, "src-port %d dst-port %d", &src_port, &dst_port))
574     {
575       udp->src_port = clib_host_to_net_u16 (src_port);
576       udp->dst_port = clib_host_to_net_u16 (dst_port);
577       return 1;
578     }
579   return 0;
580 }
581
582 static void
583 udp_setup_node (vlib_main_t * vm, u32 node_index)
584 {
585   vlib_node_t *n = vlib_get_node (vm, node_index);
586   pg_node_t *pn = pg_get_node (node_index);
587
588   n->format_buffer = format_udp_header;
589   n->unformat_buffer = unformat_udp_header;
590   pn->unformat_edit = unformat_pg_udp_header;
591 }
592
593 clib_error_t *
594 udp_local_init (vlib_main_t * vm)
595 {
596   udp_main_t *um = &udp_main;
597   int i;
598
599   {
600     clib_error_t *error;
601     error = vlib_call_init_function (vm, udp_init);
602     if (error)
603       clib_error_report (error);
604   }
605
606
607   for (i = 0; i < 2; i++)
608     {
609       um->dst_port_info_by_name[i] = hash_create_string (0, sizeof (uword));
610       um->dst_port_info_by_dst_port[i] = hash_create (0, sizeof (uword));
611     }
612
613   udp_setup_node (vm, udp4_local_node.index);
614   udp_setup_node (vm, udp6_local_node.index);
615
616   um->punt_unknown4 = 0;
617   um->punt_unknown6 = 0;
618
619   um->next_by_dst_port4 = sparse_vec_new
620     ( /* elt bytes */ sizeof (um->next_by_dst_port4[0]),
621      /* bits in index */ BITS (((udp_header_t *) 0)->dst_port));
622
623   um->next_by_dst_port6 = sparse_vec_new
624     ( /* elt bytes */ sizeof (um->next_by_dst_port6[0]),
625      /* bits in index */ BITS (((udp_header_t *) 0)->dst_port));
626
627 #define _(n,s) udp_add_dst_port (um, UDP_DST_PORT_##s, #s, 1 /* is_ip4 */);
628   foreach_udp4_dst_port
629 #undef _
630 #define _(n,s) udp_add_dst_port (um, UDP_DST_PORT_##s, #s, 0 /* is_ip4 */);
631     foreach_udp6_dst_port
632 #undef _
633     ip4_register_protocol (IP_PROTOCOL_UDP, udp4_local_node.index);
634   /* Note: ip6 differs from ip4, UDP is hotwired to ip6-udp-lookup */
635   return 0;
636 }
637
638 VLIB_INIT_FUNCTION (udp_local_init);
639 #endif /* CLIB_MARCH_VARIANT */
640
641 /*
642  * fd.io coding-style-patch-verification: ON
643  *
644  * Local Variables:
645  * eval: (c-set-style "gnu")
646  * End:
647  */