Line data Source code
1 : /*
2 : * Copyright (c) 2015 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 : #include <vppinfra/error.h>
16 : #include <vppinfra/hash.h>
17 : #include <vnet/vnet.h>
18 : #include <vnet/ip/ip.h>
19 : #include <vnet/ethernet/ethernet.h>
20 : #include <vnet/vxlan-gpe/vxlan_gpe.h>
21 : #include <ioam/lib-vxlan-gpe/vxlan_gpe_ioam.h>
22 :
23 : /* Statistics (not really errors) */
24 : #define foreach_vxlan_gpe_pop_ioam_v4_error \
25 : _(POPPED, "good packets popped")
26 :
27 : static char *vxlan_gpe_pop_ioam_v4_error_strings[] = {
28 : #define _(sym,string) string,
29 : foreach_vxlan_gpe_pop_ioam_v4_error
30 : #undef _
31 : };
32 :
33 : typedef enum
34 : {
35 : #define _(sym,str) VXLAN_GPE_POP_IOAM_V4_ERROR_##sym,
36 : foreach_vxlan_gpe_pop_ioam_v4_error
37 : #undef _
38 : VXLAN_GPE_POP_IOAM_V4_N_ERROR,
39 : } vxlan_gpe_pop_ioam_v4_error_t;
40 :
41 : typedef struct
42 : {
43 : ioam_trace_t fmt_trace;
44 : } vxlan_gpe_pop_ioam_v4_trace_t;
45 :
46 :
47 : u8 *
48 0 : format_vxlan_gpe_pop_ioam_v4_trace (u8 * s, va_list * args)
49 : {
50 0 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
51 0 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
52 0 : vxlan_gpe_pop_ioam_v4_trace_t *t1
53 : = va_arg (*args, vxlan_gpe_pop_ioam_v4_trace_t *);
54 0 : ioam_trace_t *t = &(t1->fmt_trace);
55 : vxlan_gpe_ioam_option_t *fmt_trace0;
56 : vxlan_gpe_ioam_option_t *opt0, *limit0;
57 0 : vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main;
58 :
59 : u8 type0;
60 :
61 0 : fmt_trace0 = (vxlan_gpe_ioam_option_t *) t->option_data;
62 :
63 0 : s = format (s, "VXLAN_GPE_IOAM_POP: next_index %d len %d traced %d",
64 0 : t->next_index, fmt_trace0->length, t->trace_len);
65 :
66 0 : opt0 = (vxlan_gpe_ioam_option_t *) (fmt_trace0 + 1);
67 0 : limit0 = (vxlan_gpe_ioam_option_t *) ((u8 *) fmt_trace0) + t->trace_len;
68 :
69 0 : while (opt0 < limit0)
70 : {
71 0 : type0 = opt0->type;
72 0 : switch (type0)
73 : {
74 0 : case 0: /* Pad, just stop */
75 0 : opt0 = (vxlan_gpe_ioam_option_t *) ((u8 *) opt0) + 1;
76 0 : break;
77 :
78 0 : default:
79 0 : if (hm->trace[type0])
80 : {
81 0 : s = (*hm->trace[type0]) (s, opt0);
82 : }
83 : else
84 : {
85 : s =
86 0 : format (s, "\n unrecognized option %d length %d", type0,
87 0 : opt0->length);
88 : }
89 0 : opt0 =
90 0 : (vxlan_gpe_ioam_option_t *) (((u8 *) opt0) + opt0->length +
91 : sizeof (vxlan_gpe_ioam_option_t));
92 0 : break;
93 : }
94 : }
95 :
96 0 : return s;
97 : }
98 :
99 : always_inline void
100 0 : vxlan_gpe_ioam_pop_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
101 : vlib_buffer_t * b0)
102 : {
103 : ip4_header_t *ip0;
104 : udp_header_t *udp_hdr0;
105 : vxlan_gpe_header_t *gpe_hdr0;
106 : vxlan_gpe_ioam_hdr_t *gpe_ioam0;
107 :
108 0 : ip0 = vlib_buffer_get_current (b0);
109 :
110 0 : udp_hdr0 = (udp_header_t *) (ip0 + 1);
111 0 : gpe_hdr0 = (vxlan_gpe_header_t *) (udp_hdr0 + 1);
112 0 : gpe_ioam0 = (vxlan_gpe_ioam_hdr_t *) (gpe_hdr0 + 1);
113 :
114 : /* Pop the iOAM data */
115 0 : vlib_buffer_advance (b0,
116 : (word) (sizeof (udp_header_t) +
117 : sizeof (ip4_header_t) +
118 0 : sizeof (vxlan_gpe_header_t) +
119 0 : gpe_ioam0->length));
120 :
121 0 : return;
122 : }
123 :
124 :
125 :
126 : always_inline void
127 0 : vxlan_gpe_pop_ioam_v4_one_inline (vlib_main_t * vm,
128 : vlib_node_runtime_t * node,
129 : vxlan_gpe_main_t * ngm,
130 : vlib_buffer_t * b0, u32 * next0)
131 : {
132 : CLIB_UNUSED (ip4_header_t * ip0);
133 : CLIB_UNUSED (udp_header_t * udp_hdr0);
134 : CLIB_UNUSED (vxlan_gpe_header_t * gpe_hdr0);
135 : CLIB_UNUSED (vxlan_gpe_ioam_hdr_t * gpe_ioam0);
136 : CLIB_UNUSED (vxlan_gpe_ioam_option_t * opt0);
137 : CLIB_UNUSED (vxlan_gpe_ioam_option_t * limit0);
138 0 : vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main;
139 :
140 :
141 : /* Pop the iOAM header */
142 0 : ip0 = vlib_buffer_get_current (b0);
143 0 : udp_hdr0 = (udp_header_t *) (ip0 + 1);
144 0 : gpe_hdr0 = (vxlan_gpe_header_t *) (udp_hdr0 + 1);
145 0 : gpe_ioam0 = (vxlan_gpe_ioam_hdr_t *) (gpe_hdr0 + 1);
146 0 : opt0 = (vxlan_gpe_ioam_option_t *) (gpe_ioam0 + 1);
147 0 : limit0 = (vxlan_gpe_ioam_option_t *) ((u8 *) gpe_ioam0 + gpe_ioam0->length);
148 :
149 : /*
150 : * Basic validity checks
151 : */
152 0 : if (gpe_ioam0->length > clib_net_to_host_u16 (ip0->length))
153 : {
154 0 : *next0 = VXLAN_GPE_INPUT_NEXT_DROP;
155 0 : goto trace00;
156 : }
157 :
158 : /* Scan the set of h-b-h options, process ones that we understand */
159 0 : while (opt0 < limit0)
160 : {
161 : u8 type0;
162 0 : type0 = opt0->type;
163 0 : switch (type0)
164 : {
165 0 : case 0: /* Pad1 */
166 0 : opt0 = (vxlan_gpe_ioam_option_t *) ((u8 *) opt0) + 1;
167 0 : continue;
168 0 : case 1: /* PadN */
169 0 : break;
170 0 : default:
171 0 : if (hm->pop_options[type0])
172 : {
173 0 : if ((*hm->pop_options[type0]) (ip0, opt0) < 0)
174 : {
175 0 : *next0 = VXLAN_GPE_INPUT_NEXT_DROP;
176 0 : goto trace00;
177 : }
178 : }
179 0 : break;
180 : }
181 0 : opt0 =
182 0 : (vxlan_gpe_ioam_option_t *) (((u8 *) opt0) + opt0->length +
183 : sizeof (vxlan_gpe_ioam_hdr_t));
184 : }
185 :
186 :
187 0 : *next0 =
188 0 : (gpe_ioam0->protocol < VXLAN_GPE_PROTOCOL_MAX) ?
189 : ngm->
190 0 : decap_next_node_list[gpe_ioam0->protocol] : VXLAN_GPE_INPUT_NEXT_DROP;
191 :
192 0 : trace00:
193 0 : if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
194 : {
195 : vxlan_gpe_pop_ioam_v4_trace_t *t =
196 0 : vlib_add_trace (vm, node, b0, sizeof (*t));
197 0 : u32 trace_len = gpe_ioam0->length;
198 0 : t->fmt_trace.next_index = *next0;
199 : /* Capture the h-b-h option verbatim */
200 0 : trace_len =
201 : trace_len <
202 : ARRAY_LEN (t->fmt_trace.
203 : option_data) ? trace_len : ARRAY_LEN (t->fmt_trace.
204 : option_data);
205 0 : t->fmt_trace.trace_len = trace_len;
206 0 : clib_memcpy_fast (&(t->fmt_trace.option_data), gpe_ioam0, trace_len);
207 : }
208 :
209 : /* Remove the iOAM header inside the VxLAN-GPE header */
210 0 : vxlan_gpe_ioam_pop_v4 (vm, node, b0);
211 0 : return;
212 : }
213 :
214 : always_inline void
215 0 : vxlan_gpe_pop_ioam_v4_two_inline (vlib_main_t * vm,
216 : vlib_node_runtime_t * node,
217 : vxlan_gpe_main_t * ngm,
218 : vlib_buffer_t * b0, vlib_buffer_t * b1,
219 : u32 * next0, u32 * next1)
220 : {
221 :
222 0 : vxlan_gpe_pop_ioam_v4_one_inline (vm, node, ngm, b0, next0);
223 0 : vxlan_gpe_pop_ioam_v4_one_inline (vm, node, ngm, b1, next1);
224 0 : }
225 :
226 :
227 :
228 : static uword
229 0 : vxlan_gpe_pop_ioam (vlib_main_t * vm,
230 : vlib_node_runtime_t * node,
231 : vlib_frame_t * from_frame, u8 is_ipv6)
232 : {
233 : u32 n_left_from, next_index, *from, *to_next;
234 0 : vxlan_gpe_main_t *ngm = &vxlan_gpe_main;
235 :
236 0 : from = vlib_frame_vector_args (from_frame);
237 0 : n_left_from = from_frame->n_vectors;
238 :
239 0 : next_index = node->cached_next_index;
240 :
241 0 : while (n_left_from > 0)
242 : {
243 : u32 n_left_to_next;
244 :
245 0 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
246 :
247 0 : while (n_left_from >= 4 && n_left_to_next >= 2)
248 : {
249 : u32 bi0, bi1;
250 : vlib_buffer_t *b0, *b1;
251 : u32 next0, next1;
252 :
253 : /* Prefetch next iteration. */
254 : {
255 : vlib_buffer_t *p2, *p3;
256 :
257 0 : p2 = vlib_get_buffer (vm, from[2]);
258 0 : p3 = vlib_get_buffer (vm, from[3]);
259 :
260 0 : vlib_prefetch_buffer_header (p2, LOAD);
261 0 : vlib_prefetch_buffer_header (p3, LOAD);
262 :
263 0 : CLIB_PREFETCH (p2->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
264 0 : CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
265 : }
266 :
267 0 : bi0 = from[0];
268 0 : bi1 = from[1];
269 0 : to_next[0] = bi0;
270 0 : to_next[1] = bi1;
271 0 : from += 2;
272 0 : to_next += 2;
273 0 : n_left_to_next -= 2;
274 0 : n_left_from -= 2;
275 :
276 0 : b0 = vlib_get_buffer (vm, bi0);
277 0 : b1 = vlib_get_buffer (vm, bi1);
278 :
279 0 : vxlan_gpe_pop_ioam_v4_two_inline (vm, node, ngm, b0, b1, &next0,
280 : &next1);
281 :
282 :
283 0 : vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
284 : n_left_to_next, bi0, bi1, next0,
285 : next1);
286 : }
287 :
288 0 : while (n_left_from > 0 && n_left_to_next > 0)
289 : {
290 : u32 bi0;
291 : vlib_buffer_t *b0;
292 : u32 next0;
293 :
294 0 : bi0 = from[0];
295 0 : to_next[0] = bi0;
296 0 : from += 1;
297 0 : to_next += 1;
298 0 : n_left_from -= 1;
299 0 : n_left_to_next -= 1;
300 :
301 0 : b0 = vlib_get_buffer (vm, bi0);
302 :
303 0 : vxlan_gpe_pop_ioam_v4_one_inline (vm, node, ngm, b0, &next0);
304 :
305 :
306 0 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
307 : n_left_to_next, bi0, next0);
308 : }
309 :
310 0 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
311 : }
312 :
313 0 : return from_frame->n_vectors;
314 : }
315 :
316 :
317 : static uword
318 0 : vxlan_gpe_pop_ioam_v4 (vlib_main_t * vm,
319 : vlib_node_runtime_t * node, vlib_frame_t * from_frame)
320 : {
321 0 : return vxlan_gpe_pop_ioam (vm, node, from_frame, 0);
322 : }
323 :
324 : /* *INDENT-OFF* */
325 110920 : VLIB_REGISTER_NODE (vxlan_gpe_pop_ioam_v4_node) = {
326 : .function = vxlan_gpe_pop_ioam_v4,
327 : .name = "vxlan-gpe-pop-ioam-v4",
328 : .vector_size = sizeof (u32),
329 : .format_trace = format_vxlan_gpe_pop_ioam_v4_trace,
330 : .type = VLIB_NODE_TYPE_INTERNAL,
331 :
332 : .n_errors = ARRAY_LEN(vxlan_gpe_pop_ioam_v4_error_strings),
333 : .error_strings = vxlan_gpe_pop_ioam_v4_error_strings,
334 :
335 : .n_next_nodes = VXLAN_GPE_INPUT_N_NEXT,
336 :
337 : .next_nodes = {
338 : #define _(s,n) [VXLAN_GPE_INPUT_NEXT_##s] = n,
339 : foreach_vxlan_gpe_input_next
340 : #undef _
341 : },
342 : };
343 : /* *INDENT-ON* */
344 :
345 :
346 :
347 : /*
348 : * fd.io coding-style-patch-verification: ON
349 : *
350 : * Local Variables:
351 : * eval: (c-set-style "gnu")
352 : * End:
353 : */
|