blob: 57e4a60ea51b87fd67d88f74ed3a4b4812168e1b [file] [log] [blame]
Dave Barach68b0fb02017-02-28 15:15:56 -05001/*
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
25udp_uri_main_t udp_uri_main;
26
27u32
Florin Corase69f4952017-03-07 10:06:24 -080028udp_session_bind_ip4 (u32 session_index,
Dave Barach68b0fb02017-02-28 15:15:56 -050029 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
44u32
Florin Corase69f4952017-03-07 10:06:24 -080045udp_session_bind_ip6 (u32 session_index,
Dave Barach68b0fb02017-02-28 15:15:56 -050046 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
60u32
Florin Corase69f4952017-03-07 10:06:24 -080061udp_session_unbind_ip4 (u32 listener_index)
Dave Barach68b0fb02017-02-28 15:15:56 -050062{
Florin Corase69f4952017-03-07 10:06:24 -080063 vlib_main_t *vm = vlib_get_main ();
Dave Barach68b0fb02017-02-28 15:15:56 -050064 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
72u32
Florin Corase69f4952017-03-07 10:06:24 -080073udp_session_unbind_ip6 (u32 listener_index)
Dave Barach68b0fb02017-02-28 15:15:56 -050074{
Florin Corase69f4952017-03-07 10:06:24 -080075 vlib_main_t *vm = vlib_get_main ();
Dave Barach68b0fb02017-02-28 15:15:56 -050076 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
85transport_connection_t *
86udp_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
94u32
95udp_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
168transport_connection_t *
169udp_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
179void
180udp_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
186u8 *
187format_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
202u8 *
203format_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
215u8 *
216format_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
227u8 *
228format_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
239u16
240udp_send_mss_uri (transport_connection_t * t)
241{
242 /* TODO figure out MTU of output interface */
243 return 400;
244}
245
246u32
247udp_send_space_uri (transport_connection_t * t)
248{
249 /* No constraint on TX window */
250 return ~0;
251}
252
253int
254udp_open_connection (ip46_address_t * addr, u16 port)
255{
256 clib_warning ("Not implemented");
257 return 0;
258}
259
260/* *INDENT-OFF* */
261const 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
275const 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
290static clib_error_t *
291udp_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
336VLIB_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 */