VPP-598: tcp stack initial commit
[vpp.git] / src / vnet / udp / udp.h
1 /*
2  * Copyright (c) 2017 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 #ifndef __included_udp_h__
16 #define __included_udp_h__
17
18 #include <vnet/vnet.h>
19 #include <vnet/udp/udp_packet.h>
20 #include <vnet/ip/ip.h>
21 #include <vnet/ip/ip4.h>
22 #include <vnet/ip/ip4_packet.h>
23 #include <vnet/pg/pg.h>
24 #include <vnet/ip/format.h>
25
26 #include <vnet/ip/ip.h>
27 #include <vnet/session/transport.h>
28
29 typedef struct
30 {
31   transport_connection_t connection;          /** must be first */
32
33   /** ersatz MTU to limit fifo pushes to test data size */
34   u32 mtu;
35 } udp_connection_t;
36
37 typedef struct _udp_uri_main
38 {
39   /* Per-worker thread udp connection pools */
40   udp_connection_t **udp_sessions;
41   udp_connection_t *udp_listeners;
42
43   /* convenience */
44   vlib_main_t *vlib_main;
45   vnet_main_t *vnet_main;
46   ip4_main_t *ip4_main;
47   ip6_main_t *ip6_main;
48 } udp_uri_main_t;
49
50 extern udp_uri_main_t udp_uri_main;
51 extern vlib_node_registration_t udp4_uri_input_node;
52
53 always_inline udp_uri_main_t *
54 vnet_get_udp_main ()
55 {
56   return &udp_uri_main;
57 }
58
59 always_inline udp_connection_t *
60 udp_connection_get (u32 conn_index, u32 thread_index)
61 {
62   return pool_elt_at_index (udp_uri_main.udp_sessions[thread_index],
63                             conn_index);
64 }
65
66 always_inline udp_connection_t *
67 udp_listener_get (u32 conn_index)
68 {
69   return pool_elt_at_index (udp_uri_main.udp_listeners, conn_index);
70 }
71
72 typedef enum
73 {
74 #define udp_error(n,s) UDP_ERROR_##n,
75 #include <vnet/udp/udp_error.def>
76 #undef udp_error
77   UDP_N_ERROR,
78 } udp_error_t;
79
80 #define foreach_udp4_dst_port                   \
81 _ (67, dhcp_to_server)                          \
82 _ (68, dhcp_to_client)                          \
83 _ (500, ikev2)                                  \
84 _ (3784, bfd4)                                  \
85 _ (3785, bfd_echo4)                             \
86 _ (4341, lisp_gpe)                              \
87 _ (4342, lisp_cp)                               \
88 _ (4739, ipfix)                                 \
89 _ (4789, vxlan)                                 \
90 _ (4789, vxlan6)                                \
91 _ (4790, vxlan_gpe)                             \
92 _ (6633, vpath_3)
93
94
95 #define foreach_udp6_dst_port                   \
96 _ (547, dhcpv6_to_server)                       \
97 _ (546, dhcpv6_to_client)                       \
98 _ (3784, bfd6)                                  \
99 _ (3785, bfd_echo6)                             \
100 _ (4341, lisp_gpe6)                             \
101 _ (4342, lisp_cp6)                              \
102 _ (4790, vxlan6_gpe)      \
103 _ (6633, vpath6_3)
104
105 typedef enum
106 {
107 #define _(n,f) UDP_DST_PORT_##f = n,
108   foreach_udp4_dst_port foreach_udp6_dst_port
109 #undef _
110 } udp_dst_port_t;
111
112 typedef enum
113 {
114 #define _(n,f) UDP6_DST_PORT_##f = n,
115   foreach_udp6_dst_port
116 #undef _
117 } udp6_dst_port_t;
118
119 typedef struct
120 {
121   /* Name (a c string). */
122   char *name;
123
124   /* GRE protocol type in host byte order. */
125   udp_dst_port_t dst_port;
126
127   /* Node which handles this type. */
128   u32 node_index;
129
130   /* Next index for this type. */
131   u32 next_index;
132 } udp_dst_port_info_t;
133
134 typedef enum
135 {
136   UDP_IP6 = 0,
137   UDP_IP4,                      /* the code is full of is_ip4... */
138   N_UDP_AF,
139 } udp_af_t;
140
141 typedef struct
142 {
143   udp_dst_port_info_t *dst_port_infos[N_UDP_AF];
144
145   /* Hash tables mapping name/protocol to protocol info index. */
146   uword *dst_port_info_by_name[N_UDP_AF];
147   uword *dst_port_info_by_dst_port[N_UDP_AF];
148
149   /* convenience */
150   vlib_main_t *vlib_main;
151 } udp_main_t;
152
153 always_inline udp_dst_port_info_t *
154 udp_get_dst_port_info (udp_main_t * um, udp_dst_port_t dst_port, u8 is_ip4)
155 {
156   uword *p = hash_get (um->dst_port_info_by_dst_port[is_ip4], dst_port);
157   return p ? vec_elt_at_index (um->dst_port_infos[is_ip4], p[0]) : 0;
158 }
159
160 format_function_t format_udp_header;
161 format_function_t format_udp_rx_trace;
162
163 unformat_function_t unformat_udp_header;
164
165 void udp_register_dst_port (vlib_main_t * vm,
166                             udp_dst_port_t dst_port,
167                             u32 node_index, u8 is_ip4);
168
169 void
170 udp_unregister_dst_port (vlib_main_t * vm,
171                          udp_dst_port_t dst_port, u8 is_ip4);
172
173 void udp_punt_unknown (vlib_main_t * vm, u8 is_ip4, u8 is_add);
174
175 always_inline void
176 ip_udp_fixup_one (vlib_main_t * vm, vlib_buffer_t * b0, u8 is_ip4)
177 {
178   u16 new_l0;
179   udp_header_t *udp0;
180
181   if (is_ip4)
182     {
183       ip4_header_t *ip0;
184       ip_csum_t sum0;
185       u16 old_l0 = 0;
186
187       ip0 = vlib_buffer_get_current (b0);
188
189       /* fix the <bleep>ing outer-IP checksum */
190       sum0 = ip0->checksum;
191       /* old_l0 always 0, see the rewrite setup */
192       new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
193
194       sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
195                              length /* changed member */ );
196       ip0->checksum = ip_csum_fold (sum0);
197       ip0->length = new_l0;
198
199       /* Fix UDP length */
200       udp0 = (udp_header_t *) (ip0 + 1);
201       new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0)
202                                      - sizeof (*ip0));
203       udp0->length = new_l0;
204     }
205   else
206     {
207       ip6_header_t *ip0;
208       int bogus0;
209
210       ip0 = vlib_buffer_get_current (b0);
211
212       new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0)
213                                      - sizeof (*ip0));
214       ip0->payload_length = new_l0;
215
216       /* Fix UDP length */
217       udp0 = (udp_header_t *) (ip0 + 1);
218       udp0->length = new_l0;
219
220       udp0->checksum =
221         ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip0, &bogus0);
222       ASSERT (bogus0 == 0);
223
224       if (udp0->checksum == 0)
225         udp0->checksum = 0xffff;
226     }
227 }
228
229 always_inline void
230 ip_udp_encap_one (vlib_main_t * vm, vlib_buffer_t * b0, u8 * ec0, word ec_len,
231                   u8 is_ip4)
232 {
233   vlib_buffer_advance (b0, -ec_len);
234
235   if (is_ip4)
236     {
237       ip4_header_t *ip0;
238
239       ip0 = vlib_buffer_get_current (b0);
240
241       /* Apply the encap string. */
242       clib_memcpy (ip0, ec0, ec_len);
243       ip_udp_fixup_one (vm, b0, 1);
244     }
245   else
246     {
247       ip6_header_t *ip0;
248
249       ip0 = vlib_buffer_get_current (b0);
250
251       /* Apply the encap string. */
252       clib_memcpy (ip0, ec0, ec_len);
253       ip_udp_fixup_one (vm, b0, 0);
254     }
255 }
256
257 always_inline void
258 ip_udp_encap_two (vlib_main_t * vm, vlib_buffer_t * b0, vlib_buffer_t * b1,
259                   u8 * ec0, u8 * ec1, word ec_len, u8 is_v4)
260 {
261   u16 new_l0, new_l1;
262   udp_header_t *udp0, *udp1;
263
264   ASSERT (_vec_len (ec0) == _vec_len (ec1));
265
266   vlib_buffer_advance (b0, -ec_len);
267   vlib_buffer_advance (b1, -ec_len);
268
269   if (is_v4)
270     {
271       ip4_header_t *ip0, *ip1;
272       ip_csum_t sum0, sum1;
273       u16 old_l0 = 0, old_l1 = 0;
274
275       ip0 = vlib_buffer_get_current (b0);
276       ip1 = vlib_buffer_get_current (b1);
277
278       /* Apply the encap string */
279       clib_memcpy (ip0, ec0, ec_len);
280       clib_memcpy (ip1, ec1, ec_len);
281
282       /* fix the <bleep>ing outer-IP checksum */
283       sum0 = ip0->checksum;
284       sum1 = ip1->checksum;
285
286       /* old_l0 always 0, see the rewrite setup */
287       new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
288       new_l1 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b1));
289
290       sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
291                              length /* changed member */ );
292       sum1 = ip_csum_update (sum1, old_l1, new_l1, ip4_header_t,
293                              length /* changed member */ );
294
295       ip0->checksum = ip_csum_fold (sum0);
296       ip1->checksum = ip_csum_fold (sum1);
297
298       ip0->length = new_l0;
299       ip1->length = new_l1;
300
301       /* Fix UDP length */
302       udp0 = (udp_header_t *) (ip0 + 1);
303       udp1 = (udp_header_t *) (ip1 + 1);
304
305       new_l0 =
306         clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0) -
307                               sizeof (*ip0));
308       new_l1 =
309         clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b1) -
310                               sizeof (*ip1));
311       udp0->length = new_l0;
312       udp1->length = new_l1;
313     }
314   else
315     {
316       ip6_header_t *ip0, *ip1;
317       int bogus0, bogus1;
318
319       ip0 = vlib_buffer_get_current (b0);
320       ip1 = vlib_buffer_get_current (b1);
321
322       /* Apply the encap string. */
323       clib_memcpy (ip0, ec0, ec_len);
324       clib_memcpy (ip1, ec1, ec_len);
325
326       new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0)
327                                      - sizeof (*ip0));
328       new_l1 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b1)
329                                      - sizeof (*ip1));
330       ip0->payload_length = new_l0;
331       ip1->payload_length = new_l1;
332
333       /* Fix UDP length */
334       udp0 = (udp_header_t *) (ip0 + 1);
335       udp1 = (udp_header_t *) (ip1 + 1);
336
337       udp0->length = new_l0;
338       udp1->length = new_l1;
339
340       udp0->checksum =
341         ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip0, &bogus0);
342       udp1->checksum =
343         ip6_tcp_udp_icmp_compute_checksum (vm, b1, ip1, &bogus1);
344       ASSERT (bogus0 == 0);
345       ASSERT (bogus1 == 0);
346
347       if (udp0->checksum == 0)
348         udp0->checksum = 0xffff;
349       if (udp1->checksum == 0)
350         udp1->checksum = 0xffff;
351     }
352 }
353
354 /*
355  * fd.io coding-style-patch-verification: ON
356  *
357  * Local Variables:
358  * eval: (c-set-style "gnu")
359  * End:
360  */
361
362 #endif /* __included_udp_h__ */