fd-io-styleify pass
[vpp.git] / vlib / vlib / buffer_node.h
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 /*
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
43 /** \file
44     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,
49  with MULTIPLE SIDE EFFECTS. In the ideal case,
50  <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
70 #define vlib_validate_buffer_enqueue_x2(vm,node,next_index,to_next,n_left_to_next,bi0,bi1,next0,next1) \
71 do {                                                                    \
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
110 /** \brief Finish enqueueing one buffer forward in the graph.
111  Standard single loop boilerplate element. This is a MACRO,
112  with MULTIPLE SIDE EFFECTS. In the ideal case,
113  <code>next_index == next0</code>,
114  which means that the speculative enqueue at the top of the single loop
115  has correctly dealt with the packet in hand. In that case, the macro does
116  nothing at all.
117
118  @param vm vlib_main_t pointer, varies by thread
119  @param node current node vlib_node_runtime_t pointer
120  @param next_index speculated next index used for both packets
121  @param to_next speculated vector pointer used for both packets
122  @param n_left_to_next number of slots left in speculated vector
123  @param bi0 first buffer index
124  @param next0 actual next index to be used for the first packet
125
126  @return @c next_index -- speculative next index to be used for future packets
127  @return @c to_next -- speculative frame to be used for future packets
128  @return @c n_left_to_next -- number of slots left in speculative frame
129 */
130 #define vlib_validate_buffer_enqueue_x1(vm,node,next_index,to_next,n_left_to_next,bi0,next0) \
131 do {                                                                    \
132   if (PREDICT_FALSE (next0 != next_index))                              \
133     {                                                                   \
134       vlib_put_next_frame (vm, node, next_index, n_left_to_next + 1);   \
135       next_index = next0;                                               \
136       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); \
137                                                                         \
138       to_next[0] = bi0;                                                 \
139       to_next += 1;                                                     \
140       n_left_to_next -= 1;                                              \
141     }                                                                   \
142 } while (0)
143
144 always_inline uword
145 generic_buffer_node_inline (vlib_main_t * vm,
146                             vlib_node_runtime_t * node,
147                             vlib_frame_t * frame,
148                             uword sizeof_trace,
149                             void *opaque1,
150                             uword opaque2,
151                             void (*two_buffers) (vlib_main_t * vm,
152                                                  void *opaque1,
153                                                  uword opaque2,
154                                                  vlib_buffer_t * b0,
155                                                  vlib_buffer_t * b1,
156                                                  u32 * next0, u32 * next1),
157                             void (*one_buffer) (vlib_main_t * vm,
158                                                 void *opaque1, uword opaque2,
159                                                 vlib_buffer_t * b0,
160                                                 u32 * next0))
161 {
162   u32 n_left_from, *from, *to_next;
163   u32 next_index;
164
165   from = vlib_frame_vector_args (frame);
166   n_left_from = frame->n_vectors;
167   next_index = node->cached_next_index;
168
169   if (node->flags & VLIB_NODE_FLAG_TRACE)
170     vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
171                                    /* stride */ 1, sizeof_trace);
172
173   while (n_left_from > 0)
174     {
175       u32 n_left_to_next;
176
177       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
178
179       while (n_left_from >= 4 && n_left_to_next >= 2)
180         {
181           vlib_buffer_t *p0, *p1;
182           u32 pi0, next0;
183           u32 pi1, next1;
184
185           /* Prefetch next iteration. */
186           {
187             vlib_buffer_t *p2, *p3;
188
189             p2 = vlib_get_buffer (vm, from[2]);
190             p3 = vlib_get_buffer (vm, from[3]);
191
192             vlib_prefetch_buffer_header (p2, LOAD);
193             vlib_prefetch_buffer_header (p3, LOAD);
194
195             CLIB_PREFETCH (p2->data, 64, LOAD);
196             CLIB_PREFETCH (p3->data, 64, LOAD);
197           }
198
199           pi0 = to_next[0] = from[0];
200           pi1 = to_next[1] = from[1];
201           from += 2;
202           to_next += 2;
203           n_left_from -= 2;
204           n_left_to_next -= 2;
205
206           p0 = vlib_get_buffer (vm, pi0);
207           p1 = vlib_get_buffer (vm, pi1);
208
209           two_buffers (vm, opaque1, opaque2, p0, p1, &next0, &next1);
210
211           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
212                                            to_next, n_left_to_next,
213                                            pi0, pi1, next0, next1);
214         }
215
216       while (n_left_from > 0 && n_left_to_next > 0)
217         {
218           vlib_buffer_t *p0;
219           u32 pi0, next0;
220
221           pi0 = from[0];
222           to_next[0] = pi0;
223           from += 1;
224           to_next += 1;
225           n_left_from -= 1;
226           n_left_to_next -= 1;
227
228           p0 = vlib_get_buffer (vm, pi0);
229
230           one_buffer (vm, opaque1, opaque2, p0, &next0);
231
232           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
233                                            to_next, n_left_to_next,
234                                            pi0, next0);
235         }
236
237       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
238     }
239
240   return frame->n_vectors;
241 }
242
243 #endif /* included_vlib_buffer_node_h */
244
245 /*
246  * fd.io coding-style-patch-verification: ON
247  *
248  * Local Variables:
249  * eval: (c-set-style "gnu")
250  * End:
251  */