Fix issue with udp port registration when running multithreaded
[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   /* Sparse vector mapping udp dst_port in network byte order
150      to next index. */
151   u16 *next_by_dst_port4;
152   u16 *next_by_dst_port6;
153   u8 punt_unknown4;
154   u8 punt_unknown6;
155
156   /* convenience */
157   vlib_main_t *vlib_main;
158 } udp_main_t;
159
160 always_inline udp_dst_port_info_t *
161 udp_get_dst_port_info (udp_main_t * um, udp_dst_port_t dst_port, u8 is_ip4)
162 {
163   uword *p = hash_get (um->dst_port_info_by_dst_port[is_ip4], dst_port);
164   return p ? vec_elt_at_index (um->dst_port_infos[is_ip4], p[0]) : 0;
165 }
166
167 format_function_t format_udp_header;
168 format_function_t format_udp_rx_trace;
169
170 unformat_function_t unformat_udp_header;
171
172 void udp_register_dst_port (vlib_main_t * vm,
173                             udp_dst_port_t dst_port,
174                             u32 node_index, u8 is_ip4);
175
176 void
177 udp_unregister_dst_port (vlib_main_t * vm,
178                          udp_dst_port_t dst_port, u8 is_ip4);
179
180 void udp_punt_unknown (vlib_main_t * vm, u8 is_ip4, u8 is_add);
181
182 always_inline void
183 ip_udp_fixup_one (vlib_main_t * vm, vlib_buffer_t * b0, u8 is_ip4)
184 {
185   u16 new_l0;
186   udp_header_t *udp0;
187
188   if (is_ip4)
189     {
190       ip4_header_t *ip0;
191       ip_csum_t sum0;
192       u16 old_l0 = 0;
193
194       ip0 = vlib_buffer_get_current (b0);
195
196       /* fix the <bleep>ing outer-IP checksum */
197       sum0 = ip0->checksum;
198       /* old_l0 always 0, see the rewrite setup */
199       new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
200
201       sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
202                              length /* changed member */ );
203       ip0->checksum = ip_csum_fold (sum0);
204       ip0->length = new_l0;
205
206       /* Fix UDP length */
207       udp0 = (udp_header_t *) (ip0 + 1);
208       new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0)
209                                      - sizeof (*ip0));
210       udp0->length = new_l0;
211     }
212   else
213     {
214       ip6_header_t *ip0;
215       int bogus0;
216
217       ip0 = vlib_buffer_get_current (b0);
218
219       new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0)
220                                      - sizeof (*ip0));
221       ip0->payload_length = new_l0;
222
223       /* Fix UDP length */
224       udp0 = (udp_header_t *) (ip0 + 1);
225       udp0->length = new_l0;
226
227       udp0->checksum =
228         ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip0, &bogus0);
229       ASSERT (bogus0 == 0);
230
231       if (udp0->checksum == 0)
232         udp0->checksum = 0xffff;
233     }
234 }
235
236 always_inline void
237 ip_udp_encap_one (vlib_main_t * vm, vlib_buffer_t * b0, u8 * ec0, word ec_len,
238                   u8 is_ip4)
239 {
240   vlib_buffer_advance (b0, -ec_len);
241
242   if (is_ip4)
243     {
244       ip4_header_t *ip0;
245
246       ip0 = vlib_buffer_get_current (b0);
247
248       /* Apply the encap string. */
249       clib_memcpy (ip0, ec0, ec_len);
250       ip_udp_fixup_one (vm, b0, 1);
251     }
252   else
253     {
254       ip6_header_t *ip0;
255
256       ip0 = vlib_buffer_get_current (b0);
257
258       /* Apply the encap string. */
259       clib_memcpy (ip0, ec0, ec_len);
260       ip_udp_fixup_one (vm, b0, 0);
261     }
262 }
263
264 always_inline void
265 ip_udp_encap_two (vlib_main_t * vm, vlib_buffer_t * b0, vlib_buffer_t * b1,
266                   u8 * ec0, u8 * ec1, word ec_len, u8 is_v4)
267 {
268   u16 new_l0, new_l1;
269   udp_header_t *udp0, *udp1;
270
271   ASSERT (_vec_len (ec0) == _vec_len (ec1));
272
273   vlib_buffer_advance (b0, -ec_len);
274   vlib_buffer_advance (b1, -ec_len);
275
276   if (is_v4)
277     {
278       ip4_header_t *ip0, *ip1;
279       ip_csum_t sum0, sum1;
280       u16 old_l0 = 0, old_l1 = 0;
281
282       ip0 = vlib_buffer_get_current (b0);
283       ip1 = vlib_buffer_get_current (b1);
284
285       /* Apply the encap string */
286       clib_memcpy (ip0, ec0, ec_len);
287       clib_memcpy (ip1, ec1, ec_len);
288
289       /* fix the <bleep>ing outer-IP checksum */
290       sum0 = ip0->checksum;
291       sum1 = ip1->checksum;
292
293       /* old_l0 always 0, see the rewrite setup */
294       new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
295       new_l1 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b1));
296
297       sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
298                              length /* changed member */ );
299       sum1 = ip_csum_update (sum1, old_l1, new_l1, ip4_header_t,
300                              length /* changed member */ );
301
302       ip0->checksum = ip_csum_fold (sum0);
303       ip1->checksum = ip_csum_fold (sum1);
304
305       ip0->length = new_l0;
306       ip1->length = new_l1;
307
308       /* Fix UDP length */
309       udp0 = (udp_header_t *) (ip0 + 1);
310       udp1 = (udp_header_t *) (ip1 + 1);
311
312       new_l0 =
313         clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0) -
314                               sizeof (*ip0));
315       new_l1 =
316         clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b1) -
317                               sizeof (*ip1));
318       udp0->length = new_l0;
319       udp1->length = new_l1;
320     }
321   else
322     {
323       ip6_header_t *ip0, *ip1;
324       int bogus0, bogus1;
325
326       ip0 = vlib_buffer_get_current (b0);
327       ip1 = vlib_buffer_get_current (b1);
328
329       /* Apply the encap string. */
330       clib_memcpy (ip0, ec0, ec_len);
331       clib_memcpy (ip1, ec1, ec_len);
332
333       new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0)
334                                      - sizeof (*ip0));
335       new_l1 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b1)
336                                      - sizeof (*ip1));
337       ip0->payload_length = new_l0;
338       ip1->payload_length = new_l1;
339
340       /* Fix UDP length */
341       udp0 = (udp_header_t *) (ip0 + 1);
342       udp1 = (udp_header_t *) (ip1 + 1);
343
344       udp0->length = new_l0;
345       udp1->length = new_l1;
346
347       udp0->checksum =
348         ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip0, &bogus0);
349       udp1->checksum =
350         ip6_tcp_udp_icmp_compute_checksum (vm, b1, ip1, &bogus1);
351       ASSERT (bogus0 == 0);
352       ASSERT (bogus1 == 0);
353
354       if (udp0->checksum == 0)
355         udp0->checksum = 0xffff;
356       if (udp1->checksum == 0)
357         udp1->checksum = 0xffff;
358     }
359 }
360
361 /*
362  * fd.io coding-style-patch-verification: ON
363  *
364  * Local Variables:
365  * eval: (c-set-style "gnu")
366  * End:
367  */
368
369 #endif /* __included_udp_h__ */