Line data Source code
1 : /*
2 : * Copyright (c) 2016 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 : #include <stdint.h>
17 :
18 : #include <vlib/vlib.h>
19 : #include <vnet/vnet.h>
20 : #include <vnet/ip/ip.h>
21 : #include <vnet/classify/flow_classify.h>
22 : #include <vnet/classify/vnet_classify.h>
23 :
24 : typedef struct
25 : {
26 : u32 sw_if_index;
27 : u32 next_index;
28 : u32 table_index;
29 : u32 offset;
30 : } flow_classify_trace_t;
31 :
32 : static u8 *
33 0 : format_flow_classify_trace (u8 * s, va_list * args)
34 : {
35 0 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
36 0 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
37 0 : flow_classify_trace_t *t = va_arg (*args, flow_classify_trace_t *);
38 :
39 0 : s = format (s, "FLOW_CLASSIFY: sw_if_index %d next %d table %d offset %d",
40 : t->sw_if_index, t->next_index, t->table_index, t->offset);
41 0 : return s;
42 : }
43 :
44 : #define foreach_flow_classify_error \
45 : _(MISS, "Flow classify misses") \
46 : _(HIT, "Flow classify hits") \
47 : _(CHAIN_HIT, "Flow classify hits after chain walk") \
48 : _(DROP, "Flow classify action drop")
49 :
50 : typedef enum
51 : {
52 : #define _(sym,str) FLOW_CLASSIFY_ERROR_##sym,
53 : foreach_flow_classify_error
54 : #undef _
55 : FLOW_CLASSIFY_N_ERROR,
56 : } flow_classify_error_t;
57 :
58 : static char *flow_classify_error_strings[] = {
59 : #define _(sym,string) string,
60 : foreach_flow_classify_error
61 : #undef _
62 : };
63 :
64 : static inline uword
65 0 : flow_classify_inline (vlib_main_t * vm,
66 : vlib_node_runtime_t * node,
67 : vlib_frame_t * frame, flow_classify_table_id_t tid)
68 : {
69 : u32 n_left_from, *from, *to_next;
70 : flow_classify_next_index_t next_index;
71 0 : flow_classify_main_t *fcm = &flow_classify_main;
72 0 : vnet_classify_main_t *vcm = fcm->vnet_classify_main;
73 0 : f64 now = vlib_time_now (vm);
74 0 : u32 hits = 0;
75 0 : u32 misses = 0;
76 0 : u32 chain_hits = 0;
77 0 : u32 drop = 0;
78 :
79 0 : from = vlib_frame_vector_args (frame);
80 0 : n_left_from = frame->n_vectors;
81 :
82 : /* First pass: compute hashes */
83 0 : while (n_left_from > 2)
84 : {
85 : vlib_buffer_t *b0, *b1;
86 : u32 bi0, bi1;
87 : u8 *h0, *h1;
88 : u32 sw_if_index0, sw_if_index1;
89 : u32 table_index0, table_index1;
90 : vnet_classify_table_t *t0, *t1;
91 :
92 : /* Prefetch next iteration */
93 : {
94 : vlib_buffer_t *p1, *p2;
95 :
96 0 : p1 = vlib_get_buffer (vm, from[1]);
97 0 : p2 = vlib_get_buffer (vm, from[2]);
98 :
99 0 : vlib_prefetch_buffer_header (p1, STORE);
100 0 : clib_prefetch_store (p1->data);
101 0 : vlib_prefetch_buffer_header (p2, STORE);
102 0 : clib_prefetch_store (p2->data);
103 : }
104 :
105 0 : bi0 = from[0];
106 0 : b0 = vlib_get_buffer (vm, bi0);
107 0 : h0 = b0->data;
108 :
109 0 : bi1 = from[1];
110 0 : b1 = vlib_get_buffer (vm, bi1);
111 0 : h1 = b1->data;
112 :
113 0 : sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
114 0 : table_index0 =
115 0 : fcm->classify_table_index_by_sw_if_index[tid][sw_if_index0];
116 :
117 0 : sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
118 0 : table_index1 =
119 0 : fcm->classify_table_index_by_sw_if_index[tid][sw_if_index1];
120 :
121 0 : t0 = pool_elt_at_index (vcm->tables, table_index0);
122 :
123 0 : t1 = pool_elt_at_index (vcm->tables, table_index1);
124 :
125 0 : vnet_buffer (b0)->l2_classify.hash = vnet_classify_hash_packet (t0, h0);
126 :
127 0 : vnet_classify_prefetch_bucket (t0, vnet_buffer (b0)->l2_classify.hash);
128 :
129 0 : vnet_buffer (b1)->l2_classify.hash = vnet_classify_hash_packet (t1, h1);
130 :
131 0 : vnet_classify_prefetch_bucket (t1, vnet_buffer (b1)->l2_classify.hash);
132 :
133 0 : vnet_buffer (b0)->l2_classify.table_index = table_index0;
134 :
135 0 : vnet_buffer (b1)->l2_classify.table_index = table_index1;
136 :
137 0 : from += 2;
138 0 : n_left_from -= 2;
139 : }
140 :
141 0 : while (n_left_from > 0)
142 : {
143 : vlib_buffer_t *b0;
144 : u32 bi0;
145 : u8 *h0;
146 : u32 sw_if_index0;
147 : u32 table_index0;
148 : vnet_classify_table_t *t0;
149 :
150 0 : bi0 = from[0];
151 0 : b0 = vlib_get_buffer (vm, bi0);
152 0 : h0 = b0->data;
153 :
154 0 : sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
155 0 : table_index0 =
156 0 : fcm->classify_table_index_by_sw_if_index[tid][sw_if_index0];
157 :
158 0 : t0 = pool_elt_at_index (vcm->tables, table_index0);
159 0 : vnet_buffer (b0)->l2_classify.hash = vnet_classify_hash_packet (t0, h0);
160 :
161 0 : vnet_buffer (b0)->l2_classify.table_index = table_index0;
162 0 : vnet_classify_prefetch_bucket (t0, vnet_buffer (b0)->l2_classify.hash);
163 :
164 0 : from++;
165 0 : n_left_from--;
166 : }
167 :
168 0 : next_index = node->cached_next_index;
169 0 : from = vlib_frame_vector_args (frame);
170 0 : n_left_from = frame->n_vectors;
171 :
172 0 : while (n_left_from > 0)
173 : {
174 : u32 n_left_to_next;
175 :
176 0 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
177 :
178 : /* Not enough load/store slots to dual loop... */
179 0 : while (n_left_from > 0 && n_left_to_next > 0)
180 : {
181 : u32 bi0;
182 : vlib_buffer_t *b0;
183 0 : u32 next0 = FLOW_CLASSIFY_NEXT_INDEX_DROP;
184 : u32 table_index0;
185 : vnet_classify_table_t *t0;
186 : vnet_classify_entry_t *e0;
187 : u32 hash0;
188 : u8 *h0;
189 :
190 : /* Stride 3 seems to work best */
191 0 : if (PREDICT_TRUE (n_left_from > 3))
192 : {
193 0 : vlib_buffer_t *p1 = vlib_get_buffer (vm, from[3]);
194 : vnet_classify_table_t *tp1;
195 : u32 table_index1;
196 : u32 phash1;
197 :
198 0 : table_index1 = vnet_buffer (p1)->l2_classify.table_index;
199 :
200 0 : if (PREDICT_TRUE (table_index1 != ~0))
201 : {
202 0 : tp1 = pool_elt_at_index (vcm->tables, table_index1);
203 0 : phash1 = vnet_buffer (p1)->l2_classify.hash;
204 0 : vnet_classify_prefetch_entry (tp1, phash1);
205 : }
206 : }
207 :
208 : /* Speculatively enqueue b0 to the current next frame */
209 0 : bi0 = from[0];
210 0 : to_next[0] = bi0;
211 0 : from += 1;
212 0 : to_next += 1;
213 0 : n_left_from -= 1;
214 0 : n_left_to_next -= 1;
215 :
216 0 : b0 = vlib_get_buffer (vm, bi0);
217 0 : h0 = b0->data;
218 0 : table_index0 = vnet_buffer (b0)->l2_classify.table_index;
219 0 : e0 = 0;
220 0 : t0 = 0;
221 :
222 0 : vnet_get_config_data (fcm->vnet_config_main[tid],
223 : &b0->current_config_index, &next0,
224 : /* # bytes of config data */ 0);
225 :
226 0 : if (PREDICT_TRUE (table_index0 != ~0))
227 : {
228 0 : hash0 = vnet_buffer (b0)->l2_classify.hash;
229 0 : t0 = pool_elt_at_index (vcm->tables, table_index0);
230 0 : e0 = vnet_classify_find_entry (t0, h0, hash0, now);
231 0 : if (e0)
232 : {
233 0 : hits++;
234 : }
235 : else
236 : {
237 0 : misses++;
238 0 : vnet_classify_add_del_session (vcm, table_index0,
239 : h0, ~0, 0, 0, 0, 0, 1);
240 : /* increment counter */
241 0 : vnet_classify_find_entry (t0, h0, hash0, now);
242 : }
243 : }
244 0 : if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
245 : && (b0->flags & VLIB_BUFFER_IS_TRACED)))
246 : {
247 : flow_classify_trace_t *t =
248 0 : vlib_add_trace (vm, node, b0, sizeof (*t));
249 0 : t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
250 0 : t->next_index = next0;
251 0 : t->table_index = t0 ? t0 - vcm->tables : ~0;
252 0 : t->offset = (t0 && e0) ? vnet_classify_get_offset (t0, e0) : ~0;
253 : }
254 :
255 : /* Verify speculative enqueue, maybe switch current next frame */
256 0 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
257 : n_left_to_next, bi0, next0);
258 : }
259 :
260 0 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
261 : }
262 :
263 0 : vlib_node_increment_counter (vm, node->node_index,
264 : FLOW_CLASSIFY_ERROR_MISS, misses);
265 0 : vlib_node_increment_counter (vm, node->node_index,
266 : FLOW_CLASSIFY_ERROR_HIT, hits);
267 0 : vlib_node_increment_counter (vm, node->node_index,
268 : FLOW_CLASSIFY_ERROR_CHAIN_HIT, chain_hits);
269 0 : vlib_node_increment_counter (vm, node->node_index,
270 : FLOW_CLASSIFY_ERROR_DROP, drop);
271 :
272 0 : return frame->n_vectors;
273 : }
274 :
275 2236 : VLIB_NODE_FN (ip4_flow_classify_node) (vlib_main_t * vm,
276 : vlib_node_runtime_t * node,
277 : vlib_frame_t * frame)
278 : {
279 0 : return flow_classify_inline (vm, node, frame, FLOW_CLASSIFY_TABLE_IP4);
280 : }
281 :
282 : /* *INDENT-OFF* */
283 178120 : VLIB_REGISTER_NODE (ip4_flow_classify_node) = {
284 : .name = "ip4-flow-classify",
285 : .vector_size = sizeof (u32),
286 : .format_trace = format_flow_classify_trace,
287 : .n_errors = ARRAY_LEN(flow_classify_error_strings),
288 : .error_strings = flow_classify_error_strings,
289 : .n_next_nodes = FLOW_CLASSIFY_NEXT_INDEX_N_NEXT,
290 : .next_nodes = {
291 : [FLOW_CLASSIFY_NEXT_INDEX_DROP] = "error-drop",
292 : },
293 : };
294 : /* *INDENT-ON* */
295 :
296 2236 : VLIB_NODE_FN (ip6_flow_classify_node) (vlib_main_t * vm,
297 : vlib_node_runtime_t * node,
298 : vlib_frame_t * frame)
299 : {
300 0 : return flow_classify_inline (vm, node, frame, FLOW_CLASSIFY_TABLE_IP6);
301 : }
302 :
303 : /* *INDENT-OFF* */
304 178120 : VLIB_REGISTER_NODE (ip6_flow_classify_node) = {
305 : .name = "ip6-flow-classify",
306 : .vector_size = sizeof (u32),
307 : .format_trace = format_flow_classify_trace,
308 : .n_errors = ARRAY_LEN(flow_classify_error_strings),
309 : .error_strings = flow_classify_error_strings,
310 : .n_next_nodes = FLOW_CLASSIFY_NEXT_INDEX_N_NEXT,
311 : .next_nodes = {
312 : [FLOW_CLASSIFY_NEXT_INDEX_DROP] = "error-drop",
313 : },
314 : };
315 :
316 : /* *INDENT-ON* */
317 :
318 :
319 : static clib_error_t *
320 559 : flow_classify_init (vlib_main_t * vm)
321 : {
322 559 : flow_classify_main_t *fcm = &flow_classify_main;
323 :
324 559 : fcm->vlib_main = vm;
325 559 : fcm->vnet_main = vnet_get_main ();
326 559 : fcm->vnet_classify_main = &vnet_classify_main;
327 :
328 559 : return 0;
329 : }
330 :
331 33599 : VLIB_INIT_FUNCTION (flow_classify_init);
332 :
333 : /*
334 : * fd.io coding-style-patch-verification: ON
335 : *
336 : * Local Variables:
337 : * eval: (c-set-style "gnu")
338 : * End:
339 : */
|