1ebe79532f457066d76e9632b862914a1d7ea391
[vpp.git] / src / vnet / udp / udp_encap_node.c
1 /*
2  * Copyright (c) 2017-2019 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
16 #include <vnet/udp/udp_encap.h>
17 #include <vnet/udp/udp.h>
18
19 typedef struct udp4_encap_trace_t_
20 {
21   udp_header_t udp;
22   ip4_header_t ip;
23 } udp4_encap_trace_t;
24
25 typedef struct udp6_encap_trace_t_
26 {
27   udp_header_t udp;
28   ip6_header_t ip;
29 } udp6_encap_trace_t;
30
31 extern vlib_combined_counter_main_t udp_encap_counters;
32
33 static u8 *
34 format_udp4_encap_trace (u8 * s, va_list * args)
35 {
36   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
37   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
38   udp4_encap_trace_t *t;
39
40   t = va_arg (*args, udp4_encap_trace_t *);
41
42   s = format (s, "%U\n  %U",
43               format_ip4_header, &t->ip, sizeof (t->ip),
44               format_udp_header, &t->udp, sizeof (t->udp));
45   return (s);
46 }
47
48 static u8 *
49 format_udp6_encap_trace (u8 * s, va_list * args)
50 {
51   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
52   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
53   udp6_encap_trace_t *t;
54
55   t = va_arg (*args, udp6_encap_trace_t *);
56
57   s = format (s, "%U\n  %U",
58               format_ip6_header, &t->ip, sizeof (t->ip),
59               format_udp_header, &t->udp, sizeof (t->udp));
60   return (s);
61 }
62
63 always_inline uword
64 udp_encap_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
65                   vlib_frame_t *frame, ip_address_family_t encap_family,
66                   ip_address_family_t payload_family)
67 {
68   vlib_combined_counter_main_t *cm = &udp_encap_counters;
69   u32 *from = vlib_frame_vector_args (frame);
70   u32 n_left_from, n_left_to_next, *to_next, next_index;
71   u32 thread_index = vm->thread_index;
72
73   n_left_from = frame->n_vectors;
74   next_index = node->cached_next_index;
75
76   while (n_left_from > 0)
77     {
78       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
79
80       while (n_left_from >= 4 && n_left_to_next >= 2)
81         {
82           vlib_buffer_t *b0, *b1;
83           udp_encap_t *ue0, *ue1;
84           u32 bi0, next0, uei0;
85           u32 bi1, next1, uei1;
86
87           /* Prefetch next iteration. */
88           {
89             vlib_buffer_t *p2, *p3;
90
91             p2 = vlib_get_buffer (vm, from[2]);
92             p3 = vlib_get_buffer (vm, from[3]);
93
94             vlib_prefetch_buffer_header (p2, STORE);
95             vlib_prefetch_buffer_header (p3, STORE);
96           }
97
98           bi0 = to_next[0] = from[0];
99           bi1 = to_next[1] = from[1];
100
101           from += 2;
102           n_left_from -= 2;
103           to_next += 2;
104           n_left_to_next -= 2;
105
106           b0 = vlib_get_buffer (vm, bi0);
107           b1 = vlib_get_buffer (vm, bi1);
108
109           uei0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
110           uei1 = vnet_buffer (b1)->ip.adj_index[VLIB_TX];
111
112           vlib_increment_combined_counter (cm, thread_index, uei0, 1,
113                                            vlib_buffer_length_in_chain (vm,
114                                                                         b0));
115           vlib_increment_combined_counter (cm, thread_index, uei1, 1,
116                                            vlib_buffer_length_in_chain (vm,
117                                                                         b1));
118
119           /* Rewrite packet header and updates lengths. */
120           ue0 = udp_encap_get (uei0);
121           ue1 = udp_encap_get (uei1);
122
123           /* Paint */
124           if (encap_family == AF_IP6)
125             {
126               const u8 n_bytes =
127                 sizeof (udp_header_t) + sizeof (ip6_header_t);
128               ip_udp_encap_two (vm, b0, b1, (u8 *) &ue0->ue_hdrs,
129                                 (u8 *) &ue1->ue_hdrs, n_bytes, encap_family,
130                                 payload_family);
131               if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
132                 {
133                   udp6_encap_trace_t *tr =
134                     vlib_add_trace (vm, node, b0, sizeof (*tr));
135                   tr->udp = ue0->ue_hdrs.ip6.ue_udp;
136                   tr->ip = ue0->ue_hdrs.ip6.ue_ip6;
137                 }
138               if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
139                 {
140                   udp6_encap_trace_t *tr =
141                     vlib_add_trace (vm, node, b1, sizeof (*tr));
142                   tr->udp = ue1->ue_hdrs.ip6.ue_udp;
143                   tr->ip = ue1->ue_hdrs.ip6.ue_ip6;
144                 }
145             }
146           else
147             {
148               const u8 n_bytes =
149                 sizeof (udp_header_t) + sizeof (ip4_header_t);
150
151               ip_udp_encap_two (vm, b0, b1, (u8 *) &ue0->ue_hdrs,
152                                 (u8 *) &ue1->ue_hdrs, n_bytes, encap_family,
153                                 payload_family);
154
155               if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
156                 {
157                   udp4_encap_trace_t *tr =
158                     vlib_add_trace (vm, node, b0, sizeof (*tr));
159                   tr->udp = ue0->ue_hdrs.ip4.ue_udp;
160                   tr->ip = ue0->ue_hdrs.ip4.ue_ip4;
161                 }
162               if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
163                 {
164                   udp4_encap_trace_t *tr =
165                     vlib_add_trace (vm, node, b1, sizeof (*tr));
166                   tr->udp = ue1->ue_hdrs.ip4.ue_udp;
167                   tr->ip = ue1->ue_hdrs.ip4.ue_ip4;
168                 }
169             }
170
171           next0 = ue0->ue_dpo.dpoi_next_node;
172           next1 = ue1->ue_dpo.dpoi_next_node;
173           vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ue0->ue_dpo.dpoi_index;
174           vnet_buffer (b1)->ip.adj_index[VLIB_TX] = ue1->ue_dpo.dpoi_index;
175
176           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
177                                            to_next, n_left_to_next,
178                                            bi0, bi1, next0, next1);
179         }
180
181       while (n_left_from > 0 && n_left_to_next > 0)
182         {
183           u32 bi0, next0, uei0;
184           vlib_buffer_t *b0;
185           udp_encap_t *ue0;
186
187           bi0 = to_next[0] = from[0];
188
189           from += 1;
190           n_left_from -= 1;
191           to_next += 1;
192           n_left_to_next -= 1;
193
194           b0 = vlib_get_buffer (vm, bi0);
195
196           uei0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
197
198           /* Rewrite packet header and updates lengths. */
199           ue0 = udp_encap_get (uei0);
200
201           vlib_increment_combined_counter (cm, thread_index, uei0, 1,
202                                            vlib_buffer_length_in_chain (vm,
203                                                                         b0));
204
205           /* Paint */
206           if (encap_family == AF_IP6)
207             {
208               const u8 n_bytes =
209                 sizeof (udp_header_t) + sizeof (ip6_header_t);
210               ip_udp_encap_one (vm, b0, (u8 *) &ue0->ue_hdrs.ip6, n_bytes,
211                                 encap_family, payload_family);
212
213               if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
214                 {
215                   udp6_encap_trace_t *tr =
216                     vlib_add_trace (vm, node, b0, sizeof (*tr));
217                   tr->udp = ue0->ue_hdrs.ip6.ue_udp;
218                   tr->ip = ue0->ue_hdrs.ip6.ue_ip6;
219                 }
220             }
221           else
222             {
223               const u8 n_bytes =
224                 sizeof (udp_header_t) + sizeof (ip4_header_t);
225
226               ip_udp_encap_one (vm, b0, (u8 *) &ue0->ue_hdrs.ip4, n_bytes,
227                                 encap_family, payload_family);
228
229               if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
230                 {
231                   udp4_encap_trace_t *tr =
232                     vlib_add_trace (vm, node, b0, sizeof (*tr));
233                   tr->udp = ue0->ue_hdrs.ip4.ue_udp;
234                   tr->ip = ue0->ue_hdrs.ip4.ue_ip4;
235                 }
236             }
237
238           next0 = ue0->ue_dpo.dpoi_next_node;
239           vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ue0->ue_dpo.dpoi_index;
240
241           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
242                                            to_next, n_left_to_next,
243                                            bi0, next0);
244         }
245
246       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
247     }
248
249   return frame->n_vectors;
250 }
251
252 VLIB_NODE_FN (udp4o4_encap_node)
253 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
254 {
255   return udp_encap_inline (vm, node, frame, AF_IP4, AF_IP4);
256 }
257
258 VLIB_NODE_FN (udp6o4_encap_node)
259 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
260 {
261   return udp_encap_inline (vm, node, frame, AF_IP4, AF_IP6);
262 }
263
264 VLIB_NODE_FN (udp4_encap_node)
265 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
266 {
267   return udp_encap_inline (vm, node, frame, AF_IP4, N_AF);
268 }
269
270 VLIB_NODE_FN (udp6o6_encap_node)
271 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
272 {
273   return udp_encap_inline (vm, node, frame, AF_IP6, AF_IP6);
274 }
275
276 VLIB_NODE_FN (udp4o6_encap_node)
277 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
278 {
279   return udp_encap_inline (vm, node, frame, AF_IP6, AF_IP4);
280 }
281
282 VLIB_NODE_FN (udp6_encap_node)
283 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
284 {
285   return udp_encap_inline (vm, node, frame, AF_IP6, N_AF);
286 }
287
288 /* *INDENT-OFF* */
289 VLIB_REGISTER_NODE (udp4o4_encap_node) = {
290   .name = "udp4o4-encap",
291   .vector_size = sizeof (u32),
292   .format_trace = format_udp4_encap_trace,
293   .n_next_nodes = 0,
294 };
295
296 VLIB_REGISTER_NODE (udp6o4_encap_node) = {
297   .name = "udp6o4-encap",
298   .vector_size = sizeof (u32),
299   .format_trace = format_udp6_encap_trace,
300   .n_next_nodes = 0,
301   .sibling_of = "udp4o4-encap",
302 };
303
304 VLIB_REGISTER_NODE (udp4_encap_node) = {
305   .name = "udp4-encap",
306   .vector_size = sizeof (u32),
307   .format_trace = format_udp4_encap_trace,
308   .n_next_nodes = 0,
309   .sibling_of = "udp4o4-encap",
310 };
311
312 VLIB_REGISTER_NODE (udp6o6_encap_node) = {
313   .name = "udp6o6-encap",
314   .vector_size = sizeof (u32),
315   .format_trace = format_udp6_encap_trace,
316   .n_next_nodes = 0,
317 };
318
319 VLIB_REGISTER_NODE (udp4o6_encap_node) = {
320   .name = "udp4o6-encap",
321   .vector_size = sizeof (u32),
322   .format_trace = format_udp4_encap_trace,
323   .n_next_nodes = 0,
324   .sibling_of = "udp6o6-encap",
325 };
326
327 VLIB_REGISTER_NODE (udp6_encap_node) = {
328   .name = "udp6-encap",
329   .vector_size = sizeof (u32),
330   .format_trace = format_udp6_encap_trace,
331   .n_next_nodes = 0,
332   .sibling_of = "udp6o6-encap",
333 };
334 /* *INDENT-ON* */
335
336
337 /*
338  * fd.io coding-style-patch-verification: ON
339  *
340  * Local Variables:
341  * eval: (c-set-style "gnu")
342  * End:
343  */