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