blob: 441a6e86577630de3371568e7e039cf1f7beedf8 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
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>
Dave Barach68b0fb02017-02-28 15:15:56 -050020#include <vnet/udp/udp.h>
21#include <vnet/udp/udp_packet.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070022#include <vppinfra/sparse_vec.h>
23
Florin Coras3cbc04b2017-10-02 00:18:51 -070024#define foreach_udp_local_next \
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -080025 _ (PUNT4, "ip4-punt") \
26 _ (PUNT6, "ip6-punt") \
27 _ (DROP4, "ip4-drop") \
28 _ (DROP6, "ip6-drop") \
Chris Luke816f3e12016-06-14 16:24:47 -040029 _ (ICMP4_ERROR, "ip4-icmp-error") \
30 _ (ICMP6_ERROR, "ip6-icmp-error")
Ed Warnickecb9cada2015-12-08 15:45:58 -070031
Dave Barachd7cb1b52016-12-09 09:52:16 -050032typedef enum
33{
Florin Coras3cbc04b2017-10-02 00:18:51 -070034#define _(s,n) UDP_LOCAL_NEXT_##s,
35 foreach_udp_local_next
Ed Warnickecb9cada2015-12-08 15:45:58 -070036#undef _
Florin Coras3cbc04b2017-10-02 00:18:51 -070037 UDP_LOCAL_N_NEXT,
38} udp_local_next_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -070039
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -080040#define udp_local_next_drop(is_ip4) ((is_ip4) ? UDP_LOCAL_NEXT_DROP4 : UDP_LOCAL_NEXT_DROP6)
41#define udp_local_next_punt(is_ip4) ((is_ip4) ? UDP_LOCAL_NEXT_PUNT4 : UDP_LOCAL_NEXT_PUNT6)
42
Dave Barachd7cb1b52016-12-09 09:52:16 -050043typedef struct
44{
Ed Warnickecb9cada2015-12-08 15:45:58 -070045 u16 src_port;
46 u16 dst_port;
Chris Luke816f3e12016-06-14 16:24:47 -040047 u8 bound;
Florin Coras3cbc04b2017-10-02 00:18:51 -070048} udp_local_rx_trace_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -070049
Filip Tehlar2c49ffe2019-03-06 07:16:08 -080050#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -050051u8 *
52format_udp_rx_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -070053{
54 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
55 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Florin Coras3cbc04b2017-10-02 00:18:51 -070056 udp_local_rx_trace_t *t = va_arg (*args, udp_local_rx_trace_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -050057
Chris Luke816f3e12016-06-14 16:24:47 -040058 s = format (s, "UDP: src-port %d dst-port %d%s",
Dave Barachd7cb1b52016-12-09 09:52:16 -050059 clib_net_to_host_u16 (t->src_port),
60 clib_net_to_host_u16 (t->dst_port),
61 t->bound ? "" : " (no listener)");
Ed Warnickecb9cada2015-12-08 15:45:58 -070062 return s;
63}
Filip Tehlar2c49ffe2019-03-06 07:16:08 -080064#endif /* CLIB_MARCH_VARIANT */
Ed Warnickecb9cada2015-12-08 15:45:58 -070065
66always_inline uword
Florin Coras3cbc04b2017-10-02 00:18:51 -070067udp46_local_inline (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -050068 vlib_node_runtime_t * node,
69 vlib_frame_t * from_frame, int is_ip4)
Ed Warnickecb9cada2015-12-08 15:45:58 -070070{
Damjan Marion615fc612017-04-03 14:56:08 +020071 udp_main_t *um = &udp_main;
Dave Barachd7cb1b52016-12-09 09:52:16 -050072 __attribute__ ((unused)) u32 n_left_from, next_index, *from, *to_next;
Chris Luke816f3e12016-06-14 16:24:47 -040073 word n_no_listener = 0;
Damjan Marion615fc612017-04-03 14:56:08 +020074 u8 punt_unknown = is_ip4 ? um->punt_unknown4 : um->punt_unknown6;
Ed Warnickecb9cada2015-12-08 15:45:58 -070075
76 from = vlib_frame_vector_args (from_frame);
77 n_left_from = from_frame->n_vectors;
78
79 next_index = node->cached_next_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -070080
81 while (n_left_from > 0)
82 {
83 u32 n_left_to_next;
84
Dave Barachd7cb1b52016-12-09 09:52:16 -050085 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -070086
87 while (n_left_from >= 4 && n_left_to_next >= 2)
88 {
89 u32 bi0, bi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -050090 vlib_buffer_t *b0, *b1;
91 udp_header_t *h0 = 0, *h1 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -070092 u32 i0, i1, dst_port0, dst_port1;
Dave Barachd7cb1b52016-12-09 09:52:16 -050093 u32 advance0, advance1;
94 u32 error0, next0, error1, next1;
Ed Warnickecb9cada2015-12-08 15:45:58 -070095
96 /* Prefetch next iteration. */
97 {
Dave Barachd7cb1b52016-12-09 09:52:16 -050098 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -070099
100 p2 = vlib_get_buffer (vm, from[2]);
101 p3 = vlib_get_buffer (vm, from[3]);
102
103 vlib_prefetch_buffer_header (p2, LOAD);
104 vlib_prefetch_buffer_header (p3, LOAD);
105
106 CLIB_PREFETCH (p2->data, sizeof (h0[0]), LOAD);
107 CLIB_PREFETCH (p3->data, sizeof (h1[0]), LOAD);
108 }
109
110 bi0 = from[0];
111 bi1 = from[1];
112 to_next[0] = bi0;
113 to_next[1] = bi1;
114 from += 2;
115 to_next += 2;
116 n_left_to_next -= 2;
117 n_left_from -= 2;
118
119 b0 = vlib_get_buffer (vm, bi0);
120 b1 = vlib_get_buffer (vm, bi1);
121
Dave Barachd7cb1b52016-12-09 09:52:16 -0500122 /* ip4/6_local hands us the ip header, not the udp header */
123 if (is_ip4)
124 {
125 advance0 = sizeof (ip4_header_t);
126 advance1 = sizeof (ip4_header_t);
127 }
128 else
129 {
130 advance0 = sizeof (ip6_header_t);
131 advance1 = sizeof (ip6_header_t);
132 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700133
Dave Barachd7cb1b52016-12-09 09:52:16 -0500134 if (PREDICT_FALSE (b0->current_length < advance0 + sizeof (*h0)))
135 {
136 error0 = UDP_ERROR_LENGTH_ERROR;
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -0800137 next0 = udp_local_next_drop (is_ip4);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500138 }
139 else
140 {
141 vlib_buffer_advance (b0, advance0);
142 h0 = vlib_buffer_get_current (b0);
143 error0 = next0 = 0;
144 if (PREDICT_FALSE (clib_net_to_host_u16 (h0->length) >
145 vlib_buffer_length_in_chain (vm, b0)))
146 {
John Lo76f78ec2016-03-03 00:25:54 -0500147 error0 = UDP_ERROR_LENGTH_ERROR;
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -0800148 next0 = udp_local_next_drop (is_ip4);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500149 }
150 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700151
Dave Barachd7cb1b52016-12-09 09:52:16 -0500152 if (PREDICT_FALSE (b1->current_length < advance1 + sizeof (*h1)))
153 {
154 error1 = UDP_ERROR_LENGTH_ERROR;
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -0800155 next1 = udp_local_next_drop (is_ip4);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500156 }
157 else
158 {
159 vlib_buffer_advance (b1, advance1);
160 h1 = vlib_buffer_get_current (b1);
161 error1 = next1 = 0;
162 if (PREDICT_FALSE (clib_net_to_host_u16 (h1->length) >
163 vlib_buffer_length_in_chain (vm, b1)))
164 {
John Lo76f78ec2016-03-03 00:25:54 -0500165 error1 = UDP_ERROR_LENGTH_ERROR;
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -0800166 next1 = udp_local_next_drop (is_ip4);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500167 }
168 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700169
Ed Warnickecb9cada2015-12-08 15:45:58 -0700170 /* Index sparse array with network byte order. */
171 dst_port0 = (error0 == 0) ? h0->dst_port : 0;
172 dst_port1 = (error1 == 0) ? h1->dst_port : 0;
Damjan Marion615fc612017-04-03 14:56:08 +0200173 sparse_vec_index2 (is_ip4 ? um->next_by_dst_port4 :
174 um->next_by_dst_port6,
175 dst_port0, dst_port1, &i0, &i1);
176 next0 = (error0 == 0) ?
177 vec_elt (is_ip4 ? um->next_by_dst_port4 : um->next_by_dst_port6,
178 i0) : next0;
179 next1 = (error1 == 0) ?
180 vec_elt (is_ip4 ? um->next_by_dst_port4 : um->next_by_dst_port6,
181 i1) : next1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700182
Dave Barachd7cb1b52016-12-09 09:52:16 -0500183 if (PREDICT_FALSE (i0 == SPARSE_VEC_INVALID_INDEX))
184 {
185 // move the pointer back so icmp-error can find the
186 // ip packet header
187 vlib_buffer_advance (b0, -(word) advance0);
Chris Luke816f3e12016-06-14 16:24:47 -0400188
Dave Barachd7cb1b52016-12-09 09:52:16 -0500189 if (PREDICT_FALSE (punt_unknown))
190 {
191 b0->error = node->errors[UDP_ERROR_PUNT];
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -0800192 next0 = udp_local_next_punt (is_ip4);
Alexander Popovsky (apopovsk)740bcdb2016-11-15 15:36:23 -0800193 }
Dave Barachd7cb1b52016-12-09 09:52:16 -0500194 else if (is_ip4)
195 {
196 icmp4_error_set_vnet_buffer (b0,
197 ICMP4_destination_unreachable,
198 ICMP4_destination_unreachable_port_unreachable,
199 0);
Florin Coras3cbc04b2017-10-02 00:18:51 -0700200 next0 = UDP_LOCAL_NEXT_ICMP4_ERROR;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500201 n_no_listener++;
202 }
203 else
204 {
205 icmp6_error_set_vnet_buffer (b0,
206 ICMP6_destination_unreachable,
207 ICMP6_destination_unreachable_port_unreachable,
208 0);
Florin Coras3cbc04b2017-10-02 00:18:51 -0700209 next0 = UDP_LOCAL_NEXT_ICMP6_ERROR;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500210 n_no_listener++;
211 }
212 }
213 else
214 {
215 b0->error = node->errors[UDP_ERROR_NONE];
216 // advance to the payload
217 vlib_buffer_advance (b0, sizeof (*h0));
218 }
Chris Luke816f3e12016-06-14 16:24:47 -0400219
Dave Barachd7cb1b52016-12-09 09:52:16 -0500220 if (PREDICT_FALSE (i1 == SPARSE_VEC_INVALID_INDEX))
221 {
222 // move the pointer back so icmp-error can find the
223 // ip packet header
224 vlib_buffer_advance (b1, -(word) advance1);
Chris Luke816f3e12016-06-14 16:24:47 -0400225
Dave Barachd7cb1b52016-12-09 09:52:16 -0500226 if (PREDICT_FALSE (punt_unknown))
227 {
228 b1->error = node->errors[UDP_ERROR_PUNT];
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -0800229 next1 = udp_local_next_punt (is_ip4);
Alexander Popovsky (apopovsk)740bcdb2016-11-15 15:36:23 -0800230 }
Dave Barachd7cb1b52016-12-09 09:52:16 -0500231 else if (is_ip4)
232 {
233 icmp4_error_set_vnet_buffer (b1,
234 ICMP4_destination_unreachable,
235 ICMP4_destination_unreachable_port_unreachable,
236 0);
Florin Coras3cbc04b2017-10-02 00:18:51 -0700237 next1 = UDP_LOCAL_NEXT_ICMP4_ERROR;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500238 n_no_listener++;
239 }
240 else
241 {
242 icmp6_error_set_vnet_buffer (b1,
243 ICMP6_destination_unreachable,
244 ICMP6_destination_unreachable_port_unreachable,
245 0);
Florin Coras3cbc04b2017-10-02 00:18:51 -0700246 next1 = UDP_LOCAL_NEXT_ICMP6_ERROR;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500247 n_no_listener++;
248 }
249 }
250 else
251 {
252 b1->error = node->errors[UDP_ERROR_NONE];
253 // advance to the payload
254 vlib_buffer_advance (b1, sizeof (*h1));
255 }
256
257 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
258 {
Florin Coras3cbc04b2017-10-02 00:18:51 -0700259 udp_local_rx_trace_t *tr = vlib_add_trace (vm, node,
260 b0, sizeof (*tr));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500261 if (b0->error != node->errors[UDP_ERROR_LENGTH_ERROR])
262 {
263 tr->src_port = h0 ? h0->src_port : 0;
264 tr->dst_port = h0 ? h0->dst_port : 0;
Florin Coras3cbc04b2017-10-02 00:18:51 -0700265 tr->bound = (next0 != UDP_LOCAL_NEXT_ICMP4_ERROR &&
266 next0 != UDP_LOCAL_NEXT_ICMP6_ERROR);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500267 }
268 }
269 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
270 {
Florin Coras3cbc04b2017-10-02 00:18:51 -0700271 udp_local_rx_trace_t *tr = vlib_add_trace (vm, node,
272 b1, sizeof (*tr));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500273 if (b1->error != node->errors[UDP_ERROR_LENGTH_ERROR])
274 {
275 tr->src_port = h1 ? h1->src_port : 0;
276 tr->dst_port = h1 ? h1->dst_port : 0;
Florin Coras3cbc04b2017-10-02 00:18:51 -0700277 tr->bound = (next1 != UDP_LOCAL_NEXT_ICMP4_ERROR &&
278 next1 != UDP_LOCAL_NEXT_ICMP6_ERROR);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500279 }
280 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700281
Ed Warnickecb9cada2015-12-08 15:45:58 -0700282 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
283 to_next, n_left_to_next,
284 bi0, bi1, next0, next1);
285 }
Dave Barachd7cb1b52016-12-09 09:52:16 -0500286
Ed Warnickecb9cada2015-12-08 15:45:58 -0700287 while (n_left_from > 0 && n_left_to_next > 0)
288 {
289 u32 bi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500290 vlib_buffer_t *b0;
291 udp_header_t *h0 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700292 u32 i0, next0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500293 u32 advance0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700294
295 bi0 = from[0];
296 to_next[0] = bi0;
297 from += 1;
298 to_next += 1;
299 n_left_from -= 1;
300 n_left_to_next -= 1;
301
302 b0 = vlib_get_buffer (vm, bi0);
303
Dave Barachd7cb1b52016-12-09 09:52:16 -0500304 /* ip4/6_local hands us the ip header, not the udp header */
305 if (is_ip4)
306 advance0 = sizeof (ip4_header_t);
307 else
308 advance0 = sizeof (ip6_header_t);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700309
Dave Barachd7cb1b52016-12-09 09:52:16 -0500310 if (PREDICT_FALSE (b0->current_length < advance0 + sizeof (*h0)))
311 {
312 b0->error = node->errors[UDP_ERROR_LENGTH_ERROR];
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -0800313 next0 = udp_local_next_drop (is_ip4);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500314 goto trace_x1;
315 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700316
Dave Barachd7cb1b52016-12-09 09:52:16 -0500317 vlib_buffer_advance (b0, advance0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700318
319 h0 = vlib_buffer_get_current (b0);
320
Dave Barachd7cb1b52016-12-09 09:52:16 -0500321 if (PREDICT_TRUE (clib_net_to_host_u16 (h0->length) <=
322 vlib_buffer_length_in_chain (vm, b0)))
323 {
Damjan Marion615fc612017-04-03 14:56:08 +0200324 i0 = sparse_vec_index (is_ip4 ? um->next_by_dst_port4 :
325 um->next_by_dst_port6, h0->dst_port);
326 next0 = vec_elt (is_ip4 ? um->next_by_dst_port4 :
327 um->next_by_dst_port6, i0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700328
Dave Barachd7cb1b52016-12-09 09:52:16 -0500329 if (PREDICT_FALSE (i0 == SPARSE_VEC_INVALID_INDEX))
330 {
331 // move the pointer back so icmp-error can find the
332 // ip packet header
333 vlib_buffer_advance (b0, -(word) advance0);
Chris Luke816f3e12016-06-14 16:24:47 -0400334
Dave Barachd7cb1b52016-12-09 09:52:16 -0500335 if (PREDICT_FALSE (punt_unknown))
336 {
337 b0->error = node->errors[UDP_ERROR_PUNT];
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -0800338 next0 = udp_local_next_punt (is_ip4);
Alexander Popovsky (apopovsk)740bcdb2016-11-15 15:36:23 -0800339 }
Dave Barachd7cb1b52016-12-09 09:52:16 -0500340 else if (is_ip4)
341 {
342 icmp4_error_set_vnet_buffer (b0,
343 ICMP4_destination_unreachable,
344 ICMP4_destination_unreachable_port_unreachable,
345 0);
Florin Coras3cbc04b2017-10-02 00:18:51 -0700346 next0 = UDP_LOCAL_NEXT_ICMP4_ERROR;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500347 n_no_listener++;
348 }
349 else
350 {
351 icmp6_error_set_vnet_buffer (b0,
352 ICMP6_destination_unreachable,
353 ICMP6_destination_unreachable_port_unreachable,
354 0);
Florin Coras3cbc04b2017-10-02 00:18:51 -0700355 next0 = UDP_LOCAL_NEXT_ICMP6_ERROR;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500356 n_no_listener++;
357 }
358 }
359 else
360 {
361 b0->error = node->errors[UDP_ERROR_NONE];
362 // advance to the payload
363 vlib_buffer_advance (b0, sizeof (*h0));
364 }
365 }
366 else
367 {
368 b0->error = node->errors[UDP_ERROR_LENGTH_ERROR];
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -0800369 next0 = udp_local_next_drop (is_ip4);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500370 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700371
Dave Barachd7cb1b52016-12-09 09:52:16 -0500372 trace_x1:
373 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
374 {
Florin Coras3cbc04b2017-10-02 00:18:51 -0700375 udp_local_rx_trace_t *tr = vlib_add_trace (vm, node,
376 b0, sizeof (*tr));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500377 if (b0->error != node->errors[UDP_ERROR_LENGTH_ERROR])
378 {
379 tr->src_port = h0->src_port;
380 tr->dst_port = h0->dst_port;
Florin Coras3cbc04b2017-10-02 00:18:51 -0700381 tr->bound = (next0 != UDP_LOCAL_NEXT_ICMP4_ERROR &&
382 next0 != UDP_LOCAL_NEXT_ICMP6_ERROR);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500383 }
384 }
Chris Luke816f3e12016-06-14 16:24:47 -0400385
Ed Warnickecb9cada2015-12-08 15:45:58 -0700386 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
387 to_next, n_left_to_next,
388 bi0, next0);
389 }
390
391 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
392 }
Dave Barachd7cb1b52016-12-09 09:52:16 -0500393 vlib_error_count (vm, node->node_index, UDP_ERROR_NO_LISTENER,
394 n_no_listener);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700395 return from_frame->n_vectors;
396}
397
Dave Barachd7cb1b52016-12-09 09:52:16 -0500398static char *udp_error_strings[] = {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700399#define udp_error(n,s) s,
400#include "udp_error.def"
401#undef udp_error
402};
403
Filip Tehlar2c49ffe2019-03-06 07:16:08 -0800404VLIB_NODE_FN (udp4_local_node) (vlib_main_t * vm,
405 vlib_node_runtime_t * node,
406 vlib_frame_t * from_frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700407{
Florin Coras3cbc04b2017-10-02 00:18:51 -0700408 return udp46_local_inline (vm, node, from_frame, 1 /* is_ip4 */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -0700409}
410
Filip Tehlar2c49ffe2019-03-06 07:16:08 -0800411VLIB_NODE_FN (udp6_local_node) (vlib_main_t * vm,
412 vlib_node_runtime_t * node,
413 vlib_frame_t * from_frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700414{
Florin Coras3cbc04b2017-10-02 00:18:51 -0700415 return udp46_local_inline (vm, node, from_frame, 0 /* is_ip4 */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -0700416}
417
Dave Barachd7cb1b52016-12-09 09:52:16 -0500418/* *INDENT-OFF* */
Florin Coras3cbc04b2017-10-02 00:18:51 -0700419VLIB_REGISTER_NODE (udp4_local_node) = {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700420 .name = "ip4-udp-lookup",
421 /* Takes a vector of packets. */
422 .vector_size = sizeof (u32),
423
Ed Warnickecb9cada2015-12-08 15:45:58 -0700424 .n_errors = UDP_N_ERROR,
425 .error_strings = udp_error_strings,
426
Florin Coras3cbc04b2017-10-02 00:18:51 -0700427 .n_next_nodes = UDP_LOCAL_N_NEXT,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700428 .next_nodes = {
Florin Coras3cbc04b2017-10-02 00:18:51 -0700429#define _(s,n) [UDP_LOCAL_NEXT_##s] = n,
430 foreach_udp_local_next
Ed Warnickecb9cada2015-12-08 15:45:58 -0700431#undef _
432 },
433
434 .format_buffer = format_udp_header,
435 .format_trace = format_udp_rx_trace,
436 .unformat_buffer = unformat_udp_header,
437};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500438/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700439
Dave Barachd7cb1b52016-12-09 09:52:16 -0500440/* *INDENT-OFF* */
Florin Coras3cbc04b2017-10-02 00:18:51 -0700441VLIB_REGISTER_NODE (udp6_local_node) = {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700442 .name = "ip6-udp-lookup",
443 /* Takes a vector of packets. */
444 .vector_size = sizeof (u32),
445
Ed Warnickecb9cada2015-12-08 15:45:58 -0700446 .n_errors = UDP_N_ERROR,
447 .error_strings = udp_error_strings,
448
Florin Coras3cbc04b2017-10-02 00:18:51 -0700449 .n_next_nodes = UDP_LOCAL_N_NEXT,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700450 .next_nodes = {
Florin Coras3cbc04b2017-10-02 00:18:51 -0700451#define _(s,n) [UDP_LOCAL_NEXT_##s] = n,
452 foreach_udp_local_next
Ed Warnickecb9cada2015-12-08 15:45:58 -0700453#undef _
454 },
455
456 .format_buffer = format_udp_header,
457 .format_trace = format_udp_rx_trace,
458 .unformat_buffer = unformat_udp_header,
459};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500460/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700461
Filip Tehlar2c49ffe2019-03-06 07:16:08 -0800462#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -0500463static void
464add_dst_port (udp_main_t * um,
465 udp_dst_port_t dst_port, char *dst_port_name, u8 is_ip4)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700466{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500467 udp_dst_port_info_t *pi;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700468 u32 i;
469
470 vec_add2 (um->dst_port_infos[is_ip4], pi, 1);
471 i = pi - um->dst_port_infos[is_ip4];
472
473 pi->name = dst_port_name;
474 pi->dst_port = dst_port;
475 pi->next_index = pi->node_index = ~0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500476
Ed Warnickecb9cada2015-12-08 15:45:58 -0700477 hash_set (um->dst_port_info_by_dst_port[is_ip4], dst_port, i);
478
479 if (pi->name)
480 hash_set_mem (um->dst_port_info_by_name[is_ip4], pi->name, i);
481}
482
483void
484udp_register_dst_port (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500485 udp_dst_port_t dst_port, u32 node_index, u8 is_ip4)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700486{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500487 udp_main_t *um = &udp_main;
488 udp_dst_port_info_t *pi;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500489 u16 *n;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700490
491 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500492 clib_error_t *error = vlib_call_init_function (vm, udp_local_init);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700493 if (error)
494 clib_error_report (error);
495 }
496
497 pi = udp_get_dst_port_info (um, dst_port, is_ip4);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500498 if (!pi)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700499 {
500 add_dst_port (um, dst_port, 0, is_ip4);
501 pi = udp_get_dst_port_info (um, dst_port, is_ip4);
502 ASSERT (pi);
503 }
Dave Barachd7cb1b52016-12-09 09:52:16 -0500504
Ed Warnickecb9cada2015-12-08 15:45:58 -0700505 pi->node_index = node_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500506 pi->next_index = vlib_node_add_next (vm,
Florin Coras3cbc04b2017-10-02 00:18:51 -0700507 is_ip4 ? udp4_local_node.index
508 : udp6_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700509
510 /* Setup udp protocol -> next index sparse vector mapping. */
Damjan Marion615fc612017-04-03 14:56:08 +0200511 if (is_ip4)
512 n = sparse_vec_validate (um->next_by_dst_port4,
Damjan Marione9f929b2017-03-16 11:32:09 +0100513 clib_host_to_net_u16 (dst_port));
Damjan Marion615fc612017-04-03 14:56:08 +0200514 else
515 n = sparse_vec_validate (um->next_by_dst_port6,
516 clib_host_to_net_u16 (dst_port));
517
518 n[0] = pi->next_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700519}
520
Alexander Popovsky (apopovsk)740bcdb2016-11-15 15:36:23 -0800521void
Dave Barach68b0fb02017-02-28 15:15:56 -0500522udp_unregister_dst_port (vlib_main_t * vm, udp_dst_port_t dst_port, u8 is_ip4)
523{
524 udp_main_t *um = &udp_main;
525 udp_dst_port_info_t *pi;
Dave Barach68b0fb02017-02-28 15:15:56 -0500526 u16 *n;
527
528 pi = udp_get_dst_port_info (um, dst_port, is_ip4);
529 /* Not registered? Fagedaboudit */
530 if (!pi)
531 return;
532
533 /* Kill the mapping. Don't bother killing the pi, it may be back. */
Damjan Marion615fc612017-04-03 14:56:08 +0200534 if (is_ip4)
535 n = sparse_vec_validate (um->next_by_dst_port4,
Damjan Marione9f929b2017-03-16 11:32:09 +0100536 clib_host_to_net_u16 (dst_port));
Damjan Marion615fc612017-04-03 14:56:08 +0200537 else
538 n = sparse_vec_validate (um->next_by_dst_port6,
539 clib_host_to_net_u16 (dst_port));
540
541 n[0] = SPARSE_VEC_INVALID_INDEX;
Dave Barach68b0fb02017-02-28 15:15:56 -0500542}
543
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100544bool
545udp_is_valid_dst_port (udp_dst_port_t dst_port, u8 is_ip4)
546{
547 udp_main_t *um = &udp_main;
548 u16 *n;
549
550 if (is_ip4)
551 n = sparse_vec_validate (um->next_by_dst_port4,
552 clib_host_to_net_u16 (dst_port));
553 else
554 n = sparse_vec_validate (um->next_by_dst_port6,
555 clib_host_to_net_u16 (dst_port));
556
557 return (n[0] != SPARSE_VEC_INVALID_INDEX);
558}
559
Dave Barach68b0fb02017-02-28 15:15:56 -0500560void
Dave Barachd7cb1b52016-12-09 09:52:16 -0500561udp_punt_unknown (vlib_main_t * vm, u8 is_ip4, u8 is_add)
Alexander Popovsky (apopovsk)740bcdb2016-11-15 15:36:23 -0800562{
Damjan Marion615fc612017-04-03 14:56:08 +0200563 udp_main_t *um = &udp_main;
Alexander Popovsky (apopovsk)740bcdb2016-11-15 15:36:23 -0800564 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500565 clib_error_t *error = vlib_call_init_function (vm, udp_local_init);
Alexander Popovsky (apopovsk)740bcdb2016-11-15 15:36:23 -0800566 if (error)
567 clib_error_report (error);
568 }
569
Damjan Marion615fc612017-04-03 14:56:08 +0200570 if (is_ip4)
571 um->punt_unknown4 = is_add;
572 else
573 um->punt_unknown6 = is_add;
Alexander Popovsky (apopovsk)740bcdb2016-11-15 15:36:23 -0800574}
575
Ed Warnickecb9cada2015-12-08 15:45:58 -0700576/* Parse a UDP header. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500577uword
578unformat_udp_header (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700579{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500580 u8 **result = va_arg (*args, u8 **);
581 udp_header_t *udp;
582 __attribute__ ((unused)) int old_length;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700583 u16 src_port, dst_port;
584
585 /* Allocate space for IP header. */
586 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500587 void *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700588
589 old_length = vec_len (*result);
590 vec_add2 (*result, p, sizeof (ip4_header_t));
591 udp = p;
592 }
593
Dave Barachb7b92992018-10-17 10:38:51 -0400594 clib_memset (udp, 0, sizeof (udp[0]));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500595 if (unformat (input, "src-port %d dst-port %d", &src_port, &dst_port))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700596 {
597 udp->src_port = clib_host_to_net_u16 (src_port);
598 udp->dst_port = clib_host_to_net_u16 (dst_port);
599 return 1;
600 }
601 return 0;
602}
603
604static void
605udp_setup_node (vlib_main_t * vm, u32 node_index)
606{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500607 vlib_node_t *n = vlib_get_node (vm, node_index);
608 pg_node_t *pn = pg_get_node (node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700609
610 n->format_buffer = format_udp_header;
611 n->unformat_buffer = unformat_udp_header;
612 pn->unformat_edit = unformat_pg_udp_header;
613}
614
Dave Barachd7cb1b52016-12-09 09:52:16 -0500615clib_error_t *
616udp_local_init (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700617{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500618 udp_main_t *um = &udp_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700619 int i;
620
621 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500622 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700623 error = vlib_call_init_function (vm, udp_init);
624 if (error)
625 clib_error_report (error);
626 }
627
628
629 for (i = 0; i < 2; i++)
630 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500631 um->dst_port_info_by_name[i] = hash_create_string (0, sizeof (uword));
632 um->dst_port_info_by_dst_port[i] = hash_create (0, sizeof (uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700633 }
634
Florin Coras3cbc04b2017-10-02 00:18:51 -0700635 udp_setup_node (vm, udp4_local_node.index);
636 udp_setup_node (vm, udp6_local_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700637
Damjan Marion615fc612017-04-03 14:56:08 +0200638 um->punt_unknown4 = 0;
639 um->punt_unknown6 = 0;
640
641 um->next_by_dst_port4 = sparse_vec_new
642 ( /* elt bytes */ sizeof (um->next_by_dst_port4[0]),
643 /* bits in index */ BITS (((udp_header_t *) 0)->dst_port));
644
645 um->next_by_dst_port6 = sparse_vec_new
646 ( /* elt bytes */ sizeof (um->next_by_dst_port6[0]),
647 /* bits in index */ BITS (((udp_header_t *) 0)->dst_port));
Alexander Popovsky (apopovsk)740bcdb2016-11-15 15:36:23 -0800648
Ed Warnickecb9cada2015-12-08 15:45:58 -0700649#define _(n,s) add_dst_port (um, UDP_DST_PORT_##s, #s, 1 /* is_ip4 */);
650 foreach_udp4_dst_port
651#undef _
Ed Warnickecb9cada2015-12-08 15:45:58 -0700652#define _(n,s) add_dst_port (um, UDP_DST_PORT_##s, #s, 0 /* is_ip4 */);
Damjan Marione9f929b2017-03-16 11:32:09 +0100653 foreach_udp6_dst_port
Ed Warnickecb9cada2015-12-08 15:45:58 -0700654#undef _
Florin Coras3cbc04b2017-10-02 00:18:51 -0700655 ip4_register_protocol (IP_PROTOCOL_UDP, udp4_local_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700656 /* Note: ip6 differs from ip4, UDP is hotwired to ip6-udp-lookup */
657 return 0;
658}
659
660VLIB_INIT_FUNCTION (udp_local_init);
Filip Tehlar2c49ffe2019-03-06 07:16:08 -0800661#endif /* CLIB_MARCH_VARIANT */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500662
663/*
664 * fd.io coding-style-patch-verification: ON
665 *
666 * Local Variables:
667 * eval: (c-set-style "gnu")
668 * End:
669 */