Initial commit of vpp code.
[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 #define vlib_validate_buffer_enqueue_x2(vm,node,next_index,to_next,n_left_to_next,bi0,bi1,next0,next1) \
44 do {                                                                    \
45   int enqueue_code = (next0 != next_index) + 2*(next1 != next_index);   \
46                                                                         \
47   if (PREDICT_FALSE (enqueue_code != 0))                                \
48     {                                                                   \
49       switch (enqueue_code)                                             \
50         {                                                               \
51         case 1:                                                         \
52           /* A B A */                                                   \
53           to_next[-2] = bi1;                                            \
54           to_next -= 1;                                                 \
55           n_left_to_next += 1;                                          \
56           vlib_set_next_frame_buffer (vm, node, next0, bi0);            \
57           break;                                                        \
58                                                                         \
59         case 2:                                                         \
60           /* A A B */                                                   \
61           to_next -= 1;                                                 \
62           n_left_to_next += 1;                                          \
63           vlib_set_next_frame_buffer (vm, node, next1, bi1);            \
64           break;                                                        \
65                                                                         \
66         case 3:                                                         \
67           /* A B B or A B C */                                          \
68           to_next -= 2;                                                 \
69           n_left_to_next += 2;                                          \
70           vlib_set_next_frame_buffer (vm, node, next0, bi0);            \
71           vlib_set_next_frame_buffer (vm, node, next1, bi1);            \
72           if (next0 == next1)                                           \
73             {                                                           \
74               vlib_put_next_frame (vm, node, next_index,                \
75                                    n_left_to_next);                     \
76               next_index = next1;                                       \
77               vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); \
78             }                                                           \
79         }                                                               \
80     }                                                                   \
81 } while (0)
82
83 #define vlib_validate_buffer_enqueue_x1(vm,node,next_index,to_next,n_left_to_next,bi0,next0) \
84 do {                                                                    \
85   if (PREDICT_FALSE (next0 != next_index))                              \
86     {                                                                   \
87       vlib_put_next_frame (vm, node, next_index, n_left_to_next + 1);   \
88       next_index = next0;                                               \
89       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); \
90                                                                         \
91       to_next[0] = bi0;                                                 \
92       to_next += 1;                                                     \
93       n_left_to_next -= 1;                                              \
94     }                                                                   \
95 } while (0)
96
97 always_inline uword
98 generic_buffer_node_inline (vlib_main_t * vm,
99                             vlib_node_runtime_t * node,
100                             vlib_frame_t * frame,
101                             uword sizeof_trace,
102                             void * opaque1,
103                             uword opaque2,
104                             void (* two_buffers) (vlib_main_t * vm,
105                                                   void * opaque1,
106                                                   uword opaque2,
107                                                   vlib_buffer_t * b0, vlib_buffer_t * b1,
108                                                   u32 * next0, u32 * next1),
109                             void (* one_buffer) (vlib_main_t * vm,
110                                                  void * opaque1,
111                                                  uword opaque2,
112                                                  vlib_buffer_t * b0,
113                                                  u32 * next0))
114 {
115   u32 n_left_from, * from, * to_next;
116   u32 next_index;
117
118   from = vlib_frame_vector_args (frame);
119   n_left_from = frame->n_vectors;
120   next_index = node->cached_next_index;
121
122   if (node->flags & VLIB_NODE_FLAG_TRACE)
123     vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
124                                    /* stride */ 1, sizeof_trace);
125
126   while (n_left_from > 0)
127     {
128       u32 n_left_to_next;
129
130       vlib_get_next_frame (vm, node, next_index,
131                            to_next, n_left_to_next);
132
133       while (n_left_from >= 4 && n_left_to_next >= 2)
134         {
135           vlib_buffer_t * p0, * p1;
136           u32 pi0, next0;
137           u32 pi1, next1;
138
139           /* Prefetch next iteration. */
140           {
141             vlib_buffer_t * p2, * p3;
142
143             p2 = vlib_get_buffer (vm, from[2]);
144             p3 = vlib_get_buffer (vm, from[3]);
145
146             vlib_prefetch_buffer_header (p2, LOAD);
147             vlib_prefetch_buffer_header (p3, LOAD);
148
149             CLIB_PREFETCH (p2->data, 64, LOAD);
150             CLIB_PREFETCH (p3->data, 64, LOAD);
151           }
152
153           pi0 = to_next[0] = from[0];
154           pi1 = to_next[1] = from[1];
155           from += 2;
156           to_next += 2;
157           n_left_from -= 2;
158           n_left_to_next -= 2;
159
160           p0 = vlib_get_buffer (vm, pi0);
161           p1 = vlib_get_buffer (vm, pi1);
162
163           two_buffers (vm, opaque1, opaque2, p0, p1, &next0, &next1);
164
165           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
166                                            to_next, n_left_to_next,
167                                            pi0, pi1, next0, next1);
168         }
169     
170       while (n_left_from > 0 && n_left_to_next > 0)
171         {
172           vlib_buffer_t * p0;
173           u32 pi0, next0;
174
175           pi0 = from[0];
176           to_next[0] = pi0;
177           from += 1;
178           to_next += 1;
179           n_left_from -= 1;
180           n_left_to_next -= 1;
181
182           p0 = vlib_get_buffer (vm, pi0);
183
184           one_buffer (vm, opaque1, opaque2, p0, &next0);
185
186           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
187                                            to_next, n_left_to_next,
188                                            pi0, next0);
189         }
190
191       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
192     }
193
194   return frame->n_vectors;
195 }
196
197 #endif /* included_vlib_buffer_node_h */