blob: 8a7790496252ebadc6b366448e16409a2f6f094c [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
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/*
16 * buffer_node.h: VLIB buffer handling node helper macros/inlines
17 *
18 * Copyright (c) 2008 Eliot Dresselhaus
19 *
20 * Permission is hereby granted, free of charge, to any person obtaining
21 * a copy of this software and associated documentation files (the
22 * "Software"), to deal in the Software without restriction, including
23 * without limitation the rights to use, copy, modify, merge, publish,
24 * distribute, sublicense, and/or sell copies of the Software, and to
25 * permit persons to whom the Software is furnished to do so, subject to
26 * the following conditions:
27 *
28 * The above copyright notice and this permission notice shall be
29 * included in all copies or substantial portions of the Software.
30 *
31 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 */
39
40#ifndef included_vlib_buffer_node_h
41#define included_vlib_buffer_node_h
42
Dave Barach9b8ffd92016-07-08 08:13:45 -040043/** \file
Dave Barach9770e202016-07-06 10:29:27 -040044 vlib buffer/node functions
45*/
46
47/** \brief Finish enqueueing two buffers forward in the graph.
48 Standard dual loop boilerplate element. This is a MACRO,
Dave Barach9b8ffd92016-07-08 08:13:45 -040049 with MULTIPLE SIDE EFFECTS. In the ideal case,
Dave Barach9770e202016-07-06 10:29:27 -040050 <code>next_index == next0 == next1</code>,
51 which means that the speculative enqueue at the top of the dual loop
52 has correctly dealt with both packets. In that case, the macro does
53 nothing at all.
54
55 @param vm vlib_main_t pointer, varies by thread
56 @param node current node vlib_node_runtime_t pointer
57 @param next_index speculated next index used for both packets
58 @param to_next speculated vector pointer used for both packets
59 @param n_left_to_next number of slots left in speculated vector
60 @param bi0 first buffer index
61 @param bi1 second buffer index
62 @param next0 actual next index to be used for the first packet
63 @param next1 actual next index to be used for the second packet
64
65 @return @c next_index -- speculative next index to be used for future packets
66 @return @c to_next -- speculative frame to be used for future packets
67 @return @c n_left_to_next -- number of slots left in speculative frame
68*/
69
Ed Warnickecb9cada2015-12-08 15:45:58 -070070#define vlib_validate_buffer_enqueue_x2(vm,node,next_index,to_next,n_left_to_next,bi0,bi1,next0,next1) \
71do { \
72 int enqueue_code = (next0 != next_index) + 2*(next1 != next_index); \
73 \
74 if (PREDICT_FALSE (enqueue_code != 0)) \
75 { \
76 switch (enqueue_code) \
77 { \
78 case 1: \
79 /* A B A */ \
80 to_next[-2] = bi1; \
81 to_next -= 1; \
82 n_left_to_next += 1; \
83 vlib_set_next_frame_buffer (vm, node, next0, bi0); \
84 break; \
85 \
86 case 2: \
87 /* A A B */ \
88 to_next -= 1; \
89 n_left_to_next += 1; \
90 vlib_set_next_frame_buffer (vm, node, next1, bi1); \
91 break; \
92 \
93 case 3: \
94 /* A B B or A B C */ \
95 to_next -= 2; \
96 n_left_to_next += 2; \
97 vlib_set_next_frame_buffer (vm, node, next0, bi0); \
98 vlib_set_next_frame_buffer (vm, node, next1, bi1); \
99 if (next0 == next1) \
100 { \
101 vlib_put_next_frame (vm, node, next_index, \
102 n_left_to_next); \
103 next_index = next1; \
104 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); \
105 } \
106 } \
107 } \
108} while (0)
109
Dave Barach670909e2016-10-18 15:25:35 -0400110
111/** \brief Finish enqueueing four buffers forward in the graph.
112 Standard quad loop boilerplate element. This is a MACRO,
113 with MULTIPLE SIDE EFFECTS. In the ideal case,
114 <code>next_index == next0 == next1 == next2 == next3</code>,
115 which means that the speculative enqueue at the top of the quad loop
116 has correctly dealt with all four packets. In that case, the macro does
117 nothing at all.
118
119 @param vm vlib_main_t pointer, varies by thread
120 @param node current node vlib_node_runtime_t pointer
121 @param next_index speculated next index used for both packets
122 @param to_next speculated vector pointer used for both packets
123 @param n_left_to_next number of slots left in speculated vector
124 @param bi0 first buffer index
125 @param bi1 second buffer index
126 @param bi2 third buffer index
127 @param bi3 fourth buffer index
128 @param next0 actual next index to be used for the first packet
129 @param next1 actual next index to be used for the second packet
130 @param next2 actual next index to be used for the third packet
131 @param next3 actual next index to be used for the fourth packet
132
133 @return @c next_index -- speculative next index to be used for future packets
134 @return @c to_next -- speculative frame to be used for future packets
135 @return @c n_left_to_next -- number of slots left in speculative frame
136*/
137
138#define vlib_validate_buffer_enqueue_x4(vm,node,next_index,to_next,n_left_to_next,bi0,bi1,bi2,bi3,next0,next1,next2,next3) \
139do { \
140 /* After the fact: check the [speculative] enqueue to "next" */ \
141 u32 fix_speculation = next_index != next0 || next_index != next1 \
142 || next_index != next2 || next_index != next3; \
143 if (PREDICT_FALSE(fix_speculation)) \
144 { \
145 /* rewind... */ \
146 to_next -= 4; \
147 n_left_to_next += 4; \
148 \
Dave Barach6b9c6df2016-11-16 08:04:58 -0500149 /* If bi0 belongs to "next", send it there */ \
Dave Barach670909e2016-10-18 15:25:35 -0400150 if (next_index == next0) \
151 { \
Dave Barach6b9c6df2016-11-16 08:04:58 -0500152 to_next[0] = bi0; \
Dave Barach670909e2016-10-18 15:25:35 -0400153 to_next++; \
154 n_left_to_next --; \
155 } \
156 else /* send it where it needs to go */ \
Dave Barach6b9c6df2016-11-16 08:04:58 -0500157 vlib_set_next_frame_buffer (vm, node, next0, bi0); \
Dave Barach670909e2016-10-18 15:25:35 -0400158 \
159 if (next_index == next1) \
160 { \
Dave Barach6b9c6df2016-11-16 08:04:58 -0500161 to_next[0] = bi1; \
Dave Barach670909e2016-10-18 15:25:35 -0400162 to_next++; \
163 n_left_to_next --; \
164 } \
165 else \
Dave Barach6b9c6df2016-11-16 08:04:58 -0500166 vlib_set_next_frame_buffer (vm, node, next1, bi1); \
Dave Barach670909e2016-10-18 15:25:35 -0400167 \
168 if (next_index == next2) \
169 { \
Dave Barach6b9c6df2016-11-16 08:04:58 -0500170 to_next[0] = bi2; \
Dave Barach670909e2016-10-18 15:25:35 -0400171 to_next++; \
172 n_left_to_next --; \
173 } \
174 else \
Dave Barach6b9c6df2016-11-16 08:04:58 -0500175 vlib_set_next_frame_buffer (vm, node, next2, bi2); \
Dave Barach670909e2016-10-18 15:25:35 -0400176 \
177 if (next_index == next3) \
178 { \
Dave Barach6b9c6df2016-11-16 08:04:58 -0500179 to_next[0] = bi3; \
Dave Barach670909e2016-10-18 15:25:35 -0400180 to_next++; \
181 n_left_to_next --; \
182 } \
183 else \
Dave Barach6b9c6df2016-11-16 08:04:58 -0500184 vlib_set_next_frame_buffer (vm, node, next3, bi3); \
Dave Barach670909e2016-10-18 15:25:35 -0400185 \
186 /* Change speculation: last 2 packets went to the same node */ \
187 if (next2 == next3) \
188 { \
189 vlib_put_next_frame (vm, node, next_index, n_left_to_next); \
190 next_index = next3; \
191 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); \
192 } \
193 } \
194 } while(0);
195
Dave Barach9770e202016-07-06 10:29:27 -0400196/** \brief Finish enqueueing one buffer forward in the graph.
197 Standard single loop boilerplate element. This is a MACRO,
198 with MULTIPLE SIDE EFFECTS. In the ideal case,
199 <code>next_index == next0</code>,
200 which means that the speculative enqueue at the top of the single loop
201 has correctly dealt with the packet in hand. In that case, the macro does
202 nothing at all.
203
204 @param vm vlib_main_t pointer, varies by thread
205 @param node current node vlib_node_runtime_t pointer
206 @param next_index speculated next index used for both packets
207 @param to_next speculated vector pointer used for both packets
208 @param n_left_to_next number of slots left in speculated vector
209 @param bi0 first buffer index
210 @param next0 actual next index to be used for the first packet
211
212 @return @c next_index -- speculative next index to be used for future packets
213 @return @c to_next -- speculative frame to be used for future packets
214 @return @c n_left_to_next -- number of slots left in speculative frame
215*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700216#define vlib_validate_buffer_enqueue_x1(vm,node,next_index,to_next,n_left_to_next,bi0,next0) \
217do { \
218 if (PREDICT_FALSE (next0 != next_index)) \
219 { \
220 vlib_put_next_frame (vm, node, next_index, n_left_to_next + 1); \
221 next_index = next0; \
222 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); \
223 \
224 to_next[0] = bi0; \
225 to_next += 1; \
226 n_left_to_next -= 1; \
227 } \
228} while (0)
229
230always_inline uword
231generic_buffer_node_inline (vlib_main_t * vm,
232 vlib_node_runtime_t * node,
233 vlib_frame_t * frame,
234 uword sizeof_trace,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400235 void *opaque1,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700236 uword opaque2,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400237 void (*two_buffers) (vlib_main_t * vm,
238 void *opaque1,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700239 uword opaque2,
240 vlib_buffer_t * b0,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400241 vlib_buffer_t * b1,
242 u32 * next0, u32 * next1),
243 void (*one_buffer) (vlib_main_t * vm,
244 void *opaque1, uword opaque2,
245 vlib_buffer_t * b0,
246 u32 * next0))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700247{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400248 u32 n_left_from, *from, *to_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700249 u32 next_index;
250
251 from = vlib_frame_vector_args (frame);
252 n_left_from = frame->n_vectors;
253 next_index = node->cached_next_index;
254
255 if (node->flags & VLIB_NODE_FLAG_TRACE)
256 vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
257 /* stride */ 1, sizeof_trace);
258
259 while (n_left_from > 0)
260 {
261 u32 n_left_to_next;
262
Dave Barach9b8ffd92016-07-08 08:13:45 -0400263 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700264
265 while (n_left_from >= 4 && n_left_to_next >= 2)
266 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400267 vlib_buffer_t *p0, *p1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700268 u32 pi0, next0;
269 u32 pi1, next1;
270
271 /* Prefetch next iteration. */
272 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400273 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700274
275 p2 = vlib_get_buffer (vm, from[2]);
276 p3 = vlib_get_buffer (vm, from[3]);
277
278 vlib_prefetch_buffer_header (p2, LOAD);
279 vlib_prefetch_buffer_header (p3, LOAD);
280
281 CLIB_PREFETCH (p2->data, 64, LOAD);
282 CLIB_PREFETCH (p3->data, 64, LOAD);
283 }
284
285 pi0 = to_next[0] = from[0];
286 pi1 = to_next[1] = from[1];
287 from += 2;
288 to_next += 2;
289 n_left_from -= 2;
290 n_left_to_next -= 2;
291
292 p0 = vlib_get_buffer (vm, pi0);
293 p1 = vlib_get_buffer (vm, pi1);
294
295 two_buffers (vm, opaque1, opaque2, p0, p1, &next0, &next1);
296
297 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
298 to_next, n_left_to_next,
299 pi0, pi1, next0, next1);
300 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400301
Ed Warnickecb9cada2015-12-08 15:45:58 -0700302 while (n_left_from > 0 && n_left_to_next > 0)
303 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400304 vlib_buffer_t *p0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700305 u32 pi0, next0;
306
307 pi0 = from[0];
308 to_next[0] = pi0;
309 from += 1;
310 to_next += 1;
311 n_left_from -= 1;
312 n_left_to_next -= 1;
313
314 p0 = vlib_get_buffer (vm, pi0);
315
316 one_buffer (vm, opaque1, opaque2, p0, &next0);
317
318 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
319 to_next, n_left_to_next,
320 pi0, next0);
321 }
322
323 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
324 }
325
326 return frame->n_vectors;
327}
328
329#endif /* included_vlib_buffer_node_h */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400330
331/*
332 * fd.io coding-style-patch-verification: ON
333 *
334 * Local Variables:
335 * eval: (c-set-style "gnu")
336 * End:
337 */