dpdk: Add support for Mellanox ConnectX-4 devices
[vpp.git] / vnet / vnet / ip / udp.h
1 /*
2  * ip/udp.h: udp protocol
3  *
4  * Copyright (c) 2013 Cisco and/or its affiliates.
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #ifndef included_udp_h
19 #define included_udp_h
20
21 #include <vnet/vnet.h>
22 #include <vnet/ip/udp_packet.h>
23 #include <vnet/ip/ip.h>
24 #include <vnet/ip/ip4.h>
25 #include <vnet/ip/ip4_packet.h>
26 #include <vnet/pg/pg.h>
27 #include <vnet/ip/format.h>
28
29 typedef enum
30 {
31 #define udp_error(n,s) UDP_ERROR_##n,
32 #include <vnet/ip/udp_error.def>
33 #undef udp_error
34   UDP_N_ERROR,
35 } udp_error_t;
36
37 #define foreach_udp4_dst_port                   \
38 _ (67, dhcp_to_server)                          \
39 _ (68, dhcp_to_client)                          \
40 _ (500, ikev2)                                  \
41 _ (3784, bfd4)                                   \
42 _ (4341, lisp_gpe)                              \
43 _ (4342, lisp_cp)                               \
44 _ (4739, ipfix)                                 \
45 _ (4789, vxlan)                                 \
46 _ (4789, vxlan6)                                \
47 _ (4790, vxlan_gpe)                             \
48 _ (6633, vpath_3)
49
50
51 #define foreach_udp6_dst_port                   \
52 _ (547, dhcpv6_to_server)                       \
53 _ (546, dhcpv6_to_client)                       \
54 _ (3784, bfd6)                                   \
55 _ (4341, lisp_gpe6)                             \
56 _ (4342, lisp_cp6)                              \
57 _ (4790, vxlan6_gpe)      \
58 _ (6633, vpath6_3)
59
60 typedef enum
61 {
62 #define _(n,f) UDP_DST_PORT_##f = n,
63   foreach_udp4_dst_port foreach_udp6_dst_port
64 #undef _
65 } udp_dst_port_t;
66
67 typedef enum
68 {
69 #define _(n,f) UDP6_DST_PORT_##f = n,
70   foreach_udp6_dst_port
71 #undef _
72 } udp6_dst_port_t;
73
74 typedef struct
75 {
76   /* Name (a c string). */
77   char *name;
78
79   /* GRE protocol type in host byte order. */
80   udp_dst_port_t dst_port;
81
82   /* Node which handles this type. */
83   u32 node_index;
84
85   /* Next index for this type. */
86   u32 next_index;
87 } udp_dst_port_info_t;
88
89 typedef enum
90 {
91   UDP_IP6 = 0,
92   UDP_IP4,                      /* the code is full of is_ip4... */
93   N_UDP_AF,
94 } udp_af_t;
95
96 typedef struct
97 {
98   udp_dst_port_info_t *dst_port_infos[N_UDP_AF];
99
100   /* Hash tables mapping name/protocol to protocol info index. */
101   uword *dst_port_info_by_name[N_UDP_AF];
102   uword *dst_port_info_by_dst_port[N_UDP_AF];
103
104   /* convenience */
105   vlib_main_t *vlib_main;
106 } udp_main_t;
107
108 always_inline udp_dst_port_info_t *
109 udp_get_dst_port_info (udp_main_t * um, udp_dst_port_t dst_port, u8 is_ip4)
110 {
111   uword *p = hash_get (um->dst_port_info_by_dst_port[is_ip4], dst_port);
112   return p ? vec_elt_at_index (um->dst_port_infos[is_ip4], p[0]) : 0;
113 }
114
115 format_function_t format_udp_header;
116 format_function_t format_udp_rx_trace;
117
118 unformat_function_t unformat_udp_header;
119
120 void udp_register_dst_port (vlib_main_t * vm,
121                             udp_dst_port_t dst_port,
122                             u32 node_index, u8 is_ip4);
123
124 void udp_punt_unknown (vlib_main_t * vm, u8 is_ip4, u8 is_add);
125
126 always_inline void
127 ip_udp_fixup_one (vlib_main_t * vm, vlib_buffer_t * b0, u8 is_ip4)
128 {
129   u16 new_l0;
130   udp_header_t *udp0;
131
132   if (is_ip4)
133     {
134       ip4_header_t *ip0;
135       ip_csum_t sum0;
136       u16 old_l0 = 0;
137
138       ip0 = vlib_buffer_get_current (b0);
139
140       /* fix the <bleep>ing outer-IP checksum */
141       sum0 = ip0->checksum;
142       /* old_l0 always 0, see the rewrite setup */
143       new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
144
145       sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
146                              length /* changed member */ );
147       ip0->checksum = ip_csum_fold (sum0);
148       ip0->length = new_l0;
149
150       /* Fix UDP length */
151       udp0 = (udp_header_t *) (ip0 + 1);
152       new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0)
153                                      - sizeof (*ip0));
154       udp0->length = new_l0;
155     }
156   else
157     {
158       ip6_header_t *ip0;
159       int bogus0;
160
161       ip0 = vlib_buffer_get_current (b0);
162
163       new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0)
164                                      - sizeof (*ip0));
165       ip0->payload_length = new_l0;
166
167       /* Fix UDP length */
168       udp0 = (udp_header_t *) (ip0 + 1);
169       udp0->length = new_l0;
170
171       udp0->checksum =
172         ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip0, &bogus0);
173       ASSERT (bogus0 == 0);
174
175       if (udp0->checksum == 0)
176         udp0->checksum = 0xffff;
177     }
178 }
179
180 always_inline void
181 ip_udp_encap_one (vlib_main_t * vm, vlib_buffer_t * b0, u8 * ec0, word ec_len,
182                   u8 is_ip4)
183 {
184   vlib_buffer_advance (b0, -ec_len);
185
186   if (is_ip4)
187     {
188       ip4_header_t *ip0;
189
190       ip0 = vlib_buffer_get_current (b0);
191
192       /* Apply the encap string. */
193       clib_memcpy (ip0, ec0, ec_len);
194       ip_udp_fixup_one (vm, b0, 1);
195     }
196   else
197     {
198       ip6_header_t *ip0;
199
200       ip0 = vlib_buffer_get_current (b0);
201
202       /* Apply the encap string. */
203       clib_memcpy (ip0, ec0, ec_len);
204       ip_udp_fixup_one (vm, b0, 0);
205     }
206 }
207
208 always_inline void
209 ip_udp_encap_two (vlib_main_t * vm, vlib_buffer_t * b0, vlib_buffer_t * b1,
210                   u8 * ec0, u8 * ec1, word ec_len, u8 is_v4)
211 {
212   u16 new_l0, new_l1;
213   udp_header_t *udp0, *udp1;
214
215   ASSERT (_vec_len (ec0) == _vec_len (ec1));
216
217   vlib_buffer_advance (b0, -ec_len);
218   vlib_buffer_advance (b1, -ec_len);
219
220   if (is_v4)
221     {
222       ip4_header_t *ip0, *ip1;
223       ip_csum_t sum0, sum1;
224       u16 old_l0 = 0, old_l1 = 0;
225
226       ip0 = vlib_buffer_get_current (b0);
227       ip1 = vlib_buffer_get_current (b1);
228
229       /* Apply the encap string */
230       clib_memcpy (ip0, ec0, ec_len);
231       clib_memcpy (ip1, ec1, ec_len);
232
233       /* fix the <bleep>ing outer-IP checksum */
234       sum0 = ip0->checksum;
235       sum1 = ip1->checksum;
236
237       /* old_l0 always 0, see the rewrite setup */
238       new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
239       new_l1 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b1));
240
241       sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
242                              length /* changed member */ );
243       sum1 = ip_csum_update (sum1, old_l1, new_l1, ip4_header_t,
244                              length /* changed member */ );
245
246       ip0->checksum = ip_csum_fold (sum0);
247       ip1->checksum = ip_csum_fold (sum1);
248
249       ip0->length = new_l0;
250       ip1->length = new_l1;
251
252       /* Fix UDP length */
253       udp0 = (udp_header_t *) (ip0 + 1);
254       udp1 = (udp_header_t *) (ip1 + 1);
255
256       new_l0 =
257         clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0) -
258                               sizeof (*ip0));
259       new_l1 =
260         clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b1) -
261                               sizeof (*ip1));
262       udp0->length = new_l0;
263       udp1->length = new_l1;
264     }
265   else
266     {
267       ip6_header_t *ip0, *ip1;
268       int bogus0, bogus1;
269
270       ip0 = vlib_buffer_get_current (b0);
271       ip1 = vlib_buffer_get_current (b1);
272
273       /* Apply the encap string. */
274       clib_memcpy (ip0, ec0, ec_len);
275       clib_memcpy (ip1, ec1, ec_len);
276
277       new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0)
278                                      - sizeof (*ip0));
279       new_l1 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b1)
280                                      - sizeof (*ip1));
281       ip0->payload_length = new_l0;
282       ip1->payload_length = new_l1;
283
284       /* Fix UDP length */
285       udp0 = (udp_header_t *) (ip0 + 1);
286       udp1 = (udp_header_t *) (ip1 + 1);
287
288       udp0->length = new_l0;
289       udp1->length = new_l1;
290
291       udp0->checksum =
292         ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip0, &bogus0);
293       udp1->checksum =
294         ip6_tcp_udp_icmp_compute_checksum (vm, b1, ip1, &bogus1);
295       ASSERT (bogus0 == 0);
296       ASSERT (bogus1 == 0);
297
298       if (udp0->checksum == 0)
299         udp0->checksum = 0xffff;
300       if (udp1->checksum == 0)
301         udp1->checksum = 0xffff;
302     }
303 }
304
305 #endif /* included_udp_h */
306
307 /*
308  * fd.io coding-style-patch-verification: ON
309  *
310  * Local Variables:
311  * eval: (c-set-style "gnu")
312  * End:
313  */