Remove c-11 memcpy checks from perf-critical code
[vpp.git] / src / plugins / nsh / nsh_pop.c
1 /*
2  * nsh_pop.c - nsh POP only processing
3  *
4  * Copyright (c) 2017 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 #include <vnet/vnet.h>
19 #include <vnet/plugin/plugin.h>
20 #include <nsh/nsh.h>
21 #include <vnet/gre/gre.h>
22 #include <vnet/vxlan/vxlan.h>
23 #include <vnet/vxlan-gpe/vxlan_gpe.h>
24 #include <vnet/l2/l2_classify.h>
25
26 #include <vlibapi/api.h>
27 #include <vlibmemory/api.h>
28
29 extern nsh_option_map_t * nsh_md2_lookup_option (u16 class, u8 type);
30
31 extern u8 * format_nsh_header (u8 * s, va_list * args);
32 extern u8 * format_nsh_node_map_trace (u8 * s, va_list * args);
33
34 /* format from network order */
35 u8 * format_nsh_pop_header (u8 * s, va_list * args)
36 {
37   return format_nsh_header(s, args);
38 }
39
40
41
42 u8 * format_nsh_pop_node_map_trace (u8 * s, va_list * args)
43 {
44   return format_nsh_node_map_trace(s, args);
45 }
46
47
48 static uword
49 nsh_pop_inline (vlib_main_t * vm,
50                vlib_node_runtime_t * node,
51                vlib_frame_t * from_frame)
52 {
53   u32 n_left_from, next_index, *from, *to_next;
54   nsh_main_t * nm = &nsh_main;
55
56   from = vlib_frame_vector_args(from_frame);
57   n_left_from = from_frame->n_vectors;
58
59   next_index = node->cached_next_index;
60
61   while (n_left_from > 0)
62     {
63       u32 n_left_to_next;
64
65       vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
66
67       while (n_left_from >= 4 && n_left_to_next >= 2)
68         {
69           u32 bi0, bi1;
70           vlib_buffer_t * b0, *b1;
71           u32 next0 = NSH_NODE_NEXT_DROP, next1 = NSH_NODE_NEXT_DROP;
72           uword * entry0, *entry1;
73           nsh_base_header_t * hdr0 = 0, *hdr1 = 0;
74           u32 header_len0 = 0, header_len1 = 0;
75           u32 nsp_nsi0, nsp_nsi1;
76           u32 error0, error1;
77           nsh_map_t * map0 = 0, *map1 = 0;
78
79           /* Prefetch next iteration. */
80           {
81             vlib_buffer_t * p2, *p3;
82
83             p2 = vlib_get_buffer(vm, from[2]);
84             p3 = vlib_get_buffer(vm, from[3]);
85
86             vlib_prefetch_buffer_header(p2, LOAD);
87             vlib_prefetch_buffer_header(p3, LOAD);
88
89             CLIB_PREFETCH(p2->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
90             CLIB_PREFETCH(p3->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
91           }
92
93           bi0 = from[0];
94           bi1 = from[1];
95           to_next[0] = bi0;
96           to_next[1] = bi1;
97           from += 2;
98           to_next += 2;
99           n_left_from -= 2;
100           n_left_to_next -= 2;
101
102           error0 = 0;
103           error1 = 0;
104
105           b0 = vlib_get_buffer(vm, bi0);
106           b1 = vlib_get_buffer(vm, bi1);
107           hdr0 = vlib_buffer_get_current(b0);
108           nsp_nsi0 = hdr0->nsp_nsi;
109           header_len0 = hdr0->length * 4;
110
111           hdr1 = vlib_buffer_get_current(b1);
112           nsp_nsi1 = hdr1->nsp_nsi;
113           header_len1 = hdr1->length * 4;
114
115           /* Process packet 0 */
116           entry0 = hash_get_mem(nm->nsh_mapping_by_key, &nsp_nsi0);
117           if (PREDICT_FALSE(entry0 == 0))
118             {
119               error0 = NSH_NODE_ERROR_NO_MAPPING;
120               goto trace0;
121             }
122
123           /* Entry should point to a mapping ...*/
124           map0 = pool_elt_at_index(nm->nsh_mappings, entry0[0]);
125           if (PREDICT_FALSE(map0 == 0))
126             {
127               error0 = NSH_NODE_ERROR_NO_MAPPING;
128               goto trace0;
129             }
130
131           /* set up things for next node to transmit ie which node to handle it and where */
132           next0 = map0->next_node;
133           //vnet_buffer(b0)->sw_if_index[VLIB_TX] = map0->sw_if_index;
134
135           if(PREDICT_FALSE(map0->nsh_action == NSH_ACTION_POP))
136             {
137               /* Manipulate MD2 */
138               if(PREDICT_FALSE(hdr0->md_type == 2))
139                 {
140                   if (PREDICT_FALSE(next0 == NSH_NODE_NEXT_DROP))
141                     {
142                       error0 = NSH_NODE_ERROR_INVALID_OPTIONS;
143                       goto trace0;
144                     }
145                   //vnet_buffer(b0)->sw_if_index[VLIB_RX] = map0->sw_if_index;
146                 }
147
148               /* Pop NSH header */
149               vlib_buffer_advance(b0, (word)header_len0);
150               goto trace0;
151             }
152
153           entry0 = hash_get_mem(nm->nsh_entry_by_key, &map0->mapped_nsp_nsi);
154           if (PREDICT_FALSE(entry0 == 0))
155             {
156               error0 = NSH_NODE_ERROR_NO_ENTRY;
157               goto trace0;
158             }
159
160         trace0: b0->error = error0 ? node->errors[error0] : 0;
161
162           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
163             {
164               nsh_input_trace_t *tr = vlib_add_trace(vm, node, b0, sizeof(*tr));
165               clib_memcpy_fast ( &(tr->trace_data), hdr0, (hdr0->length*4) );
166             }
167
168           /* Process packet 1 */
169           entry1 = hash_get_mem(nm->nsh_mapping_by_key, &nsp_nsi1);
170           if (PREDICT_FALSE(entry1 == 0))
171             {
172               error1 = NSH_NODE_ERROR_NO_MAPPING;
173               goto trace1;
174             }
175
176           /* Entry should point to a mapping ...*/
177           map1 = pool_elt_at_index(nm->nsh_mappings, entry1[0]);
178           if (PREDICT_FALSE(map1 == 0))
179             {
180               error1 = NSH_NODE_ERROR_NO_MAPPING;
181               goto trace1;
182             }
183
184           /* set up things for next node to transmit ie which node to handle it and where */
185           next1 = map1->next_node;
186           //vnet_buffer(b1)->sw_if_index[VLIB_TX] = map1->sw_if_index;
187
188           if(PREDICT_FALSE(map1->nsh_action == NSH_ACTION_POP))
189             {
190               /* Manipulate MD2 */
191               if(PREDICT_FALSE(hdr1->md_type == 2))
192                 {
193                   if (PREDICT_FALSE(next1 == NSH_NODE_NEXT_DROP))
194                     {
195                       error1 = NSH_NODE_ERROR_INVALID_OPTIONS;
196                       goto trace1;
197                     }
198                   //vnet_buffer(b1)->sw_if_index[VLIB_RX] = map1->sw_if_index;
199                 }
200
201               /* Pop NSH header */
202               vlib_buffer_advance(b1, (word)header_len1);
203               goto trace1;
204             }
205
206           entry1 = hash_get_mem(nm->nsh_entry_by_key, &map1->mapped_nsp_nsi);
207           if (PREDICT_FALSE(entry1 == 0))
208             {
209               error1 = NSH_NODE_ERROR_NO_ENTRY;
210               goto trace1;
211             }
212
213
214         trace1: b1->error = error1 ? node->errors[error1] : 0;
215
216           if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
217             {
218               nsh_input_trace_t *tr = vlib_add_trace(vm, node, b1, sizeof(*tr));
219               clib_memcpy_fast ( &(tr->trace_data), hdr1, (hdr1->length*4) );
220             }
221
222           vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next,
223                                           n_left_to_next, bi0, bi1, next0, next1);
224
225         }
226
227       while (n_left_from > 0 && n_left_to_next > 0)
228         {
229           u32 bi0 = 0;
230           vlib_buffer_t * b0 = NULL;
231           u32 next0 = NSH_NODE_NEXT_DROP;
232           uword * entry0;
233           nsh_base_header_t * hdr0 = 0;
234           u32 header_len0 = 0;
235           u32 nsp_nsi0;
236           u32 error0;
237           nsh_map_t * map0 = 0;
238
239           bi0 = from[0];
240           to_next[0] = bi0;
241           from += 1;
242           to_next += 1;
243           n_left_from -= 1;
244           n_left_to_next -= 1;
245           error0 = 0;
246
247           b0 = vlib_get_buffer(vm, bi0);
248           hdr0 = vlib_buffer_get_current(b0);
249
250           nsp_nsi0 = hdr0->nsp_nsi;
251           header_len0 = hdr0->length * 4;
252
253           entry0 = hash_get_mem(nm->nsh_mapping_by_key, &nsp_nsi0);
254
255           if (PREDICT_FALSE(entry0 == 0))
256             {
257               error0 = NSH_NODE_ERROR_NO_MAPPING;
258               goto trace00;
259             }
260
261           /* Entry should point to a mapping ...*/
262           map0 = pool_elt_at_index(nm->nsh_mappings, entry0[0]);
263
264           if (PREDICT_FALSE(map0 == 0))
265             {
266               error0 = NSH_NODE_ERROR_NO_MAPPING;
267               goto trace00;
268             }
269
270           /* set up things for next node to transmit ie which node to handle it and where */
271           next0 = map0->next_node;
272           //vnet_buffer(b0)->sw_if_index[VLIB_TX] = map0->sw_if_index;
273
274           if(PREDICT_FALSE(map0->nsh_action == NSH_ACTION_POP))
275             {
276               /* Manipulate MD2 */
277               if(PREDICT_FALSE(hdr0->md_type == 2))
278                 {
279                   if (PREDICT_FALSE(next0 == NSH_NODE_NEXT_DROP))
280                     {
281                       error0 = NSH_NODE_ERROR_INVALID_OPTIONS;
282                       goto trace00;
283                     }
284                   //vnet_buffer(b0)->sw_if_index[VLIB_RX] = map0->sw_if_index;
285                 }
286
287               /* Pop NSH header */
288               vlib_buffer_advance(b0, (word)header_len0);
289               goto trace00;
290             }
291
292           entry0 = hash_get_mem(nm->nsh_entry_by_key, &map0->mapped_nsp_nsi);
293           if (PREDICT_FALSE(entry0 == 0))
294             {
295               error0 = NSH_NODE_ERROR_NO_ENTRY;
296               goto trace00;
297             }
298
299           trace00: b0->error = error0 ? node->errors[error0] : 0;
300
301           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
302             {
303               nsh_input_trace_t *tr = vlib_add_trace(vm, node, b0, sizeof(*tr));
304               clib_memcpy_fast ( &(tr->trace_data[0]), hdr0, (hdr0->length*4) );
305             }
306
307           vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
308                                           n_left_to_next, bi0, next0);
309         }
310
311       vlib_put_next_frame(vm, node, next_index, n_left_to_next);
312
313     }
314
315   return from_frame->n_vectors;
316 }
317
318 /**
319  * @brief Graph processing dispatch function for NSH Input
320  *
321  * @node nsh_input
322  * @param *vm
323  * @param *node
324  * @param *from_frame
325  *
326  * @return from_frame->n_vectors
327  *
328  */
329 static uword
330 nsh_pop (vlib_main_t * vm, vlib_node_runtime_t * node,
331                   vlib_frame_t * from_frame)
332 {
333   return nsh_pop_inline (vm, node, from_frame);
334 }
335
336 static char * nsh_pop_node_error_strings[] = {
337 #define _(sym,string) string,
338   foreach_nsh_node_error
339 #undef _
340 };
341
342 /* register nsh-input node */
343 VLIB_REGISTER_NODE (nsh_pop_node) = {
344   .function = nsh_pop,
345   .name = "nsh-pop",
346   .vector_size = sizeof (u32),
347   .format_trace = format_nsh_pop_node_map_trace,
348   .format_buffer = format_nsh_pop_header,
349   .type = VLIB_NODE_TYPE_INTERNAL,
350
351   .n_errors = ARRAY_LEN(nsh_pop_node_error_strings),
352   .error_strings = nsh_pop_node_error_strings,
353
354   .n_next_nodes = NSH_NODE_N_NEXT,
355
356   .next_nodes = {
357 #define _(s,n) [NSH_NODE_NEXT_##s] = n,
358     foreach_nsh_node_next
359 #undef _
360   },
361 };
362
363 VLIB_NODE_FUNCTION_MULTIARCH (nsh_pop_node, nsh_pop);
364
365