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