FD.io VPP  v18.07.1-19-g511ce25
Vector Packet Processing
udp.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 /** @file
17  udp state machine, etc.
18 */
19 
20 #include <vnet/udp/udp.h>
21 #include <vnet/session/session.h>
22 #include <vnet/dpo/load_balance.h>
23 #include <vnet/fib/ip4_fib.h>
24 
26 udp_connection_alloc (u32 thread_index)
27 {
28  udp_main_t *um = &udp_main;
29  udp_connection_t *uc;
30  u32 will_expand = 0;
31  pool_get_aligned_will_expand (um->connections[thread_index], will_expand,
33 
34  if (PREDICT_FALSE (will_expand))
35  {
37  [thread_index]);
38  pool_get_aligned (udp_main.connections[thread_index], uc,
41  [thread_index]);
42  }
43  else
44  {
45  pool_get_aligned (um->connections[thread_index], uc,
47  }
48  memset (uc, 0, sizeof (*uc));
49  uc->c_c_index = uc - um->connections[thread_index];
50  uc->c_thread_index = thread_index;
51  uc->c_proto = TRANSPORT_PROTO_UDP;
53  return uc;
54 }
55 
56 void
58 {
59  pool_put (udp_main.connections[uc->c_thread_index], uc);
60  if (CLIB_DEBUG)
61  memset (uc, 0xFA, sizeof (*uc));
62 }
63 
64 u32
66 {
69  udp_connection_t *listener;
70  u32 node_index;
71  void *iface_ip;
73 
74  pi = udp_get_dst_port_info (um, lcl->port, lcl->is_ip4);
75  if (pi)
76  return -1;
77 
78  pool_get (um->listener_pool, listener);
79  memset (listener, 0, sizeof (udp_connection_t));
80 
81  listener->c_lcl_port = lcl->port;
82  listener->c_c_index = listener - um->listener_pool;
83 
84  /* If we are provided a sw_if_index, bind using one of its ips */
85  if (ip_is_zero (&lcl->ip, 1) && lcl->sw_if_index != ENDPOINT_INVALID_INDEX)
86  {
87  if ((iface_ip = ip_interface_get_first_ip (lcl->sw_if_index,
88  lcl->is_ip4)))
89  ip_set (&lcl->ip, iface_ip, lcl->is_ip4);
90  }
91  ip_copy (&listener->c_lcl_ip, &lcl->ip, lcl->is_ip4);
92  listener->c_is_ip4 = lcl->is_ip4;
93  listener->c_proto = TRANSPORT_PROTO_UDP;
94  listener->c_s_index = session_index;
95  listener->c_fib_index = lcl->fib_index;
96  clib_spinlock_init (&listener->rx_lock);
97 
98  node_index = lcl->is_ip4 ? udp4_input_node.index : udp6_input_node.index;
99  udp_register_dst_port (vm, clib_net_to_host_u16 (lcl->port), node_index,
100  1 /* is_ipv4 */ );
101  return listener->c_c_index;
102 }
103 
104 u32
105 udp_session_unbind (u32 listener_index)
106 {
108 
109  udp_connection_t *listener;
110  listener = udp_listener_get (listener_index);
111  udp_unregister_dst_port (vm, clib_net_to_host_u16 (listener->c_lcl_port),
112  listener->c_is_ip4);
113  return 0;
114 }
115 
118 {
119  udp_connection_t *us;
120 
121  us = udp_listener_get (listener_index);
122  return &us->connection;
123 }
124 
125 u32
127 {
128  udp_connection_t *uc;
130 
132 
133  vlib_buffer_push_udp (b, uc->c_lcl_port, uc->c_rmt_port, 1);
134  if (tc->is_ip4)
135  vlib_buffer_push_ip4 (vm, b, &uc->c_lcl_ip4, &uc->c_rmt_ip4,
136  IP_PROTOCOL_UDP, 1);
137  else
138  {
139  ip6_header_t *ih;
140  ih = vlib_buffer_push_ip6 (vm, b, &uc->c_lcl_ip6, &uc->c_rmt_ip6,
141  IP_PROTOCOL_UDP);
142  vnet_buffer (b)->l3_hdr_offset = (u8 *) ih - b->data;
143  }
144  vnet_buffer (b)->sw_if_index[VLIB_RX] = 0;
145  vnet_buffer (b)->sw_if_index[VLIB_TX] = uc->c_fib_index;
146  b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
147 
148  return 0;
149 }
150 
152 udp_session_get (u32 connection_index, u32 thread_index)
153 {
154  udp_connection_t *uc;
155  uc = udp_connection_get (connection_index, thread_index);
156  if (uc)
157  return &uc->connection;
158  return 0;
159 }
160 
161 void
162 udp_session_close (u32 connection_index, u32 thread_index)
163 {
165  udp_connection_t *uc;
166  uc = udp_connection_get (connection_index, thread_index);
167  if (uc)
168  {
169  udp_unregister_dst_port (vm, clib_net_to_host_u16 (uc->c_lcl_port),
170  uc->c_is_ip4);
172  udp_connection_free (uc);
173  }
174 }
175 
176 void
177 udp_session_cleanup (u32 connection_index, u32 thread_index)
178 {
179  udp_connection_t *uc;
180  uc = udp_connection_get (connection_index, thread_index);
181  if (uc)
182  udp_connection_free (uc);
183 }
184 
185 u8 *
186 format_udp_connection_id (u8 * s, va_list * args)
187 {
188  udp_connection_t *uc = va_arg (*args, udp_connection_t *);
189  if (!uc)
190  return s;
191  if (uc->c_is_ip4)
192  s = format (s, "[#%d][%s] %U:%d->%U:%d", uc->c_thread_index, "U",
193  format_ip4_address, &uc->c_lcl_ip4,
194  clib_net_to_host_u16 (uc->c_lcl_port), format_ip4_address,
195  &uc->c_rmt_ip4, clib_net_to_host_u16 (uc->c_rmt_port));
196  else
197  s = format (s, "[#%d][%s] %U:%d->%U:%d", uc->c_thread_index, "U",
198  format_ip6_address, &uc->c_lcl_ip6,
199  clib_net_to_host_u16 (uc->c_lcl_port), format_ip6_address,
200  &uc->c_rmt_ip6, clib_net_to_host_u16 (uc->c_rmt_port));
201  return s;
202 }
203 
204 u8 *
205 format_udp_connection (u8 * s, va_list * args)
206 {
207  udp_connection_t *uc = va_arg (*args, udp_connection_t *);
208  u32 verbose = va_arg (*args, u32);
209  if (!uc)
210  return s;
211  s = format (s, "%-50U", format_udp_connection_id, uc);
212  if (verbose)
213  {
214  if (verbose == 1)
215  s = format (s, "%-15s\n", "-");
216  else
217  s = format (s, "\n");
218  }
219  return s;
220 }
221 
222 u8 *
223 format_udp_session (u8 * s, va_list * args)
224 {
225  u32 uci = va_arg (*args, u32);
226  u32 thread_index = va_arg (*args, u32);
227  u32 verbose = va_arg (*args, u32);
228  udp_connection_t *uc;
229 
230  uc = udp_connection_get (uci, thread_index);
231  return format (s, "%U", format_udp_connection, uc, verbose);
232 }
233 
234 u8 *
235 format_udp_half_open_session (u8 * s, va_list * args)
236 {
237  clib_warning ("BUG");
238  return 0;
239 }
240 
241 u8 *
242 format_udp_listener_session (u8 * s, va_list * args)
243 {
244  u32 tci = va_arg (*args, u32);
246  return format (s, "%U", format_udp_connection, uc);
247 }
248 
249 u16
251 {
252  /* TODO figure out MTU of output interface */
253  return 1460;
254 }
255 
256 u32
258 {
259  /* No constraint on TX window */
260  return ~0;
261 }
262 
263 int
265 {
266  udp_main_t *um = vnet_get_udp_main ();
268  u32 thread_index = vm->thread_index;
269  udp_connection_t *uc;
270  ip46_address_t lcl_addr;
271  u32 node_index;
272  u16 lcl_port;
273 
275  &lcl_port))
276  return -1;
277 
278  while (udp_get_dst_port_info (um, lcl_port, rmt->is_ip4))
279  {
280  lcl_port = transport_alloc_local_port (TRANSPORT_PROTO_UDP, &lcl_addr);
281  if (lcl_port < 1)
282  {
283  clib_warning ("Failed to allocate src port");
284  return -1;
285  }
286  }
287 
288  node_index = rmt->is_ip4 ? udp4_input_node.index : udp6_input_node.index;
289  udp_register_dst_port (vm, lcl_port, node_index, 1 /* is_ipv4 */ );
290 
291  /* We don't poll main thread if we have workers */
292  if (vlib_num_workers ())
293  thread_index = 1;
294 
295  uc = udp_connection_alloc (thread_index);
296  ip_copy (&uc->c_rmt_ip, &rmt->ip, rmt->is_ip4);
297  ip_copy (&uc->c_lcl_ip, &lcl_addr, rmt->is_ip4);
298  uc->c_rmt_port = rmt->port;
299  uc->c_lcl_port = clib_host_to_net_u16 (lcl_port);
300  uc->c_is_ip4 = rmt->is_ip4;
301  uc->c_proto = TRANSPORT_PROTO_UDP;
302  uc->c_fib_index = rmt->fib_index;
303 
304  return uc->c_c_index;
305 }
306 
309 {
310  udp_connection_t *uc;
311  u32 thread_index;
312 
313  /* We don't poll main thread if we have workers */
314  thread_index = vlib_num_workers ()? 1 : 0;
315  uc = udp_connection_get (conn_index, thread_index);
316  return &uc->connection;
317 }
318 
319 /* *INDENT-OFF* */
321  .bind = udp_session_bind,
322  .open = udp_open_connection,
323  .unbind = udp_session_unbind,
324  .push_header = udp_push_header,
325  .get_connection = udp_session_get,
326  .get_listener = udp_session_get_listener,
327  .get_half_open = udp_session_get_half_open,
328  .close = udp_session_close,
329  .cleanup = udp_session_cleanup,
330  .send_mss = udp_send_mss,
331  .send_space = udp_send_space,
332  .format_connection = format_udp_session,
333  .format_half_open = format_udp_half_open_session,
334  .format_listener = format_udp_listener_session,
335  .tx_type = TRANSPORT_TX_DGRAM,
336  .service_type = TRANSPORT_SERVICE_CL,
337 };
338 /* *INDENT-ON* */
339 
340 
341 int
343 {
344  udp_connection_t *uc;
345  u32 uc_index;
346  uc_index = udp_open_connection (rmt);
347  uc = udp_connection_get (uc_index, vlib_get_thread_index ());
348  uc->is_connected = 1;
349  return uc_index;
350 }
351 
352 u32
354 {
355  udp_connection_t *listener;
356  u32 li;
357  li = udp_session_bind (session_index, lcl);
358  listener = udp_listener_get (li);
359  listener->is_connected = 1;
360  return li;
361 }
362 
363 /* *INDENT-OFF* */
365  .bind = udpc_connection_listen,
366  .open = udpc_connection_open,
367  .unbind = udp_session_unbind,
368  .push_header = udp_push_header,
369  .get_connection = udp_session_get,
370  .get_listener = udp_session_get_listener,
371  .get_half_open = udp_session_get_half_open,
372  .close = udp_session_close,
373  .cleanup = udp_session_cleanup,
374  .send_mss = udp_send_mss,
375  .send_space = udp_send_space,
376  .format_connection = format_udp_session,
377  .format_half_open = format_udp_half_open_session,
378  .format_listener = format_udp_listener_session,
379  .tx_type = TRANSPORT_TX_DEQUEUE,
380  .service_type = TRANSPORT_SERVICE_CL,
381 };
382 /* *INDENT-ON* */
383 
384 static clib_error_t *
386 {
387  udp_main_t *um = vnet_get_udp_main ();
388  ip_main_t *im = &ip_main;
390  u32 num_threads;
391  clib_error_t *error = 0;
392  ip_protocol_info_t *pi;
393  int i;
394 
395  if ((error = vlib_call_init_function (vm, ip_main_init)))
396  return error;
397  if ((error = vlib_call_init_function (vm, ip4_lookup_init)))
398  return error;
399  if ((error = vlib_call_init_function (vm, ip6_lookup_init)))
400  return error;
401 
402  /*
403  * Registrations
404  */
405 
406  /* IP registration */
407  pi = ip_get_protocol_info (im, IP_PROTOCOL_UDP);
408  if (pi == 0)
409  return clib_error_return (0, "UDP protocol info AWOL");
412 
413  /* Register as transport with URI */
422 
423  /*
424  * Initialize data structures
425  */
426 
427  num_threads = 1 /* main thread */ + tm->n_threads;
428  vec_validate (um->connections, num_threads - 1);
429  vec_validate (um->connection_peekers, num_threads - 1);
430  vec_validate (um->peekers_readers_locks, num_threads - 1);
431  vec_validate (um->peekers_write_locks, num_threads - 1);
432 
433  if (num_threads > 1)
434  for (i = 0; i < num_threads; i++)
435  {
438  }
439  return error;
440 }
441 
443 
444 /*
445  * fd.io coding-style-patch-verification: ON
446  *
447  * Local Variables:
448  * eval: (c-set-style "gnu")
449  * End:
450  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:437
void udp_session_cleanup(u32 connection_index, u32 thread_index)
Definition: udp.c:177
int udpc_connection_open(transport_endpoint_t *rmt)
Definition: udp.c:342
static udp_connection_t * udp_listener_get(u32 conn_index)
Definition: udp.h:156
u8 * format_udp_session(u8 *s, va_list *args)
Definition: udp.c:223
void ip_copy(ip46_address_t *dst, ip46_address_t *src, u8 is_ip4)
Definition: ip.c:81
format_function_t format_udp_header
Definition: format.h:107
struct _transport_connection transport_connection_t
u32 * connection_peekers
Definition: udp.h:136
static udp_connection_t * udp_get_connection_from_transport(transport_connection_t *tc)
Definition: udp.h:168
void ip_set(ip46_address_t *dst, void *src, u8 is_ip4)
Definition: ip.c:90
static clib_error_t * udp_init(vlib_main_t *vm)
Definition: udp.c:385
static_always_inline void clib_spinlock_unlock_if_init(clib_spinlock_t *p)
Definition: lock.h:98
transport_connection_t * udp_session_get_half_open(u32 conn_index)
Definition: udp.c:308
u32 thread_index
Definition: main.h:179
#define pool_get_aligned_will_expand(P, YESNO, A)
See if pool_get will expand the pool or not.
Definition: pool.h:231
struct _transport_proto_vft transport_proto_vft_t
int i
static udp_dst_port_info_t * udp_get_dst_port_info(udp_main_t *um, udp_dst_port_t dst_port, u8 is_ip4)
Definition: udp.h:235
transport_connection_t * udp_session_get_listener(u32 listener_index)
Definition: udp.c:117
void * ip_interface_get_first_ip(u32 sw_if_index, u8 is_ip4)
Definition: ip.c:133
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
Definition: ip.h:109
u32 udp_push_header(transport_connection_t *tc, vlib_buffer_t *b)
Definition: udp.c:126
static void * vlib_buffer_push_udp(vlib_buffer_t *b, u16 sp, u16 dp, u8 offload_csum)
Definition: udp.h:254
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:228
unsigned char u8
Definition: types.h:56
static udp_main_t * vnet_get_udp_main()
Definition: udp.h:162
vlib_node_registration_t ip4_lookup_node
(constructor) VLIB_REGISTER_NODE (ip4_lookup_node)
Definition: ip4_forward.c:104
connectionless service
format_function_t format_ip4_address
Definition: format.h:81
unformat_function_t * unformat_pg_edit
Definition: ip.h:90
void udp_connection_free(udp_connection_t *uc)
Definition: udp.c:57
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:156
u32 udp_session_bind(u32 session_index, transport_endpoint_t *lcl)
Definition: udp.c:65
#define clib_error_return(e, args...)
Definition: error.h:99
void stream_session_delete_notify(transport_connection_t *tc)
Notification from transport that connection is being deleted.
Definition: session.c:787
unsigned int u32
Definition: types.h:88
static const transport_proto_vft_t udpc_proto
Definition: udp.c:364
#define vlib_call_init_function(vm, x)
Definition: init.h:227
static void clib_spinlock_init(clib_spinlock_t *p)
Definition: lock.h:57
vlib_node_registration_t udp4_input_node
(constructor) VLIB_REGISTER_NODE (udp4_input_node)
Definition: udp_input.c:307
udp_main_t udp_main
Definition: udp_local.c:24
static ip_protocol_info_t * ip_get_protocol_info(ip_main_t *im, u32 protocol)
Definition: ip.h:136
format_function_t * format_header
Definition: ip.h:81
u32 udp_session_unbind(u32 listener_index)
Definition: udp.c:105
udp_connection_t * udp_connection_alloc(u32 thread_index)
Definition: udp.c:26
unsigned short u16
Definition: types.h:57
clib_spinlock_t * peekers_readers_locks
Definition: udp.h:137
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:274
vlib_node_registration_t udp6_input_node
(constructor) VLIB_REGISTER_NODE (udp6_input_node)
Definition: udp_input.c:333
#define PREDICT_FALSE(x)
Definition: clib.h:105
udp_connection_t * listener_pool
Definition: udp.h:139
u16 udp_send_mss(transport_connection_t *t)
Definition: udp.c:250
int udp_open_connection(transport_endpoint_t *rmt)
Definition: udp.c:264
#define pool_get_aligned(P, E, A)
Allocate an object E from a pool P (general version).
Definition: pool.h:188
clib_error_t * ip_main_init(vlib_main_t *vm)
Definition: ip_init.c:45
static_always_inline uword vlib_get_thread_index(void)
Definition: threads.h:221
format_function_t format_ip6_address
Definition: format.h:99
vlib_main_t * vm
Definition: buffer.c:294
ip_main_t ip_main
Definition: ip_init.c:42
#define ENDPOINT_INVALID_INDEX
Definition: transport.h:116
void udp_unregister_dst_port(vlib_main_t *vm, udp_dst_port_t dst_port, u8 is_ip4)
Definition: udp_local.c:530
#define clib_warning(format, args...)
Definition: error.h:59
unformat_function_t unformat_pg_udp_header
Definition: format.h:109
static udp_connection_t * udp_connection_get(u32 conn_index, u32 thread_index)
Definition: udp.h:148
void transport_register_protocol(transport_proto_t transport_proto, const transport_proto_vft_t *vft, fib_protocol_t fib_proto, u32 output_node)
Register transport virtual function table.
Definition: transport.c:173
vlib_node_registration_t ip6_lookup_node
(constructor) VLIB_REGISTER_NODE (ip6_lookup_node)
Definition: ip6_forward.c:512
clib_error_t * ip4_lookup_init(vlib_main_t *vm)
Definition: ip4_forward.c:835
clib_spinlock_t * peekers_write_locks
Definition: udp.h:138
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
u8 * format_udp_connection(u8 *s, va_list *args)
Definition: udp.c:205
unreliable transport protos
u8 ip_is_zero(ip46_address_t *ip46_address, u8 is_ip4)
Definition: ip.c:20
u32 udpc_connection_listen(u32 session_index, transport_endpoint_t *lcl)
Definition: udp.c:353
Definition: defs.h:47
static const transport_proto_vft_t udp_proto
Definition: udp.c:320
static void * vlib_buffer_push_ip6(vlib_main_t *vm, vlib_buffer_t *b, ip6_address_t *src, ip6_address_t *dst, int proto)
Push IPv6 header to buffer.
Definition: ip6.h:594
transport_connection_t connection
must be first
Definition: udp.h:41
clib_spinlock_t rx_lock
rx fifo lock
Definition: udp.h:42
void udp_session_close(u32 connection_index, u32 thread_index)
Definition: udp.c:162
struct _transport_endpoint transport_endpoint_t
u8 * format_udp_half_open_session(u8 *s, va_list *args)
Definition: udp.c:235
u8 * format_udp_connection_id(u8 *s, va_list *args)
Definition: udp.c:186
#define vnet_buffer(b)
Definition: buffer.h:360
transport_connection_t * udp_session_get(u32 connection_index, u32 thread_index)
Definition: udp.c:152
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:32
static u32 vlib_num_workers()
Definition: threads.h:375
u8 data[0]
Packet data.
Definition: buffer.h:172
int transport_alloc_local_endpoint(u8 proto, transport_endpoint_t *rmt, ip46_address_t *lcl_addr, u16 *lcl_port)
Definition: transport.c:301
void udp_register_dst_port(vlib_main_t *vm, udp_dst_port_t dst_port, u32 node_index, u8 is_ip4)
Definition: udp_local.c:492
int transport_alloc_local_port(u8 proto, ip46_address_t *ip)
Allocate local port and add if successful add entry to local endpoint table to mark the pair as used...
Definition: transport.c:256
static clib_error_t * ip6_lookup_init(vlib_main_t *vm)
Definition: ip6_forward.c:2577
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:62
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:111
u32 udp_send_space(transport_connection_t *t)
Definition: udp.c:257
udp_connection_t ** connections
Definition: udp.h:135
static_always_inline void clib_spinlock_lock_if_init(clib_spinlock_t *p)
Definition: lock.h:82
static void * vlib_buffer_push_ip4(vlib_main_t *vm, vlib_buffer_t *b, ip4_address_t *src, ip4_address_t *dst, int proto, u8 csum_offload)
Push IPv4 header to buffer.
Definition: ip4.h:345
Definition: defs.h:46
u8 is_connected
connected mode
Definition: udp.h:43
u8 * format_udp_listener_session(u8 *s, va_list *args)
Definition: udp.c:242