Add GTP-U plugin. VPP-694
[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 _ (2152, GTPU)                                  \
85 _ (3784, bfd4)                                  \
86 _ (3785, bfd_echo4)                             \
87 _ (4341, lisp_gpe)                              \
88 _ (4342, lisp_cp)                               \
89 _ (4739, ipfix)                                 \
90 _ (4789, vxlan)                                 \
91 _ (4789, vxlan6)                                \
92 _ (4790, vxlan_gpe)                             \
93 _ (6633, vpath_3)
94
95
96 #define foreach_udp6_dst_port                   \
97 _ (547, dhcpv6_to_server)                       \
98 _ (546, dhcpv6_to_client)                       \
99 _ (2152, GTPU6)                                 \
100 _ (3784, bfd6)                                  \
101 _ (3785, bfd_echo6)                             \
102 _ (4341, lisp_gpe6)                             \
103 _ (4342, lisp_cp6)                              \
104 _ (4790, vxlan6_gpe)      \
105 _ (6633, vpath6_3)
106
107 typedef enum
108 {
109 #define _(n,f) UDP_DST_PORT_##f = n,
110   foreach_udp4_dst_port foreach_udp6_dst_port
111 #undef _
112 } udp_dst_port_t;
113
114 typedef enum
115 {
116 #define _(n,f) UDP6_DST_PORT_##f = n,
117   foreach_udp6_dst_port
118 #undef _
119 } udp6_dst_port_t;
120
121 typedef struct
122 {
123   /* Name (a c string). */
124   char *name;
125
126   /* GRE protocol type in host byte order. */
127   udp_dst_port_t dst_port;
128
129   /* Node which handles this type. */
130   u32 node_index;
131
132   /* Next index for this type. */
133   u32 next_index;
134 } udp_dst_port_info_t;
135
136 typedef enum
137 {
138   UDP_IP6 = 0,
139   UDP_IP4,                      /* the code is full of is_ip4... */
140   N_UDP_AF,
141 } udp_af_t;
142
143 typedef struct
144 {
145   udp_dst_port_info_t *dst_port_infos[N_UDP_AF];
146
147   /* Hash tables mapping name/protocol to protocol info index. */
148   uword *dst_port_info_by_name[N_UDP_AF];
149   uword *dst_port_info_by_dst_port[N_UDP_AF];
150
151   /* Sparse vector mapping udp dst_port in network byte order
152      to next index. */
153   u16 *next_by_dst_port4;
154   u16 *next_by_dst_port6;
155   u8 punt_unknown4;
156   u8 punt_unknown6;
157
158   /* convenience */
159   vlib_main_t *vlib_main;
160 } udp_main_t;
161
162 always_inline udp_dst_port_info_t *
163 udp_get_dst_port_info (udp_main_t * um, udp_dst_port_t dst_port, u8 is_ip4)
164 {
165   uword *p = hash_get (um->dst_port_info_by_dst_port[is_ip4], dst_port);
166   return p ? vec_elt_at_index (um->dst_port_infos[is_ip4], p[0]) : 0;
167 }
168
169 format_function_t format_udp_header;
170 format_function_t format_udp_rx_trace;
171
172 unformat_function_t unformat_udp_header;
173
174 void udp_register_dst_port (vlib_main_t * vm,
175                             udp_dst_port_t dst_port,
176                             u32 node_index, u8 is_ip4);
177
178 void
179 udp_unregister_dst_port (vlib_main_t * vm,
180                          udp_dst_port_t dst_port, u8 is_ip4);
181
182 void udp_punt_unknown (vlib_main_t * vm, u8 is_ip4, u8 is_add);
183
184 always_inline void
185 ip_udp_fixup_one (vlib_main_t * vm, vlib_buffer_t * b0, u8 is_ip4)
186 {
187   u16 new_l0;
188   udp_header_t *udp0;
189
190   if (is_ip4)
191     {
192       ip4_header_t *ip0;
193       ip_csum_t sum0;
194       u16 old_l0 = 0;
195
196       ip0 = vlib_buffer_get_current (b0);
197
198       /* fix the <bleep>ing outer-IP checksum */
199       sum0 = ip0->checksum;
200       /* old_l0 always 0, see the rewrite setup */
201       new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
202
203       sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
204                              length /* changed member */ );
205       ip0->checksum = ip_csum_fold (sum0);
206       ip0->length = new_l0;
207
208       /* Fix UDP length */
209       udp0 = (udp_header_t *) (ip0 + 1);
210       new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0)
211                                      - sizeof (*ip0));
212       udp0->length = new_l0;
213     }
214   else
215     {
216       ip6_header_t *ip0;
217       int bogus0;
218
219       ip0 = vlib_buffer_get_current (b0);
220
221       new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0)
222                                      - sizeof (*ip0));
223       ip0->payload_length = new_l0;
224
225       /* Fix UDP length */
226       udp0 = (udp_header_t *) (ip0 + 1);
227       udp0->length = new_l0;
228
229       udp0->checksum =
230         ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip0, &bogus0);
231       ASSERT (bogus0 == 0);
232
233       if (udp0->checksum == 0)
234         udp0->checksum = 0xffff;
235     }
236 }
237
238 always_inline void
239 ip_udp_encap_one (vlib_main_t * vm, vlib_buffer_t * b0, u8 * ec0, word ec_len,
240                   u8 is_ip4)
241 {
242   vlib_buffer_advance (b0, -ec_len);
243
244   if (is_ip4)
245     {
246       ip4_header_t *ip0;
247
248       ip0 = vlib_buffer_get_current (b0);
249
250       /* Apply the encap string. */
251       clib_memcpy (ip0, ec0, ec_len);
252       ip_udp_fixup_one (vm, b0, 1);
253     }
254   else
255     {
256       ip6_header_t *ip0;
257
258       ip0 = vlib_buffer_get_current (b0);
259
260       /* Apply the encap string. */
261       clib_memcpy (ip0, ec0, ec_len);
262       ip_udp_fixup_one (vm, b0, 0);
263     }
264 }
265
266 always_inline void
267 ip_udp_encap_two (vlib_main_t * vm, vlib_buffer_t * b0, vlib_buffer_t * b1,
268                   u8 * ec0, u8 * ec1, word ec_len, u8 is_v4)
269 {
270   u16 new_l0, new_l1;
271   udp_header_t *udp0, *udp1;
272
273   ASSERT (_vec_len (ec0) == _vec_len (ec1));
274
275   vlib_buffer_advance (b0, -ec_len);
276   vlib_buffer_advance (b1, -ec_len);
277
278   if (is_v4)
279     {
280       ip4_header_t *ip0, *ip1;
281       ip_csum_t sum0, sum1;
282       u16 old_l0 = 0, old_l1 = 0;
283
284       ip0 = vlib_buffer_get_current (b0);
285       ip1 = vlib_buffer_get_current (b1);
286
287       /* Apply the encap string */
288       clib_memcpy (ip0, ec0, ec_len);
289       clib_memcpy (ip1, ec1, ec_len);
290
291       /* fix the <bleep>ing outer-IP checksum */
292       sum0 = ip0->checksum;
293       sum1 = ip1->checksum;
294
295       /* old_l0 always 0, see the rewrite setup */
296       new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
297       new_l1 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b1));
298
299       sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
300                              length /* changed member */ );
301       sum1 = ip_csum_update (sum1, old_l1, new_l1, ip4_header_t,
302                              length /* changed member */ );
303
304       ip0->checksum = ip_csum_fold (sum0);
305       ip1->checksum = ip_csum_fold (sum1);
306
307       ip0->length = new_l0;
308       ip1->length = new_l1;
309
310       /* Fix UDP length */
311       udp0 = (udp_header_t *) (ip0 + 1);
312       udp1 = (udp_header_t *) (ip1 + 1);
313
314       new_l0 =
315         clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0) -
316                               sizeof (*ip0));
317       new_l1 =
318         clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b1) -
319                               sizeof (*ip1));
320       udp0->length = new_l0;
321       udp1->length = new_l1;
322     }
323   else
324     {
325       ip6_header_t *ip0, *ip1;
326       int bogus0, bogus1;
327
328       ip0 = vlib_buffer_get_current (b0);
329       ip1 = vlib_buffer_get_current (b1);
330
331       /* Apply the encap string. */
332       clib_memcpy (ip0, ec0, ec_len);
333       clib_memcpy (ip1, ec1, ec_len);
334
335       new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0)
336                                      - sizeof (*ip0));
337       new_l1 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b1)
338                                      - sizeof (*ip1));
339       ip0->payload_length = new_l0;
340       ip1->payload_length = new_l1;
341
342       /* Fix UDP length */
343       udp0 = (udp_header_t *) (ip0 + 1);
344       udp1 = (udp_header_t *) (ip1 + 1);
345
346       udp0->length = new_l0;
347       udp1->length = new_l1;
348
349       udp0->checksum =
350         ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip0, &bogus0);
351       udp1->checksum =
352         ip6_tcp_udp_icmp_compute_checksum (vm, b1, ip1, &bogus1);
353       ASSERT (bogus0 == 0);
354       ASSERT (bogus1 == 0);
355
356       if (udp0->checksum == 0)
357         udp0->checksum = 0xffff;
358       if (udp1->checksum == 0)
359         udp1->checksum = 0xffff;
360     }
361 }
362
363 /*
364  * fd.io coding-style-patch-verification: ON
365  *
366  * Local Variables:
367  * eval: (c-set-style "gnu")
368  * End:
369  */
370
371 #endif /* __included_udp_h__ */