FD.io VPP  v18.01.2-1-g9b554f3
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;
52  return uc;
53 }
54 
55 void
57 {
58  pool_put (udp_main.connections[uc->c_thread_index], uc);
59  if (CLIB_DEBUG)
60  memset (uc, 0xFA, sizeof (*uc));
61 }
62 
63 u32
65 {
68  udp_connection_t *listener;
69  u32 node_index;
70  void *iface_ip;
72 
73  pi = udp_get_dst_port_info (um, lcl->port, lcl->is_ip4);
74  if (pi)
75  return -1;
76 
77  pool_get (um->listener_pool, listener);
78  memset (listener, 0, sizeof (udp_connection_t));
79 
80  listener->c_lcl_port = lcl->port;
81  listener->c_c_index = listener - um->listener_pool;
82 
83  /* If we are provided a sw_if_index, bind using one of its ips */
84  if (ip_is_zero (&lcl->ip, 1) && lcl->sw_if_index != ENDPOINT_INVALID_INDEX)
85  {
86  if ((iface_ip = ip_interface_get_first_ip (lcl->sw_if_index,
87  lcl->is_ip4)))
88  ip_set (&lcl->ip, iface_ip, lcl->is_ip4);
89  }
90  ip_copy (&listener->c_lcl_ip, &lcl->ip, lcl->is_ip4);
91  listener->c_is_ip4 = lcl->is_ip4;
92  listener->c_proto = TRANSPORT_PROTO_UDP;
93  listener->c_s_index = session_index;
94  listener->c_fib_index = lcl->fib_index;
95 
96  node_index = lcl->is_ip4 ? udp4_input_node.index : udp6_input_node.index;
97  udp_register_dst_port (vm, clib_net_to_host_u16 (lcl->port), node_index,
98  1 /* is_ipv4 */ );
99  return listener->c_c_index;
100 }
101 
102 u32
103 udp_session_unbind (u32 listener_index)
104 {
106 
107  udp_connection_t *listener;
108  listener = udp_listener_get (listener_index);
109  udp_unregister_dst_port (vm, clib_net_to_host_u16 (listener->c_lcl_port),
110  listener->c_is_ip4);
111  return 0;
112 }
113 
116 {
117  udp_connection_t *us;
118 
119  us = udp_listener_get (listener_index);
120  return &us->connection;
121 }
122 
123 u32
125 {
126  udp_connection_t *uc;
128 
130 
131  vlib_buffer_push_udp (b, uc->c_lcl_port, uc->c_rmt_port, 1);
132  if (tc->is_ip4)
133  vlib_buffer_push_ip4 (vm, b, &uc->c_lcl_ip4, &uc->c_rmt_ip4,
134  IP_PROTOCOL_UDP, 1);
135  else
136  {
137  ip6_header_t *ih;
138  ih = vlib_buffer_push_ip6 (vm, b, &uc->c_lcl_ip6, &uc->c_rmt_ip6,
139  IP_PROTOCOL_UDP);
140  vnet_buffer (b)->l3_hdr_offset = (u8 *) ih - b->data;
141  }
142  vnet_buffer (b)->sw_if_index[VLIB_RX] = 0;
143  vnet_buffer (b)->sw_if_index[VLIB_TX] = ~0;
144  b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
145 
146  return 0;
147 }
148 
150 udp_session_get (u32 connection_index, u32 thread_index)
151 {
152  udp_connection_t *uc;
153  uc = udp_connection_get (connection_index, thread_index);
154  if (uc)
155  return &uc->connection;
156  return 0;
157 }
158 
159 void
160 udp_session_close (u32 connection_index, u32 thread_index)
161 {
163  udp_connection_t *uc;
164  uc = udp_connection_get (connection_index, thread_index);
165  if (uc)
166  {
167  udp_unregister_dst_port (vm, clib_net_to_host_u16 (uc->c_lcl_port),
168  uc->c_is_ip4);
170  udp_connection_free (uc);
171  }
172 }
173 
174 void
175 udp_session_cleanup (u32 connection_index, u32 thread_index)
176 {
177  udp_connection_t *uc;
178  uc = udp_connection_get (connection_index, thread_index);
179  if (uc)
180  udp_connection_free (uc);
181 }
182 
183 u8 *
184 format_udp_connection_id (u8 * s, va_list * args)
185 {
186  udp_connection_t *uc = va_arg (*args, udp_connection_t *);
187  if (!uc)
188  return s;
189  if (uc->c_is_ip4)
190  s = format (s, "[#%d][%s] %U:%d->%U:%d", uc->c_thread_index, "U",
191  format_ip4_address, &uc->c_lcl_ip4,
192  clib_net_to_host_u16 (uc->c_lcl_port), format_ip4_address,
193  &uc->c_rmt_ip4, clib_net_to_host_u16 (uc->c_rmt_port));
194  else
195  s = format (s, "[#%d][%s] %U:%d->%U:%d", uc->c_thread_index, "U",
196  format_ip6_address, &uc->c_lcl_ip6,
197  clib_net_to_host_u16 (uc->c_lcl_port), format_ip6_address,
198  &uc->c_rmt_ip6, clib_net_to_host_u16 (uc->c_rmt_port));
199  return s;
200 }
201 
202 u8 *
203 format_udp_connection (u8 * s, va_list * args)
204 {
205  udp_connection_t *uc = va_arg (*args, udp_connection_t *);
206  u32 verbose = va_arg (*args, u32);
207  if (!uc)
208  return s;
209  s = format (s, "%-50U", format_udp_connection_id, uc);
210  if (verbose)
211  {
212  if (verbose == 1)
213  s = format (s, "%-15s", "-");
214  else
215  s = format (s, "\n");
216  }
217  return s;
218 }
219 
220 u8 *
221 format_udp_session (u8 * s, va_list * args)
222 {
223  u32 uci = va_arg (*args, u32);
224  u32 thread_index = va_arg (*args, u32);
225  u32 verbose = va_arg (*args, u32);
226  udp_connection_t *uc;
227 
228  uc = udp_connection_get (uci, thread_index);
229  return format (s, "%U", format_udp_connection, uc, verbose);
230 }
231 
232 u8 *
233 format_udp_half_open_session (u8 * s, va_list * args)
234 {
235  clib_warning ("BUG");
236  return 0;
237 }
238 
239 u8 *
240 format_udp_listener_session (u8 * s, va_list * args)
241 {
242  u32 tci = va_arg (*args, u32);
244  return format (s, "%U", format_udp_connection, uc);
245 }
246 
247 u16
249 {
250  /* TODO figure out MTU of output interface */
251  return 1460;
252 }
253 
254 u32
256 {
257  /* No constraint on TX window */
258  return ~0;
259 }
260 
261 int
263 {
264  udp_main_t *um = vnet_get_udp_main ();
266  u32 thread_index = vlib_get_thread_index ();
267  udp_connection_t *uc;
268  ip46_address_t lcl_addr;
269  u32 node_index;
270  u16 lcl_port;
271 
273  &lcl_port))
274  return -1;
275 
276  while (udp_get_dst_port_info (um, lcl_port, rmt->is_ip4))
277  {
278  lcl_port = transport_alloc_local_port (TRANSPORT_PROTO_UDP, &lcl_addr);
279  if (lcl_port < 1)
280  {
281  clib_warning ("Failed to allocate src port");
282  return -1;
283  }
284  }
285 
286  node_index = rmt->is_ip4 ? udp4_input_node.index : udp6_input_node.index;
287  udp_register_dst_port (vm, lcl_port, node_index, 1 /* is_ipv4 */ );
288 
289  uc = udp_connection_alloc (thread_index);
290  ip_copy (&uc->c_rmt_ip, &rmt->ip, rmt->is_ip4);
291  ip_copy (&uc->c_lcl_ip, &lcl_addr, rmt->is_ip4);
292  uc->c_rmt_port = rmt->port;
293  uc->c_lcl_port = clib_host_to_net_u16 (lcl_port);
294  uc->c_is_ip4 = rmt->is_ip4;
295  uc->c_proto = TRANSPORT_PROTO_UDP;
296  uc->c_fib_index = rmt->fib_index;
297 
298  return uc->c_c_index;
299 }
300 
303 {
304  udp_connection_t *uc;
305  uc = udp_connection_get (conn_index, vlib_get_thread_index ());
306  return &uc->connection;
307 }
308 
309 /* *INDENT-OFF* */
311  .bind = udp_session_bind,
312  .open = udp_open_connection,
313  .unbind = udp_session_unbind,
314  .push_header = udp_push_header,
315  .get_connection = udp_session_get,
316  .get_listener = udp_session_get_listener,
317  .get_half_open = udp_half_open_session_get_transport,
318  .close = udp_session_close,
319  .cleanup = udp_session_cleanup,
320  .send_mss = udp_send_mss,
321  .send_space = udp_send_space,
322  .format_connection = format_udp_session,
323  .format_half_open = format_udp_half_open_session,
324  .format_listener = format_udp_listener_session
325 };
326 /* *INDENT-ON* */
327 
328 static clib_error_t *
330 {
331  udp_main_t *um = vnet_get_udp_main ();
332  ip_main_t *im = &ip_main;
334  u32 num_threads;
335  clib_error_t *error = 0;
336  ip_protocol_info_t *pi;
337  int i;
338 
339  if ((error = vlib_call_init_function (vm, ip_main_init)))
340  return error;
341  if ((error = vlib_call_init_function (vm, ip4_lookup_init)))
342  return error;
343  if ((error = vlib_call_init_function (vm, ip6_lookup_init)))
344  return error;
345 
346  /*
347  * Registrations
348  */
349 
350  /* IP registration */
351  pi = ip_get_protocol_info (im, IP_PROTOCOL_UDP);
352  if (pi == 0)
353  return clib_error_return (0, "UDP protocol info AWOL");
356 
357  /* Register as transport with URI */
362 
363  /*
364  * Initialize data structures
365  */
366 
367  num_threads = 1 /* main thread */ + tm->n_threads;
368  vec_validate (um->connections, num_threads - 1);
369  vec_validate (um->connection_peekers, num_threads - 1);
370  vec_validate (um->peekers_readers_locks, num_threads - 1);
371  vec_validate (um->peekers_write_locks, num_threads - 1);
372 
373  if (num_threads > 1)
374  for (i = 0; i < num_threads; i++)
375  {
378  }
379  return error;
380 }
381 
383 
384 /*
385  * fd.io coding-style-patch-verification: ON
386  *
387  * Local Variables:
388  * eval: (c-set-style "gnu")
389  * End:
390  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:432
void udp_session_cleanup(u32 connection_index, u32 thread_index)
Definition: udp.c:175
static udp_connection_t * udp_listener_get(u32 conn_index)
Definition: udp.h:153
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:337
u8 * format_udp_session(u8 *s, va_list *args)
Definition: udp.c:221
void ip_copy(ip46_address_t *dst, ip46_address_t *src, u8 is_ip4)
Definition: ip.c:67
format_function_t format_udp_header
Definition: format.h:102
struct _transport_connection transport_connection_t
u32 * connection_peekers
Definition: udp.h:133
static udp_connection_t * udp_get_connection_from_transport(transport_connection_t *tc)
Definition: udp.h:165
void ip_set(ip46_address_t *dst, void *src, u8 is_ip4)
Definition: ip.c:76
static clib_error_t * udp_init(vlib_main_t *vm)
Definition: udp.c:329
static_always_inline void clib_spinlock_unlock_if_init(clib_spinlock_t *p)
Definition: lock.h:85
#define pool_get_aligned_will_expand(P, YESNO, A)
See if pool_get will expand the pool or not.
Definition: pool.h:228
struct _transport_proto_vft transport_proto_vft_t
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:232
transport_connection_t * udp_session_get_listener(u32 listener_index)
Definition: udp.c:115
void * ip_interface_get_first_ip(u32 sw_if_index, u8 is_ip4)
Definition: ip.c:119
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
Definition: ip.h:106
u32 udp_push_header(transport_connection_t *tc, vlib_buffer_t *b)
Definition: udp.c:124
static void * vlib_buffer_push_udp(vlib_buffer_t *b, u16 sp, u16 dp, u8 offload_csum)
Definition: udp.h:251
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:225
static udp_main_t * vnet_get_udp_main()
Definition: udp.h:159
vlib_node_registration_t ip4_lookup_node
(constructor) VLIB_REGISTER_NODE (ip4_lookup_node)
Definition: ip4_forward.c:474
format_function_t format_ip4_address
Definition: format.h:79
unformat_function_t * unformat_pg_edit
Definition: ip.h:87
void udp_connection_free(udp_connection_t *uc)
Definition: udp.c:56
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
u32 udp_session_bind(u32 session_index, transport_endpoint_t *lcl)
Definition: udp.c:64
#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:732
#define vlib_call_init_function(vm, x)
Definition: init.h:162
static void clib_spinlock_init(clib_spinlock_t *p)
Definition: lock.h:33
vlib_node_registration_t udp4_input_node
(constructor) VLIB_REGISTER_NODE (udp4_input_node)
Definition: udp_input.c:257
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:133
format_function_t * format_header
Definition: ip.h:78
u32 udp_session_unbind(u32 listener_index)
Definition: udp.c:103
udp_connection_t * udp_connection_alloc(u32 thread_index)
Definition: udp.c:26
clib_spinlock_t * peekers_readers_locks
Definition: udp.h:134
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:271
vlib_node_registration_t udp6_input_node
(constructor) VLIB_REGISTER_NODE (udp6_input_node)
Definition: udp_input.c:283
#define PREDICT_FALSE(x)
Definition: clib.h:105
udp_connection_t * listener_pool
Definition: udp.h:136
u16 udp_send_mss(transport_connection_t *t)
Definition: udp.c:248
int udp_open_connection(transport_endpoint_t *rmt)
Definition: udp.c:262
#define pool_get_aligned(P, E, A)
Allocate an object E from a pool P (general version).
Definition: pool.h:188
transport_connection_t * udp_half_open_session_get_transport(u32 conn_index)
Definition: udp.c:302
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:95
vlib_main_t * vm
Definition: buffer.c:283
ip_main_t ip_main
Definition: ip_init.c:42
#define ENDPOINT_INVALID_INDEX
Definition: transport.h:97
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:104
static udp_connection_t * udp_connection_get(u32 conn_index, u32 thread_index)
Definition: udp.h:145
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:149
vlib_node_registration_t ip6_lookup_node
(constructor) VLIB_REGISTER_NODE (ip6_lookup_node)
Definition: ip6_forward.c:735
unsigned int u32
Definition: types.h:88
clib_error_t * ip4_lookup_init(vlib_main_t *vm)
Definition: ip4_forward.c:1184
clib_spinlock_t * peekers_write_locks
Definition: udp.h:135
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:203
u8 ip_is_zero(ip46_address_t *ip46_address, u8 is_ip4)
Definition: ip.c:20
Definition: defs.h:47
unsigned short u16
Definition: types.h:57
static const transport_proto_vft_t udp_proto
Definition: udp.c:310
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:578
transport_connection_t connection
Definition: udp.h:39
unsigned char u8
Definition: types.h:56
void udp_session_close(u32 connection_index, u32 thread_index)
Definition: udp.c:160
struct _transport_endpoint transport_endpoint_t
u8 * format_udp_half_open_session(u8 *s, va_list *args)
Definition: udp.c:233
u8 * format_udp_connection_id(u8 *s, va_list *args)
Definition: udp.c:184
#define vnet_buffer(b)
Definition: buffer.h:326
transport_connection_t * udp_session_get(u32 connection_index, u32 thread_index)
Definition: udp.c:150
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:32
u8 data[0]
Packet data.
Definition: buffer.h:159
int transport_alloc_local_endpoint(u8 proto, transport_endpoint_t *rmt, ip46_address_t *lcl_addr, u16 *lcl_port)
Definition: transport.c:259
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:214
static clib_error_t * ip6_lookup_init(vlib_main_t *vm)
Definition: ip6_forward.c:3012
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
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:75
u32 udp_send_space(transport_connection_t *t)
Definition: udp.c:255
udp_connection_t ** connections
Definition: udp.h:132
static_always_inline void clib_spinlock_lock_if_init(clib_spinlock_t *p)
Definition: lock.h:65
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:357
Definition: defs.h:46
u8 * format_udp_listener_session(u8 *s, va_list *args)
Definition: udp.c:240