VPP-659 Improve tcp/session debugging and testing
[vpp.git] / src / vnet / udp / udp.c
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
25 udp_uri_main_t udp_uri_main;
26
27 u32
28 udp_session_bind_ip4 (u32 session_index,
29                       ip46_address_t * ip, u16 port_number_host_byte_order)
30 {
31   udp_uri_main_t *um = vnet_get_udp_main ();
32   udp_connection_t *listener;
33
34   pool_get (um->udp_listeners, listener);
35   memset (listener, 0, sizeof (udp_connection_t));
36   listener->c_lcl_port = clib_host_to_net_u16 (port_number_host_byte_order);
37   listener->c_lcl_ip4.as_u32 = ip->ip4.as_u32;
38   listener->c_proto = SESSION_TYPE_IP4_UDP;
39   udp_register_dst_port (um->vlib_main, port_number_host_byte_order,
40                          udp4_uri_input_node.index, 1 /* is_ipv4 */ );
41   return 0;
42 }
43
44 u32
45 udp_session_bind_ip6 (u32 session_index,
46                       ip46_address_t * ip, u16 port_number_host_byte_order)
47 {
48   udp_uri_main_t *um = vnet_get_udp_main ();
49   udp_connection_t *listener;
50
51   pool_get (um->udp_listeners, listener);
52   listener->c_lcl_port = clib_host_to_net_u16 (port_number_host_byte_order);
53   clib_memcpy (&listener->c_lcl_ip6, &ip->ip6, sizeof (ip6_address_t));
54   listener->c_proto = SESSION_TYPE_IP6_UDP;
55   udp_register_dst_port (um->vlib_main, port_number_host_byte_order,
56                          udp4_uri_input_node.index, 0 /* is_ipv4 */ );
57   return 0;
58 }
59
60 u32
61 udp_session_unbind_ip4 (u32 listener_index)
62 {
63   vlib_main_t *vm = vlib_get_main ();
64   udp_connection_t *listener;
65   listener = udp_listener_get (listener_index);
66
67   /* deregister the udp_local mapping */
68   udp_unregister_dst_port (vm, listener->c_lcl_port, 1 /* is_ipv4 */ );
69   return 0;
70 }
71
72 u32
73 udp_session_unbind_ip6 (u32 listener_index)
74 {
75   vlib_main_t *vm = vlib_get_main ();
76   udp_connection_t *listener;
77
78   listener = udp_listener_get (listener_index);
79
80   /* deregister the udp_local mapping */
81   udp_unregister_dst_port (vm, listener->c_lcl_port, 0 /* is_ipv4 */ );
82   return 0;
83 }
84
85 transport_connection_t *
86 udp_session_get_listener (u32 listener_index)
87 {
88   udp_connection_t *us;
89
90   us = udp_listener_get (listener_index);
91   return &us->connection;
92 }
93
94 u32
95 udp_push_header (transport_connection_t * tconn, vlib_buffer_t * b)
96 {
97   udp_connection_t *us;
98   u8 *data;
99   udp_header_t *udp;
100
101   us = (udp_connection_t *) tconn;
102
103   if (tconn->is_ip4)
104     {
105       ip4_header_t *ip;
106
107       data = vlib_buffer_get_current (b);
108       udp = (udp_header_t *) (data - sizeof (udp_header_t));
109       ip = (ip4_header_t *) ((u8 *) udp - sizeof (ip4_header_t));
110
111       /* Build packet header, swap rx key src + dst fields */
112       ip->src_address.as_u32 = us->c_lcl_ip4.as_u32;
113       ip->dst_address.as_u32 = us->c_rmt_ip4.as_u32;
114       ip->ip_version_and_header_length = 0x45;
115       ip->ttl = 254;
116       ip->protocol = IP_PROTOCOL_UDP;
117       ip->length = clib_host_to_net_u16 (b->current_length + sizeof (*udp));
118       ip->checksum = ip4_header_checksum (ip);
119
120       udp->src_port = us->c_lcl_port;
121       udp->dst_port = us->c_rmt_port;
122       udp->length = clib_host_to_net_u16 (b->current_length);
123       udp->checksum = 0;
124
125       b->current_length = sizeof (*ip) + sizeof (*udp);
126       return SESSION_QUEUE_NEXT_IP4_LOOKUP;
127     }
128   else
129     {
130       vlib_main_t *vm = vlib_get_main ();
131       ip6_header_t *ip;
132       u16 payload_length;
133       int bogus = ~0;
134
135       data = vlib_buffer_get_current (b);
136       udp = (udp_header_t *) (data - sizeof (udp_header_t));
137       ip = (ip6_header_t *) ((u8 *) udp - sizeof (ip6_header_t));
138
139       /* Build packet header, swap rx key src + dst fields */
140       clib_memcpy (&ip->src_address, &us->c_lcl_ip6, sizeof (ip6_address_t));
141       clib_memcpy (&ip->dst_address, &us->c_rmt_ip6, sizeof (ip6_address_t));
142
143       ip->ip_version_traffic_class_and_flow_label =
144         clib_host_to_net_u32 (0x6 << 28);
145
146       ip->hop_limit = 0xff;
147       ip->protocol = IP_PROTOCOL_UDP;
148
149       payload_length = vlib_buffer_length_in_chain (vm, b);
150       payload_length -= sizeof (*ip);
151
152       ip->payload_length = clib_host_to_net_u16 (payload_length);
153
154       udp->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b, ip, &bogus);
155       ASSERT (!bogus);
156
157       udp->src_port = us->c_lcl_port;
158       udp->dst_port = us->c_rmt_port;
159       udp->length = clib_host_to_net_u16 (b->current_length);
160       udp->checksum = 0;
161
162       b->current_length = sizeof (*ip) + sizeof (*udp);
163
164       return SESSION_QUEUE_NEXT_IP6_LOOKUP;
165     }
166 }
167
168 transport_connection_t *
169 udp_session_get (u32 connection_index, u32 my_thread_index)
170 {
171   udp_uri_main_t *um = vnet_get_udp_main ();
172
173   udp_connection_t *us;
174   us =
175     pool_elt_at_index (um->udp_sessions[my_thread_index], connection_index);
176   return &us->connection;
177 }
178
179 void
180 udp_session_close (u32 connection_index, u32 my_thread_index)
181 {
182   udp_uri_main_t *um = vnet_get_udp_main ();
183   pool_put_index (um->udp_sessions[my_thread_index], connection_index);
184 }
185
186 u8 *
187 format_udp_session_ip4 (u8 * s, va_list * args)
188 {
189   u32 uci = va_arg (*args, u32);
190   u32 thread_index = va_arg (*args, u32);
191   udp_connection_t *u4;
192
193   u4 = udp_connection_get (uci, thread_index);
194
195   s = format (s, "[%s] %U:%d->%U:%d", "udp", format_ip4_address,
196               &u4->c_lcl_ip4, clib_net_to_host_u16 (u4->c_lcl_port),
197               format_ip4_address, &u4->c_rmt_ip4,
198               clib_net_to_host_u16 (u4->c_rmt_port));
199   return s;
200 }
201
202 u8 *
203 format_udp_session_ip6 (u8 * s, va_list * args)
204 {
205   u32 uci = va_arg (*args, u32);
206   u32 thread_index = va_arg (*args, u32);
207   udp_connection_t *tc = udp_connection_get (uci, thread_index);
208   s = format (s, "[%s] %U:%d->%U:%d", "udp", format_ip6_address,
209               &tc->c_lcl_ip6, clib_net_to_host_u16 (tc->c_lcl_port),
210               format_ip6_address, &tc->c_rmt_ip6,
211               clib_net_to_host_u16 (tc->c_rmt_port));
212   return s;
213 }
214
215 u8 *
216 format_udp_listener_session_ip4 (u8 * s, va_list * args)
217 {
218   u32 tci = va_arg (*args, u32);
219   udp_connection_t *tc = udp_listener_get (tci);
220   s = format (s, "[%s] %U:%d->%U:%d", "udp", format_ip4_address,
221               &tc->c_lcl_ip4, clib_net_to_host_u16 (tc->c_lcl_port),
222               format_ip4_address, &tc->c_rmt_ip4,
223               clib_net_to_host_u16 (tc->c_rmt_port));
224   return s;
225 }
226
227 u8 *
228 format_udp_listener_session_ip6 (u8 * s, va_list * args)
229 {
230   u32 tci = va_arg (*args, u32);
231   udp_connection_t *tc = udp_listener_get (tci);
232   s = format (s, "[%s] %U:%d->%U:%d", "udp", format_ip6_address,
233               &tc->c_lcl_ip6, clib_net_to_host_u16 (tc->c_lcl_port),
234               format_ip6_address, &tc->c_rmt_ip6,
235               clib_net_to_host_u16 (tc->c_rmt_port));
236   return s;
237 }
238
239 u16
240 udp_send_mss_uri (transport_connection_t * t)
241 {
242   /* TODO figure out MTU of output interface */
243   return 400;
244 }
245
246 u32
247 udp_send_space_uri (transport_connection_t * t)
248 {
249   /* No constraint on TX window */
250   return ~0;
251 }
252
253 int
254 udp_open_connection (ip46_address_t * addr, u16 port)
255 {
256   clib_warning ("Not implemented");
257   return 0;
258 }
259
260 /* *INDENT-OFF* */
261 const static transport_proto_vft_t udp4_proto = {
262   .bind = udp_session_bind_ip4,
263   .open = udp_open_connection,
264   .unbind = udp_session_unbind_ip4,
265   .push_header = udp_push_header,
266   .get_connection = udp_session_get,
267   .get_listener = udp_session_get_listener,
268   .close = udp_session_close,
269   .send_mss = udp_send_mss_uri,
270   .send_space = udp_send_space_uri,
271   .format_connection = format_udp_session_ip4,
272   .format_listener = format_udp_listener_session_ip4
273 };
274
275 const static transport_proto_vft_t udp6_proto = {
276   .bind = udp_session_bind_ip6,
277   .open = udp_open_connection,
278   .unbind = udp_session_unbind_ip6,
279   .push_header = udp_push_header,
280   .get_connection = udp_session_get,
281   .get_listener = udp_session_get_listener,
282   .close = udp_session_close,
283   .send_mss = udp_send_mss_uri,
284   .send_space = udp_send_space_uri,
285   .format_connection = format_udp_session_ip6,
286   .format_listener = format_udp_listener_session_ip6
287 };
288 /* *INDENT-ON* */
289
290 static clib_error_t *
291 udp_init (vlib_main_t * vm)
292 {
293   udp_uri_main_t *um = vnet_get_udp_main ();
294   ip_main_t *im = &ip_main;
295   vlib_thread_main_t *tm = vlib_get_thread_main ();
296   u32 num_threads;
297   clib_error_t *error = 0;
298   ip_protocol_info_t *pi;
299
300   um->vlib_main = vm;
301   um->vnet_main = vnet_get_main ();
302
303   if ((error = vlib_call_init_function (vm, ip_main_init)))
304     return error;
305   if ((error = vlib_call_init_function (vm, ip4_lookup_init)))
306     return error;
307   if ((error = vlib_call_init_function (vm, ip6_lookup_init)))
308     return error;
309
310   /*
311    * Registrations
312    */
313
314   /* IP registration */
315   pi = ip_get_protocol_info (im, IP_PROTOCOL_UDP);
316   if (pi == 0)
317     return clib_error_return (0, "UDP protocol info AWOL");
318   pi->format_header = format_udp_header;
319   pi->unformat_pg_edit = unformat_pg_udp_header;
320
321
322   /* Register as transport with URI */
323   session_register_transport (SESSION_TYPE_IP4_UDP, &udp4_proto);
324   session_register_transport (SESSION_TYPE_IP6_UDP, &udp6_proto);
325
326   /*
327    * Initialize data structures
328    */
329
330   num_threads = 1 /* main thread */  + tm->n_threads;
331   vec_validate (um->udp_sessions, num_threads - 1);
332
333   return error;
334 }
335
336 VLIB_INIT_FUNCTION (udp_init);
337
338 /*
339  * fd.io coding-style-patch-verification: ON
340  *
341  * Local Variables:
342  * eval: (c-set-style "gnu")
343  * End:
344  */