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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
15 #include <vlib/vlib.h>
16 #include <vnet/vnet.h>
17 #include <vnet/policer/policer.h>
19 /* Dispatch functions meant to be instantiated elsewhere */
25 } vnet_policer_trace_t;
27 /* packet trace format function */
28 static u8 * format_policer_trace (u8 * s, va_list * args)
30 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
31 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
32 vnet_policer_trace_t * t = va_arg (*args, vnet_policer_trace_t *);
34 s = format (s, "VNET_POLICER: sw_if_index %d policer_index %d next %d",
35 t->sw_if_index, t->policer_index, t->next_index);
39 #define foreach_vnet_policer_error \
40 _(TRANSMIT, "Packets Transmitted") \
41 _(DROP, "Packets Dropped")
44 #define _(sym,str) VNET_POLICER_ERROR_##sym,
45 foreach_vnet_policer_error
48 } vnet_policer_error_t;
50 static char * vnet_policer_error_strings[] = {
51 #define _(sym,string) string,
52 foreach_vnet_policer_error
57 uword vnet_policer_inline (vlib_main_t * vm,
58 vlib_node_runtime_t * node,
60 vnet_policer_index_t which)
62 u32 n_left_from, * from, * to_next;
63 vnet_policer_next_t next_index;
64 vnet_policer_main_t * pm = &vnet_policer_main;
65 u64 time_in_policer_periods;
68 time_in_policer_periods =
69 clib_cpu_time_now() >> POLICER_TICKS_PER_PERIOD_SHIFT;
71 from = vlib_frame_vector_args (frame);
72 n_left_from = frame->n_vectors;
73 next_index = node->cached_next_index;
75 while (n_left_from > 0)
79 vlib_get_next_frame (vm, node, next_index,
80 to_next, n_left_to_next);
82 while (n_left_from >= 4 && n_left_to_next >= 2)
85 vlib_buffer_t * b0, * b1;
87 u32 sw_if_index0, sw_if_index1;
91 policer_read_response_type_st * pol0, * pol1;
93 /* Prefetch next iteration. */
95 vlib_buffer_t * b2, * b3;
97 b2 = vlib_get_buffer (vm, from[2]);
98 b3 = vlib_get_buffer (vm, from[3]);
100 vlib_prefetch_buffer_header (b2, LOAD);
101 vlib_prefetch_buffer_header (b3, LOAD);
104 /* speculatively enqueue b0 and b1 to the current next frame */
105 to_next[0] = bi0 = from[0];
106 to_next[1] = bi1 = from[1];
112 b0 = vlib_get_buffer (vm, bi0);
113 b1 = vlib_get_buffer (vm, bi1);
115 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
116 next0 = VNET_POLICER_NEXT_TRANSMIT;
118 sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
119 next1 = VNET_POLICER_NEXT_TRANSMIT;
122 if (which == VNET_POLICER_INDEX_BY_SW_IF_INDEX)
124 pi0 = pm->policer_index_by_sw_if_index[sw_if_index0];
125 pi1 = pm->policer_index_by_sw_if_index[sw_if_index1];
128 if (which == VNET_POLICER_INDEX_BY_OPAQUE)
130 pi0 = vnet_buffer(b0)->policer.index;
131 pi1 = vnet_buffer(b1)->policer.index;
134 if (which == VNET_POLICER_INDEX_BY_EITHER)
136 pi0 = vnet_buffer(b0)->policer.index;
137 pi0 = (pi0 != ~0) ? pi0 :
138 pm->policer_index_by_sw_if_index [sw_if_index0];
139 pi1 = vnet_buffer(b1)->policer.index;
140 pi1 = (pi1 != ~0) ? pi1 :
141 pm->policer_index_by_sw_if_index [sw_if_index1];
144 len0 = vlib_buffer_length_in_chain (vm, b0);
145 pol0 = &pm->policers [pi0];
146 col0 = vnet_police_packet (pol0, len0,
147 POLICE_CONFORM /* no chaining */,
148 time_in_policer_periods);
150 len1 = vlib_buffer_length_in_chain (vm, b1);
151 pol1 = &pm->policers [pi1];
152 col1 = vnet_police_packet (pol1, len1,
153 POLICE_CONFORM /* no chaining */,
154 time_in_policer_periods);
156 if (PREDICT_FALSE(col0 > 0))
158 next0 = VNET_POLICER_NEXT_DROP;
159 b0->error = node->errors[VNET_POLICER_ERROR_DROP];
164 if (PREDICT_FALSE(col1 > 0))
166 next1 = VNET_POLICER_NEXT_DROP;
167 b1->error = node->errors[VNET_POLICER_ERROR_DROP];
173 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)))
175 if (b0->flags & VLIB_BUFFER_IS_TRACED)
177 vnet_policer_trace_t *t =
178 vlib_add_trace (vm, node, b0, sizeof (*t));
179 t->sw_if_index = sw_if_index0;
180 t->next_index = next0;
182 if (b1->flags & VLIB_BUFFER_IS_TRACED)
184 vnet_policer_trace_t *t =
185 vlib_add_trace (vm, node, b1, sizeof (*t));
186 t->sw_if_index = sw_if_index1;
187 t->next_index = next1;
191 /* verify speculative enqueues, maybe switch current next frame */
192 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
193 to_next, n_left_to_next,
194 bi0, bi1, next0, next1);
197 while (n_left_from > 0 && n_left_to_next > 0)
206 policer_read_response_type_st * pol0;
215 b0 = vlib_get_buffer (vm, bi0);
217 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
218 next0 = VNET_POLICER_NEXT_TRANSMIT;
220 if (which == VNET_POLICER_INDEX_BY_SW_IF_INDEX)
221 pi0 = pm->policer_index_by_sw_if_index[sw_if_index0];
223 if (which == VNET_POLICER_INDEX_BY_OPAQUE)
224 pi0 = vnet_buffer(b0)->policer.index;
226 if (which == VNET_POLICER_INDEX_BY_EITHER)
228 pi0 = vnet_buffer(b0)->policer.index;
229 pi0 = (pi0 != ~0) ? pi0 :
230 pm->policer_index_by_sw_if_index [sw_if_index0];
233 len0 = vlib_buffer_length_in_chain (vm, b0);
234 pol0 = &pm->policers [pi0];
235 col0 = vnet_police_packet (pol0, len0,
236 POLICE_CONFORM /* no chaining */,
237 time_in_policer_periods);
239 if (PREDICT_FALSE(col0 > 0))
241 next0 = VNET_POLICER_NEXT_DROP;
242 b0->error = node->errors[VNET_POLICER_ERROR_DROP];
249 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
250 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
252 vnet_policer_trace_t *t =
253 vlib_add_trace (vm, node, b0, sizeof (*t));
254 t->sw_if_index = sw_if_index0;
255 t->next_index = next0;
256 t->policer_index = pi0;
259 /* verify speculative enqueue, maybe switch current next frame */
260 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
261 to_next, n_left_to_next,
265 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
268 vlib_node_increment_counter (vm, node->node_index,
269 VNET_POLICER_ERROR_TRANSMIT,
271 return frame->n_vectors;
274 uword vnet_policer_by_sw_if_index (vlib_main_t * vm,
275 vlib_node_runtime_t * node,
276 vlib_frame_t * frame)
278 return vnet_policer_inline (vm, node, frame,
279 VNET_POLICER_INDEX_BY_SW_IF_INDEX);
282 uword vnet_policer_by_opaque (vlib_main_t * vm,
283 vlib_node_runtime_t * node,
284 vlib_frame_t * frame)
286 return vnet_policer_inline (vm, node, frame,
287 VNET_POLICER_INDEX_BY_OPAQUE);
290 uword vnet_policer_by_either (vlib_main_t * vm,
291 vlib_node_runtime_t * node,
292 vlib_frame_t * frame)
294 return vnet_policer_inline (vm, node, frame,
295 VNET_POLICER_INDEX_BY_EITHER);
298 void vnet_policer_node_funcs_reference (void) { }
305 VLIB_REGISTER_NODE (policer_by_sw_if_index_node, static) = {
306 .function = vnet_policer_by_sw_if_index,
307 .name = "policer-by-sw-if-index",
308 .vector_size = sizeof (u32),
309 .format_trace = format_policer_trace,
310 .type = VLIB_NODE_TYPE_INTERNAL,
312 .n_errors = ARRAY_LEN(vnet_policer_error_strings),
313 .error_strings = vnet_policer_error_strings,
315 .n_next_nodes = VNET_POLICER_N_NEXT,
317 /* edit / add dispositions here */
319 [VNET_POLICER_NEXT_TRANSMIT] = "ethernet-input",
320 [VNET_POLICER_NEXT_DROP] = "error-drop",
325 int test_policer_add_del (u32 rx_sw_if_index, u8 *config_name,
328 vnet_policer_main_t * pm = &vnet_policer_main;
329 policer_read_response_type_st * template;
330 policer_read_response_type_st * policer;
331 vnet_hw_interface_t * rxhi;
334 rxhi = vnet_get_sup_hw_interface (pm->vnet_main, rx_sw_if_index);
336 /* Make sure caller didn't pass a vlan subif, etc. */
337 if (rxhi->sw_if_index != rx_sw_if_index)
338 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
343 p = hash_get_mem (pm->policer_config_by_name, config_name);
348 template = pool_elt_at_index (pm->policer_templates, p[0]);
350 vnet_hw_interface_rx_redirect_to_node
353 policer_by_sw_if_index_node.index);
355 pool_get_aligned (pm->policers, policer, CLIB_CACHE_LINE_BYTES);
357 policer[0] = template[0];
359 vec_validate (pm->policer_index_by_sw_if_index, rx_sw_if_index);
360 pm->policer_index_by_sw_if_index[rx_sw_if_index]
361 = policer - pm->policers;
366 vnet_hw_interface_rx_redirect_to_node (pm->vnet_main,
370 pi = pm->policer_index_by_sw_if_index[rx_sw_if_index];
371 pm->policer_index_by_sw_if_index[rx_sw_if_index] = ~0;
372 pool_put_index (pm->policers, pi);
378 static clib_error_t *
379 test_policer_command_fn (vlib_main_t * vm,
380 unformat_input_t * input,
381 vlib_cli_command_t * cmd)
383 vnet_policer_main_t * pm = &vnet_policer_main;
384 unformat_input_t _line_input, * line_input = &_line_input;
387 u8 * config_name = 0;
392 /* Get a line of input. */
393 if (! unformat_user (input, unformat_line_input, line_input))
396 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
398 if (unformat (line_input, "intfc %U", unformat_vnet_sw_interface,
399 pm->vnet_main, &rx_sw_if_index))
401 else if (unformat (line_input, "show"))
403 else if (unformat (line_input, "policer %s", &config_name))
405 else if (unformat (line_input, "del"))
411 return clib_error_return (0, "interface not set");
415 u32 pi = pm->policer_index_by_sw_if_index[rx_sw_if_index];
416 policer_read_response_type_st * policer;
417 policer = pool_elt_at_index (pm->policers, pi);
419 vlib_cli_output (vm, "%U", format_policer_instance, policer);
423 if (is_add && config_name == 0)
425 return clib_error_return (0, "policer config name required");
428 rv = test_policer_add_del (rx_sw_if_index, config_name, is_add);
436 return clib_error_return
437 (0, "WARNING: vnet_vnet_policer_add_del returned %d", rv);
443 VLIB_CLI_COMMAND (test_patch_command, static) = {
444 .path = "test policer",
446 "intfc <intfc> policer <policer-config-name> [del]",
447 .function = test_policer_command_fn,
451 #endif /* TEST_CODE */