Line data Source code
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 : #include <vnet/ip/ip.h>
16 : #include <vnet/classify/vnet_classify.h>
17 : #include <vnet/classify/in_out_acl.h>
18 :
19 : typedef struct
20 : {
21 : u32 sw_if_index;
22 : u32 next_index;
23 : u32 table_index;
24 : u32 offset;
25 : }
26 : ip_in_out_acl_trace_t;
27 :
28 : /* packet trace format function */
29 : static u8 *
30 244 : format_ip_in_out_acl_trace (u8 * s, u32 is_output, va_list * args)
31 : {
32 244 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
33 244 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
34 244 : ip_in_out_acl_trace_t *t = va_arg (*args, ip_in_out_acl_trace_t *);
35 244 : const vnet_classify_main_t *vcm = &vnet_classify_main;
36 244 : const u32 indent = format_get_indent (s);
37 : vnet_classify_table_t *table;
38 : vnet_classify_entry_t *e;
39 :
40 : s =
41 244 : format (s, "%s: sw_if_index %d, next_index %d, table_index %d, offset %d",
42 : is_output ? "OUTACL" : "INACL", t->sw_if_index, t->next_index,
43 : t->table_index, t->offset);
44 :
45 244 : if (pool_is_free_index (vcm->tables, t->table_index))
46 10 : return format (s, "\n%Uno table", format_white_space, indent + 4);
47 :
48 234 : if (~0 == t->offset)
49 0 : return format (s, "\n%Uno match", format_white_space, indent + 4);
50 :
51 234 : table = vnet_classify_table_get (t->table_index);
52 234 : e = vnet_classify_get_entry (table, t->offset);
53 234 : return format (s, "\n%U%U", format_white_space, indent + 4,
54 : format_classify_entry, table, e);
55 : }
56 :
57 : static u8 *
58 236 : format_ip_inacl_trace (u8 * s, va_list * args)
59 : {
60 236 : return format_ip_in_out_acl_trace (s, 0 /* is_output */ , args);
61 : }
62 :
63 : static u8 *
64 8 : format_ip_outacl_trace (u8 * s, va_list * args)
65 : {
66 8 : return format_ip_in_out_acl_trace (s, 1 /* is_output */ , args);
67 : }
68 :
69 : extern vlib_node_registration_t ip4_inacl_node;
70 : extern vlib_node_registration_t ip4_outacl_node;
71 : extern vlib_node_registration_t ip6_inacl_node;
72 : extern vlib_node_registration_t ip6_outacl_node;
73 :
74 : #define foreach_ip_inacl_error \
75 : _(MISS, "input ACL misses") \
76 : _(HIT, "input ACL hits") \
77 : _(CHAIN_HIT, "input ACL hits after chain walk")
78 :
79 : #define foreach_ip_outacl_error \
80 : _(MISS, "output ACL misses") \
81 : _(HIT, "output ACL hits") \
82 : _(CHAIN_HIT, "output ACL hits after chain walk")
83 :
84 : typedef enum
85 : {
86 : #define _(sym,str) IP_INACL_ERROR_##sym,
87 : foreach_ip_inacl_error
88 : #undef _
89 : IP_INACL_N_ERROR,
90 : }
91 : ip_inacl_error_t;
92 :
93 : static char *ip_inacl_error_strings[] = {
94 : #define _(sym,string) string,
95 : foreach_ip_inacl_error
96 : #undef _
97 : };
98 :
99 : typedef enum
100 : {
101 : #define _(sym,str) IP_OUTACL_ERROR_##sym,
102 : foreach_ip_outacl_error
103 : #undef _
104 : IP_OUTACL_N_ERROR,
105 : }
106 : ip_outacl_error_t;
107 :
108 : static char *ip_outacl_error_strings[] = {
109 : #define _(sym,string) string,
110 : foreach_ip_outacl_error
111 : #undef _
112 : };
113 :
114 : static_always_inline void
115 64 : ip_in_out_acl_inline_trace (
116 : vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame,
117 : vlib_buffer_t **b, u16 *next, u32 n_left, u32 *hits__, u32 *misses__,
118 : u32 *chain_hits__, const vlib_error_t error_none,
119 : const vlib_error_t error_deny, const vlib_error_t error_miss,
120 : vnet_classify_table_t *tables, const u32 *table_index_by_sw_if_index,
121 : u32 *fib_index_by_sw_if_index, vnet_config_main_t *cm,
122 : const vlib_rx_or_tx_t way, const int is_output, const int do_trace)
123 : {
124 64 : f64 now = vlib_time_now (vm);
125 64 : u32 hits = 0;
126 64 : u32 misses = 0;
127 64 : u32 chain_hits = 0;
128 64 : u32 n_next_nodes = node->n_next_nodes;
129 : u8 *h[4];
130 : u32 sw_if_index[4];
131 : u32 table_index[4];
132 64 : vnet_classify_table_t *t[4] = { 0, 0 };
133 : u32 hash[4];
134 :
135 : /* calculate hashes for b[0] & b[1] */
136 64 : if (n_left >= 2)
137 : {
138 : /* ~0 is used as a wildcard to say 'always use sw_if_index 0'
139 : * aka local0. It is used when we do not care about the sw_if_index, as
140 : * when punting */
141 63 : sw_if_index[2] = ~0 == way ? 0 : vnet_buffer (b[0])->sw_if_index[way];
142 63 : sw_if_index[3] = ~0 == way ? 0 : vnet_buffer (b[1])->sw_if_index[way];
143 :
144 63 : table_index[2] = table_index_by_sw_if_index[sw_if_index[2]];
145 63 : table_index[3] = table_index_by_sw_if_index[sw_if_index[3]];
146 :
147 63 : t[2] = pool_elt_at_index (tables, table_index[2]);
148 63 : t[3] = pool_elt_at_index (tables, table_index[3]);
149 :
150 63 : if (t[2]->current_data_flag == CLASSIFY_FLAG_USE_CURR_DATA)
151 45 : h[2] =
152 45 : (void *) vlib_buffer_get_current (b[0]) + t[2]->current_data_offset;
153 : else
154 18 : h[2] = b[0]->data;
155 :
156 63 : if (t[3]->current_data_flag == CLASSIFY_FLAG_USE_CURR_DATA)
157 45 : h[3] =
158 45 : (void *) vlib_buffer_get_current (b[1]) + t[3]->current_data_offset;
159 : else
160 18 : h[3] = b[1]->data;
161 :
162 63 : if (is_output)
163 : {
164 : /* Save the rewrite length, since we are using the l2_classify struct */
165 4 : vnet_buffer (b[0])->l2.l2_len =
166 4 : vnet_buffer (b[0])->ip.save_rewrite_length;
167 : /* advance the match pointer so the matching happens on IP header */
168 4 : h[2] += vnet_buffer (b[0])->l2.l2_len;
169 :
170 : /* Save the rewrite length, since we are using the l2_classify struct */
171 4 : vnet_buffer (b[1])->l2.l2_len =
172 4 : vnet_buffer (b[1])->ip.save_rewrite_length;
173 : /* advance the match pointer so the matching happens on IP header */
174 4 : h[3] += vnet_buffer (b[1])->l2.l2_len;
175 : }
176 :
177 63 : hash[2] = vnet_classify_hash_packet_inline (t[2], (u8 *) h[2]);
178 63 : hash[3] = vnet_classify_hash_packet_inline (t[3], (u8 *) h[3]);
179 :
180 63 : vnet_buffer (b[0])->l2_classify.hash = hash[2];
181 63 : vnet_buffer (b[1])->l2_classify.hash = hash[3];
182 :
183 63 : vnet_buffer (b[0])->l2_classify.table_index = table_index[2];
184 63 : vnet_buffer (b[1])->l2_classify.table_index = table_index[3];
185 :
186 63 : vnet_buffer (b[0])->l2_classify.opaque_index = ~0;
187 63 : vnet_buffer (b[1])->l2_classify.opaque_index = ~0;
188 :
189 63 : vnet_classify_prefetch_bucket (t[2],
190 63 : vnet_buffer (b[0])->l2_classify.hash);
191 63 : vnet_classify_prefetch_bucket (t[3],
192 63 : vnet_buffer (b[1])->l2_classify.hash);
193 : }
194 :
195 181 : while (n_left >= 2)
196 : {
197 117 : vnet_classify_entry_t *e[2] = { 0, 0 };
198 117 : u32 _next[2] = { ACL_NEXT_INDEX_DENY, ACL_NEXT_INDEX_DENY };
199 :
200 117 : h[0] = h[2];
201 117 : h[1] = h[3];
202 117 : t[0] = t[2];
203 117 : t[1] = t[3];
204 :
205 117 : sw_if_index[0] = sw_if_index[2];
206 117 : sw_if_index[1] = sw_if_index[3];
207 :
208 117 : table_index[0] = table_index[2];
209 117 : table_index[1] = table_index[3];
210 :
211 117 : hash[0] = hash[2];
212 117 : hash[1] = hash[3];
213 :
214 : /* prefetch next iteration */
215 117 : if (n_left >= 6)
216 : {
217 36 : vlib_prefetch_buffer_header (b[4], LOAD);
218 36 : vlib_prefetch_buffer_header (b[5], LOAD);
219 :
220 36 : clib_prefetch_load (b[4]->data);
221 36 : clib_prefetch_load (b[5]->data);
222 : }
223 :
224 : /* calculate hashes for b[2] & b[3] */
225 117 : if (n_left >= 4)
226 : {
227 54 : sw_if_index[2] =
228 54 : ~0 == way ? 0 : vnet_buffer (b[2])->sw_if_index[way];
229 54 : sw_if_index[3] =
230 54 : ~0 == way ? 0 : vnet_buffer (b[3])->sw_if_index[way];
231 :
232 54 : table_index[2] = table_index_by_sw_if_index[sw_if_index[2]];
233 54 : table_index[3] = table_index_by_sw_if_index[sw_if_index[3]];
234 :
235 54 : t[2] = pool_elt_at_index (tables, table_index[2]);
236 54 : t[3] = pool_elt_at_index (tables, table_index[3]);
237 :
238 54 : if (t[2]->current_data_flag == CLASSIFY_FLAG_USE_CURR_DATA)
239 0 : h[2] =
240 0 : (void *) vlib_buffer_get_current (b[2]) +
241 0 : t[2]->current_data_offset;
242 : else
243 54 : h[2] = b[2]->data;
244 :
245 54 : if (t[3]->current_data_flag == CLASSIFY_FLAG_USE_CURR_DATA)
246 0 : h[3] =
247 0 : (void *) vlib_buffer_get_current (b[3]) +
248 0 : t[3]->current_data_offset;
249 : else
250 54 : h[3] = b[3]->data;
251 :
252 54 : if (is_output)
253 : {
254 : /* Save the rewrite length, since we are using the l2_classify struct */
255 0 : vnet_buffer (b[2])->l2.l2_len =
256 0 : vnet_buffer (b[2])->ip.save_rewrite_length;
257 : /* advance the match pointer so the matching happens on IP header */
258 0 : h[2] += vnet_buffer (b[2])->l2.l2_len;
259 :
260 : /* Save the rewrite length, since we are using the l2_classify struct */
261 0 : vnet_buffer (b[3])->l2.l2_len =
262 0 : vnet_buffer (b[3])->ip.save_rewrite_length;
263 : /* advance the match pointer so the matching happens on IP header */
264 0 : h[3] += vnet_buffer (b[3])->l2.l2_len;
265 : }
266 :
267 54 : hash[2] = vnet_classify_hash_packet_inline (t[2], (u8 *) h[2]);
268 54 : hash[3] = vnet_classify_hash_packet_inline (t[3], (u8 *) h[3]);
269 :
270 54 : vnet_buffer (b[2])->l2_classify.hash = hash[2];
271 54 : vnet_buffer (b[3])->l2_classify.hash = hash[3];
272 :
273 54 : vnet_buffer (b[2])->l2_classify.table_index = table_index[2];
274 54 : vnet_buffer (b[3])->l2_classify.table_index = table_index[3];
275 :
276 54 : vnet_buffer (b[2])->l2_classify.opaque_index = ~0;
277 54 : vnet_buffer (b[3])->l2_classify.opaque_index = ~0;
278 :
279 54 : vnet_classify_prefetch_bucket (t[2],
280 54 : vnet_buffer (b[2])->
281 54 : l2_classify.hash);
282 54 : vnet_classify_prefetch_bucket (t[3],
283 54 : vnet_buffer (b[3])->
284 54 : l2_classify.hash);
285 : }
286 :
287 : /* find entry for b[0] & b[1] */
288 117 : vnet_get_config_data (cm, &b[0]->current_config_index, &_next[0],
289 : /* # bytes of config data */ 0);
290 117 : vnet_get_config_data (cm, &b[1]->current_config_index, &_next[1],
291 : /* # bytes of config data */ 0);
292 :
293 117 : if (PREDICT_TRUE (table_index[0] != ~0))
294 : {
295 117 : e[0] =
296 117 : vnet_classify_find_entry_inline (t[0], (u8 *) h[0], hash[0], now);
297 117 : if (e[0])
298 : {
299 78 : vnet_buffer (b[0])->l2_classify.opaque_index
300 78 : = e[0]->opaque_index;
301 78 : vlib_buffer_advance (b[0], e[0]->advance);
302 :
303 156 : _next[0] = (e[0]->next_index < n_next_nodes) ?
304 78 : e[0]->next_index : _next[0];
305 :
306 78 : hits++;
307 :
308 78 : b[0]->error =
309 78 : (_next[0] == ACL_NEXT_INDEX_DENY) ? error_deny : error_none;
310 :
311 78 : if (!is_output)
312 : {
313 75 : if (e[0]->action == CLASSIFY_ACTION_SET_IP4_FIB_INDEX ||
314 74 : e[0]->action == CLASSIFY_ACTION_SET_IP6_FIB_INDEX)
315 1 : vnet_buffer (b[0])->sw_if_index[VLIB_TX] = e[0]->metadata;
316 74 : else if (e[0]->action == CLASSIFY_ACTION_SET_METADATA)
317 : {
318 8 : vnet_buffer (b[0])->ip.adj_index[VLIB_TX] =
319 8 : e[0]->metadata;
320 : /* For source check in case we skip the lookup node */
321 8 : ip_lookup_set_buffer_fib_index (fib_index_by_sw_if_index,
322 : b[0]);
323 : }
324 : }
325 : }
326 : else
327 : {
328 : while (1)
329 : {
330 103 : table_index[0] = t[0]->next_table_index;
331 103 : if (PREDICT_TRUE (table_index[0] != ~0))
332 98 : t[0] = pool_elt_at_index (tables, table_index[0]);
333 : else
334 : {
335 10 : _next[0] = (t[0]->miss_next_index < n_next_nodes) ?
336 5 : t[0]->miss_next_index : _next[0];
337 :
338 5 : misses++;
339 :
340 5 : b[0]->error = (_next[0] == ACL_NEXT_INDEX_DENY) ?
341 : error_miss :
342 : error_none;
343 5 : break;
344 : }
345 :
346 98 : if (t[0]->current_data_flag == CLASSIFY_FLAG_USE_CURR_DATA)
347 2 : h[0] =
348 2 : (void *) vlib_buffer_get_current (b[0]) +
349 2 : t[0]->current_data_offset;
350 : else
351 96 : h[0] = b[0]->data;
352 :
353 : /* advance the match pointer so the matching happens on IP header */
354 98 : if (is_output)
355 1 : h[0] += vnet_buffer (b[0])->l2.l2_len;
356 :
357 98 : hash[0] =
358 98 : vnet_classify_hash_packet_inline (t[0], (u8 *) h[0]);
359 98 : e[0] =
360 98 : vnet_classify_find_entry_inline (t[0], (u8 *) h[0],
361 : hash[0], now);
362 98 : if (e[0])
363 : {
364 34 : vnet_buffer (b[0])->l2_classify.opaque_index
365 34 : = e[0]->opaque_index;
366 34 : vlib_buffer_advance (b[0], e[0]->advance);
367 68 : _next[0] = (e[0]->next_index < n_next_nodes) ?
368 34 : e[0]->next_index : _next[0];
369 34 : hits++;
370 34 : chain_hits++;
371 :
372 34 : b[0]->error = (_next[0] == ACL_NEXT_INDEX_DENY) ?
373 : error_deny :
374 : error_none;
375 :
376 34 : if (!is_output)
377 : {
378 33 : if (e[0]->action ==
379 : CLASSIFY_ACTION_SET_IP4_FIB_INDEX
380 33 : || e[0]->action ==
381 : CLASSIFY_ACTION_SET_IP6_FIB_INDEX)
382 0 : vnet_buffer (b[0])->sw_if_index[VLIB_TX] =
383 0 : e[0]->metadata;
384 33 : else if (e[0]->action ==
385 : CLASSIFY_ACTION_SET_METADATA)
386 : {
387 0 : vnet_buffer (b[0])->ip.adj_index[VLIB_TX] =
388 0 : e[0]->metadata;
389 : /* For source check in case we skip the lookup
390 : * node */
391 0 : ip_lookup_set_buffer_fib_index (
392 : fib_index_by_sw_if_index, b[0]);
393 : }
394 : }
395 34 : break;
396 : }
397 : }
398 : }
399 : }
400 :
401 117 : if (PREDICT_TRUE (table_index[1] != ~0))
402 : {
403 117 : e[1] =
404 117 : vnet_classify_find_entry_inline (t[1], (u8 *) h[1], hash[1], now);
405 117 : if (e[1])
406 : {
407 62 : vnet_buffer (b[1])->l2_classify.opaque_index
408 62 : = e[1]->opaque_index;
409 62 : vlib_buffer_advance (b[1], e[1]->advance);
410 :
411 124 : _next[1] = (e[1]->next_index < n_next_nodes) ?
412 62 : e[1]->next_index : _next[1];
413 :
414 62 : hits++;
415 :
416 62 : b[1]->error =
417 62 : (_next[1] == ACL_NEXT_INDEX_DENY) ? error_deny : error_none;
418 :
419 62 : if (!is_output)
420 : {
421 59 : if (e[1]->action == CLASSIFY_ACTION_SET_IP4_FIB_INDEX ||
422 58 : e[1]->action == CLASSIFY_ACTION_SET_IP6_FIB_INDEX)
423 1 : vnet_buffer (b[1])->sw_if_index[VLIB_TX] = e[1]->metadata;
424 58 : else if (e[1]->action == CLASSIFY_ACTION_SET_METADATA)
425 : {
426 8 : vnet_buffer (b[1])->ip.adj_index[VLIB_TX] =
427 8 : e[1]->metadata;
428 : /* For source check in case we skip the lookup node */
429 8 : ip_lookup_set_buffer_fib_index (fib_index_by_sw_if_index,
430 8 : b[1]);
431 : }
432 : }
433 : }
434 : else
435 : {
436 : while (1)
437 : {
438 151 : table_index[1] = t[1]->next_table_index;
439 151 : if (PREDICT_TRUE (table_index[1] != ~0))
440 146 : t[1] = pool_elt_at_index (tables, table_index[1]);
441 : else
442 : {
443 10 : _next[1] = (t[1]->miss_next_index < n_next_nodes) ?
444 5 : t[1]->miss_next_index : _next[1];
445 :
446 5 : misses++;
447 :
448 5 : b[1]->error = (_next[1] == ACL_NEXT_INDEX_DENY) ?
449 : error_miss :
450 : error_none;
451 5 : break;
452 : }
453 :
454 146 : if (t[1]->current_data_flag == CLASSIFY_FLAG_USE_CURR_DATA)
455 2 : h[1] =
456 2 : (void *) vlib_buffer_get_current (b[1]) +
457 2 : t[1]->current_data_offset;
458 : else
459 144 : h[1] = b[1]->data;
460 :
461 : /* advance the match pointer so the matching happens on IP header */
462 146 : if (is_output)
463 1 : h[1] += vnet_buffer (b[1])->l2.l2_len;
464 :
465 146 : hash[1] =
466 146 : vnet_classify_hash_packet_inline (t[1], (u8 *) h[1]);
467 146 : e[1] =
468 146 : vnet_classify_find_entry_inline (t[1], (u8 *) h[1],
469 : hash[1], now);
470 146 : if (e[1])
471 : {
472 50 : vnet_buffer (b[1])->l2_classify.opaque_index
473 50 : = e[1]->opaque_index;
474 50 : vlib_buffer_advance (b[1], e[1]->advance);
475 100 : _next[1] = (e[1]->next_index < n_next_nodes) ?
476 50 : e[1]->next_index : _next[1];
477 50 : hits++;
478 50 : chain_hits++;
479 :
480 50 : b[1]->error = (_next[1] == ACL_NEXT_INDEX_DENY) ?
481 : error_deny :
482 : error_none;
483 :
484 50 : if (!is_output)
485 : {
486 49 : if (e[1]->action ==
487 : CLASSIFY_ACTION_SET_IP4_FIB_INDEX
488 49 : || e[1]->action ==
489 : CLASSIFY_ACTION_SET_IP6_FIB_INDEX)
490 0 : vnet_buffer (b[1])->sw_if_index[VLIB_TX] =
491 0 : e[1]->metadata;
492 49 : else if (e[1]->action ==
493 : CLASSIFY_ACTION_SET_METADATA)
494 : {
495 0 : vnet_buffer (b[1])->ip.adj_index[VLIB_TX] =
496 0 : e[1]->metadata;
497 : /* For source check in case we skip the lookup
498 : * node */
499 0 : ip_lookup_set_buffer_fib_index (
500 0 : fib_index_by_sw_if_index, b[1]);
501 : }
502 : }
503 50 : break;
504 : }
505 : }
506 : }
507 : }
508 :
509 117 : if (do_trace && b[0]->flags & VLIB_BUFFER_IS_TRACED)
510 : {
511 : ip_in_out_acl_trace_t *_t =
512 117 : vlib_add_trace (vm, node, b[0], sizeof (*_t));
513 117 : _t->sw_if_index =
514 117 : ~0 == way ? 0 : vnet_buffer (b[0])->sw_if_index[way];
515 117 : _t->next_index = _next[0];
516 117 : _t->table_index = table_index[0];
517 229 : _t->offset = (e[0]
518 112 : && t[0]) ? vnet_classify_get_offset (t[0], e[0]) : ~0;
519 : }
520 :
521 117 : if (do_trace && b[1]->flags & VLIB_BUFFER_IS_TRACED)
522 : {
523 : ip_in_out_acl_trace_t *_t =
524 117 : vlib_add_trace (vm, node, b[1], sizeof (*_t));
525 117 : _t->sw_if_index =
526 117 : ~0 == way ? 0 : vnet_buffer (b[1])->sw_if_index[way];
527 117 : _t->next_index = _next[1];
528 117 : _t->table_index = table_index[1];
529 229 : _t->offset = (e[1]
530 112 : && t[1]) ? vnet_classify_get_offset (t[1], e[1]) : ~0;
531 : }
532 :
533 117 : if ((_next[0] == ACL_NEXT_INDEX_DENY) && is_output)
534 : {
535 : /* on output, for the drop node to work properly, go back to ip header */
536 0 : vlib_buffer_advance (b[0], vnet_buffer (b[0])->l2.l2_len);
537 : }
538 :
539 117 : if ((_next[1] == ACL_NEXT_INDEX_DENY) && is_output)
540 : {
541 : /* on output, for the drop node to work properly, go back to ip header */
542 0 : vlib_buffer_advance (b[1], vnet_buffer (b[1])->l2.l2_len);
543 : }
544 :
545 117 : next[0] = _next[0];
546 117 : next[1] = _next[1];
547 :
548 : /* _next */
549 117 : next += 2;
550 117 : b += 2;
551 117 : n_left -= 2;
552 : }
553 :
554 83 : while (n_left > 0)
555 : {
556 : u8 *h0;
557 : u32 sw_if_index0;
558 : u32 table_index0;
559 19 : vnet_classify_table_t *t0 = 0;
560 19 : vnet_classify_entry_t *e0 = 0;
561 19 : u32 next0 = ACL_NEXT_INDEX_DENY;
562 : u32 hash0;
563 :
564 19 : sw_if_index0 = ~0 == way ? 0 : vnet_buffer (b[0])->sw_if_index[way];
565 19 : table_index0 = table_index_by_sw_if_index[sw_if_index0];
566 :
567 19 : t0 = pool_elt_at_index (tables, table_index0);
568 :
569 19 : if (t0->current_data_flag == CLASSIFY_FLAG_USE_CURR_DATA)
570 1 : h0 =
571 1 : (void *) vlib_buffer_get_current (b[0]) + t0->current_data_offset;
572 : else
573 18 : h0 = b[0]->data;
574 :
575 19 : if (is_output)
576 : {
577 : /* Save the rewrite length, since we are using the l2_classify struct */
578 1 : vnet_buffer (b[0])->l2.l2_len =
579 1 : vnet_buffer (b[0])->ip.save_rewrite_length;
580 : /* advance the match pointer so the matching happens on IP header */
581 1 : h0 += vnet_buffer (b[0])->l2.l2_len;
582 : }
583 :
584 38 : vnet_buffer (b[0])->l2_classify.hash =
585 19 : vnet_classify_hash_packet (t0, (u8 *) h0);
586 :
587 19 : vnet_buffer (b[0])->l2_classify.table_index = table_index0;
588 19 : vnet_buffer (b[0])->l2_classify.opaque_index = ~0;
589 :
590 19 : vnet_get_config_data (cm, &b[0]->current_config_index, &next0,
591 : /* # bytes of config data */ 0);
592 :
593 19 : if (PREDICT_TRUE (table_index0 != ~0))
594 : {
595 19 : hash0 = vnet_buffer (b[0])->l2_classify.hash;
596 19 : t0 = pool_elt_at_index (tables, table_index0);
597 :
598 19 : if (t0->current_data_flag == CLASSIFY_FLAG_USE_CURR_DATA)
599 1 : h0 =
600 1 : (void *) vlib_buffer_get_current (b[0]) +
601 1 : t0->current_data_offset;
602 : else
603 18 : h0 = b[0]->data;
604 :
605 : /* advance the match pointer so the matching happens on IP header */
606 19 : if (is_output)
607 1 : h0 += vnet_buffer (b[0])->l2.l2_len;
608 :
609 19 : e0 = vnet_classify_find_entry_inline (t0, (u8 *) h0, hash0, now);
610 19 : if (e0)
611 : {
612 2 : vnet_buffer (b[0])->l2_classify.opaque_index = e0->opaque_index;
613 2 : vlib_buffer_advance (b[0], e0->advance);
614 :
615 4 : next0 = (e0->next_index < n_next_nodes) ?
616 2 : e0->next_index : next0;
617 :
618 2 : hits++;
619 :
620 2 : b[0]->error =
621 2 : (next0 == ACL_NEXT_INDEX_DENY) ? error_deny : error_none;
622 :
623 2 : if (!is_output)
624 : {
625 2 : if (e0->action == CLASSIFY_ACTION_SET_IP4_FIB_INDEX ||
626 2 : e0->action == CLASSIFY_ACTION_SET_IP6_FIB_INDEX)
627 0 : vnet_buffer (b[0])->sw_if_index[VLIB_TX] = e0->metadata;
628 2 : else if (e0->action == CLASSIFY_ACTION_SET_METADATA)
629 : {
630 0 : vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = e0->metadata;
631 : /* For source check in case we skip the lookup node */
632 0 : ip_lookup_set_buffer_fib_index (fib_index_by_sw_if_index,
633 : b[0]);
634 : }
635 : }
636 : }
637 : else
638 : {
639 : while (1)
640 : {
641 49 : table_index0 = t0->next_table_index;
642 49 : if (PREDICT_TRUE (table_index0 != ~0))
643 48 : t0 = pool_elt_at_index (tables, table_index0);
644 : else
645 : {
646 2 : next0 = (t0->miss_next_index < n_next_nodes) ?
647 1 : t0->miss_next_index : next0;
648 :
649 1 : misses++;
650 :
651 1 : b[0]->error = (next0 == ACL_NEXT_INDEX_DENY) ?
652 : error_miss :
653 : error_none;
654 1 : break;
655 : }
656 :
657 48 : if (t0->current_data_flag == CLASSIFY_FLAG_USE_CURR_DATA)
658 0 : h0 =
659 0 : (void *) vlib_buffer_get_current (b[0]) +
660 0 : t0->current_data_offset;
661 : else
662 48 : h0 = b[0]->data;
663 :
664 : /* advance the match pointer so the matching happens on IP header */
665 48 : if (is_output)
666 0 : h0 += vnet_buffer (b[0])->l2.l2_len;
667 :
668 48 : hash0 = vnet_classify_hash_packet_inline (t0, (u8 *) h0);
669 48 : e0 = vnet_classify_find_entry_inline
670 : (t0, (u8 *) h0, hash0, now);
671 48 : if (e0)
672 : {
673 16 : vnet_buffer (b[0])->l2_classify.opaque_index
674 16 : = e0->opaque_index;
675 16 : vlib_buffer_advance (b[0], e0->advance);
676 32 : next0 = (e0->next_index < n_next_nodes) ?
677 16 : e0->next_index : next0;
678 16 : hits++;
679 :
680 16 : b[0]->error = (next0 == ACL_NEXT_INDEX_DENY) ?
681 : error_deny :
682 : error_none;
683 :
684 16 : if (!is_output)
685 : {
686 16 : if (e0->action ==
687 : CLASSIFY_ACTION_SET_IP4_FIB_INDEX
688 16 : || e0->action ==
689 : CLASSIFY_ACTION_SET_IP6_FIB_INDEX)
690 0 : vnet_buffer (b[0])->sw_if_index[VLIB_TX] =
691 0 : e0->metadata;
692 16 : else if (e0->action == CLASSIFY_ACTION_SET_METADATA)
693 : {
694 0 : vnet_buffer (b[0])->ip.adj_index[VLIB_TX] =
695 0 : e0->metadata;
696 : /* For source check in case we skip the lookup
697 : * node */
698 0 : ip_lookup_set_buffer_fib_index (
699 : fib_index_by_sw_if_index, b[0]);
700 : }
701 : }
702 16 : break;
703 : }
704 : }
705 : }
706 : }
707 :
708 19 : if (do_trace && b[0]->flags & VLIB_BUFFER_IS_TRACED)
709 : {
710 : ip_in_out_acl_trace_t *t =
711 18 : vlib_add_trace (vm, node, b[0], sizeof (*t));
712 18 : t->sw_if_index =
713 18 : ~0 == way ? 0 : vnet_buffer (b[0])->sw_if_index[way];
714 18 : t->next_index = next0;
715 18 : t->table_index = table_index0;
716 18 : t->offset = (e0 && t0) ? vnet_classify_get_offset (t0, e0) : ~0;
717 : }
718 :
719 19 : if ((next0 == ACL_NEXT_INDEX_DENY) && is_output)
720 : {
721 : /* on output, for the drop node to work properly, go back to ip header */
722 1 : vlib_buffer_advance (b[0], vnet_buffer (b[0])->l2.l2_len);
723 : }
724 :
725 19 : next[0] = next0;
726 :
727 : /* next */
728 19 : next++;
729 19 : b++;
730 19 : n_left--;
731 : }
732 :
733 64 : *hits__ = hits;
734 64 : *misses__ = misses;
735 64 : *chain_hits__ = chain_hits;
736 64 : }
737 :
738 : static_always_inline uword
739 64 : ip_in_out_acl_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
740 : vlib_frame_t *frame, const in_out_acl_table_id_t tid,
741 : u32 *fib_index_by_sw_if_index,
742 : const vlib_node_registration_t *parent_error_node,
743 : const u32 error_none_index, const u32 error_deny_index,
744 : const u32 error_miss_index, const vlib_rx_or_tx_t way,
745 : const int is_output)
746 : {
747 64 : const in_out_acl_main_t *am = &in_out_acl_main;
748 64 : vnet_classify_table_t *tables = am->vnet_classify_main->tables;
749 64 : u32 *from = vlib_frame_vector_args (frame);
750 64 : const u32 *table_index_by_sw_if_index =
751 : am->classify_table_index_by_sw_if_index[is_output][tid];
752 64 : vnet_config_main_t *cm = am->vnet_config_main[is_output][tid];
753 : const vlib_node_runtime_t *error_node =
754 64 : vlib_node_get_runtime (vm, parent_error_node->index);
755 64 : const vlib_error_t error_none = error_node->errors[error_none_index];
756 64 : const vlib_error_t error_deny = error_node->errors[error_deny_index];
757 64 : const vlib_error_t error_miss = error_node->errors[error_miss_index];
758 : vlib_buffer_t *bufs[VLIB_FRAME_SIZE];
759 : u16 nexts[VLIB_FRAME_SIZE];
760 : u32 hits, misses, chain_hits;
761 :
762 64 : vlib_get_buffers (vm, from, bufs, frame->n_vectors);
763 :
764 : #define ip_in_out_acl_inline_trace__(do_trace) \
765 : ip_in_out_acl_inline_trace ( \
766 : vm, node, frame, bufs, nexts, frame->n_vectors, &hits, &misses, \
767 : &chain_hits, error_deny, error_miss, error_none, tables, \
768 : table_index_by_sw_if_index, fib_index_by_sw_if_index, cm, way, is_output, \
769 : do_trace)
770 :
771 64 : if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE))
772 63 : ip_in_out_acl_inline_trace__ (1 /* do_trace */);
773 : else
774 1 : ip_in_out_acl_inline_trace__ (0 /* do_trace */);
775 :
776 64 : vlib_node_increment_counter (
777 : vm, node->node_index,
778 : is_output ? IP_OUTACL_ERROR_MISS : IP_INACL_ERROR_MISS, misses);
779 64 : vlib_node_increment_counter (
780 : vm, node->node_index, is_output ? IP_OUTACL_ERROR_HIT : IP_INACL_ERROR_HIT,
781 : hits);
782 64 : vlib_node_increment_counter (vm, node->node_index,
783 : is_output ? IP_OUTACL_ERROR_CHAIN_HIT :
784 : IP_INACL_ERROR_CHAIN_HIT,
785 : chain_hits);
786 :
787 64 : vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
788 64 : return frame->n_vectors;
789 : }
790 :
791 2263 : VLIB_NODE_FN (ip4_inacl_node)
792 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
793 : {
794 27 : return ip_in_out_acl_inline (
795 : vm, node, frame, IN_OUT_ACL_TABLE_IP4, ip4_main.fib_index_by_sw_if_index,
796 : &ip4_input_node, IP4_ERROR_NONE, IP4_ERROR_INACL_SESSION_DENY,
797 : IP4_ERROR_INACL_TABLE_MISS, VLIB_RX, 0 /* is_output */);
798 : }
799 :
800 2241 : VLIB_NODE_FN (ip4_punt_acl_node)
801 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
802 : {
803 5 : return ip_in_out_acl_inline (
804 : vm, node, frame, IN_OUT_ACL_TABLE_IP4_PUNT,
805 : ip4_main.fib_index_by_sw_if_index, &ip4_input_node, IP4_ERROR_NONE,
806 : IP4_ERROR_INACL_SESSION_DENY, IP4_ERROR_INACL_TABLE_MISS, ~0 /* way */,
807 : 0 /* is_output */);
808 : }
809 :
810 2239 : VLIB_NODE_FN (ip4_outacl_node)
811 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
812 : {
813 3 : return ip_in_out_acl_inline (
814 : vm, node, frame, IN_OUT_ACL_TABLE_IP4, NULL, &ip4_input_node,
815 : IP4_ERROR_NONE, IP4_ERROR_INACL_SESSION_DENY, IP4_ERROR_INACL_TABLE_MISS,
816 : VLIB_TX, 1 /* is_output */);
817 : }
818 :
819 : /* *INDENT-OFF* */
820 178120 : VLIB_REGISTER_NODE (ip4_inacl_node) = {
821 : .name = "ip4-inacl",
822 : .vector_size = sizeof (u32),
823 : .format_trace = format_ip_inacl_trace,
824 : .n_errors = ARRAY_LEN(ip_inacl_error_strings),
825 : .error_strings = ip_inacl_error_strings,
826 :
827 : .n_next_nodes = ACL_NEXT_INDEX_N_NEXT,
828 : .next_nodes = {
829 : [ACL_NEXT_INDEX_DENY] = "ip4-drop",
830 : },
831 : };
832 :
833 178120 : VLIB_REGISTER_NODE (ip4_punt_acl_node) = {
834 : .name = "ip4-punt-acl",
835 : .vector_size = sizeof (u32),
836 : .format_trace = format_ip_inacl_trace,
837 : .n_errors = ARRAY_LEN(ip_inacl_error_strings),
838 : .error_strings = ip_inacl_error_strings,
839 :
840 : .n_next_nodes = ACL_NEXT_INDEX_N_NEXT,
841 : .next_nodes = {
842 : [ACL_NEXT_INDEX_DENY] = "ip4-drop",
843 : },
844 : };
845 :
846 178120 : VLIB_REGISTER_NODE (ip4_outacl_node) = {
847 : .name = "ip4-outacl",
848 : .vector_size = sizeof (u32),
849 : .format_trace = format_ip_outacl_trace,
850 : .n_errors = ARRAY_LEN(ip_outacl_error_strings),
851 : .error_strings = ip_outacl_error_strings,
852 :
853 : .n_next_nodes = ACL_NEXT_INDEX_N_NEXT,
854 : .next_nodes = {
855 : [ACL_NEXT_INDEX_DENY] = "ip4-drop",
856 : },
857 : };
858 : /* *INDENT-ON* */
859 :
860 70583 : VNET_FEATURE_INIT (ip4_punt_acl_feature) = {
861 : .arc_name = "ip4-punt",
862 : .node_name = "ip4-punt-acl",
863 : .runs_after = VNET_FEATURES ("ip4-punt-policer"),
864 : };
865 :
866 2260 : VLIB_NODE_FN (ip6_inacl_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
867 : vlib_frame_t * frame)
868 : {
869 24 : return ip_in_out_acl_inline (
870 : vm, node, frame, IN_OUT_ACL_TABLE_IP6, ip6_main.fib_index_by_sw_if_index,
871 : &ip6_input_node, IP6_ERROR_NONE, IP6_ERROR_INACL_SESSION_DENY,
872 : IP6_ERROR_INACL_TABLE_MISS, VLIB_RX, 0 /* is_output */);
873 : }
874 :
875 2239 : VLIB_NODE_FN (ip6_punt_acl_node)
876 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
877 : {
878 3 : return ip_in_out_acl_inline (
879 : vm, node, frame, IN_OUT_ACL_TABLE_IP6_PUNT,
880 : ip4_main.fib_index_by_sw_if_index, &ip6_input_node, IP6_ERROR_NONE,
881 : IP6_ERROR_INACL_SESSION_DENY, IP6_ERROR_INACL_TABLE_MISS, ~0 /* way */,
882 : 0 /* is_output */);
883 : }
884 :
885 2238 : VLIB_NODE_FN (ip6_outacl_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
886 : vlib_frame_t * frame)
887 : {
888 2 : return ip_in_out_acl_inline (
889 : vm, node, frame, IN_OUT_ACL_TABLE_IP6, NULL, &ip6_input_node,
890 : IP6_ERROR_NONE, IP6_ERROR_INACL_SESSION_DENY, IP6_ERROR_INACL_TABLE_MISS,
891 : VLIB_TX, 1 /* is_output */);
892 : }
893 :
894 : /* *INDENT-OFF* */
895 178120 : VLIB_REGISTER_NODE (ip6_inacl_node) = {
896 : .name = "ip6-inacl",
897 : .vector_size = sizeof (u32),
898 : .format_trace = format_ip_inacl_trace,
899 : .n_errors = ARRAY_LEN(ip_inacl_error_strings),
900 : .error_strings = ip_inacl_error_strings,
901 :
902 : .n_next_nodes = ACL_NEXT_INDEX_N_NEXT,
903 : .next_nodes = {
904 : [ACL_NEXT_INDEX_DENY] = "ip6-drop",
905 : },
906 : };
907 :
908 178120 : VLIB_REGISTER_NODE (ip6_punt_acl_node) = {
909 : .name = "ip6-punt-acl",
910 : .vector_size = sizeof (u32),
911 : .format_trace = format_ip_inacl_trace,
912 : .n_errors = ARRAY_LEN(ip_inacl_error_strings),
913 : .error_strings = ip_inacl_error_strings,
914 :
915 : .n_next_nodes = ACL_NEXT_INDEX_N_NEXT,
916 : .next_nodes = {
917 : [ACL_NEXT_INDEX_DENY] = "ip6-drop",
918 : },
919 : };
920 :
921 178120 : VLIB_REGISTER_NODE (ip6_outacl_node) = {
922 : .name = "ip6-outacl",
923 : .vector_size = sizeof (u32),
924 : .format_trace = format_ip_outacl_trace,
925 : .n_errors = ARRAY_LEN(ip_outacl_error_strings),
926 : .error_strings = ip_outacl_error_strings,
927 :
928 : .n_next_nodes = ACL_NEXT_INDEX_N_NEXT,
929 : .next_nodes = {
930 : [ACL_NEXT_INDEX_DENY] = "ip6-drop",
931 : },
932 : };
933 : /* *INDENT-ON* */
934 :
935 70583 : VNET_FEATURE_INIT (ip6_punt_acl_feature) = {
936 : .arc_name = "ip6-punt",
937 : .node_name = "ip6-punt-acl",
938 : .runs_after = VNET_FEATURES ("ip6-punt-policer"),
939 : };
940 :
941 : #ifndef CLIB_MARCH_VARIANT
942 : static clib_error_t *
943 559 : ip_in_out_acl_init (vlib_main_t * vm)
944 : {
945 559 : return 0;
946 : }
947 :
948 18479 : VLIB_INIT_FUNCTION (ip_in_out_acl_init);
949 : #endif /* CLIB_MARCH_VARIANT */
950 :
951 :
952 : /*
953 : * fd.io coding-style-patch-verification: ON
954 : *
955 : * Local Variables:
956 : * eval: (c-set-style "gnu")
957 : * End:
958 : */
|