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