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.
18 #include <vlib/vlib.h>
19 #include <vnet/vnet.h>
20 #include <vnet/policer/policer.h>
22 /* Dispatch functions meant to be instantiated elsewhere */
28 } vnet_policer_trace_t;
30 /* packet trace format function */
31 static u8 * format_policer_trace (u8 * s, va_list * args)
33 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
34 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
35 vnet_policer_trace_t * t = va_arg (*args, vnet_policer_trace_t *);
37 s = format (s, "VNET_POLICER: sw_if_index %d policer_index %d next %d",
38 t->sw_if_index, t->policer_index, t->next_index);
42 #define foreach_vnet_policer_error \
43 _(TRANSMIT, "Packets Transmitted") \
44 _(DROP, "Packets Dropped")
47 #define _(sym,str) VNET_POLICER_ERROR_##sym,
48 foreach_vnet_policer_error
51 } vnet_policer_error_t;
53 static char * vnet_policer_error_strings[] = {
54 #define _(sym,string) string,
55 foreach_vnet_policer_error
60 uword vnet_policer_inline (vlib_main_t * vm,
61 vlib_node_runtime_t * node,
63 vnet_policer_index_t which)
65 u32 n_left_from, * from, * to_next;
66 vnet_policer_next_t next_index;
67 vnet_policer_main_t * pm = &vnet_policer_main;
68 u64 time_in_policer_periods;
71 time_in_policer_periods =
72 clib_cpu_time_now() >> POLICER_TICKS_PER_PERIOD_SHIFT;
74 from = vlib_frame_vector_args (frame);
75 n_left_from = frame->n_vectors;
76 next_index = node->cached_next_index;
78 while (n_left_from > 0)
82 vlib_get_next_frame (vm, node, next_index,
83 to_next, n_left_to_next);
85 while (n_left_from >= 4 && n_left_to_next >= 2)
88 vlib_buffer_t * b0, * b1;
90 u32 sw_if_index0, sw_if_index1;
94 policer_read_response_type_st * pol0, * pol1;
96 /* Prefetch next iteration. */
98 vlib_buffer_t * b2, * b3;
100 b2 = vlib_get_buffer (vm, from[2]);
101 b3 = vlib_get_buffer (vm, from[3]);
103 vlib_prefetch_buffer_header (b2, LOAD);
104 vlib_prefetch_buffer_header (b3, LOAD);
107 /* speculatively enqueue b0 and b1 to the current next frame */
108 to_next[0] = bi0 = from[0];
109 to_next[1] = bi1 = from[1];
115 b0 = vlib_get_buffer (vm, bi0);
116 b1 = vlib_get_buffer (vm, bi1);
118 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
119 next0 = VNET_POLICER_NEXT_TRANSMIT;
121 sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
122 next1 = VNET_POLICER_NEXT_TRANSMIT;
125 if (which == VNET_POLICER_INDEX_BY_SW_IF_INDEX)
127 pi0 = pm->policer_index_by_sw_if_index[sw_if_index0];
128 pi1 = pm->policer_index_by_sw_if_index[sw_if_index1];
131 if (which == VNET_POLICER_INDEX_BY_OPAQUE)
133 pi0 = vnet_buffer(b0)->policer.index;
134 pi1 = vnet_buffer(b1)->policer.index;
137 if (which == VNET_POLICER_INDEX_BY_EITHER)
139 pi0 = vnet_buffer(b0)->policer.index;
140 pi0 = (pi0 != ~0) ? pi0 :
141 pm->policer_index_by_sw_if_index [sw_if_index0];
142 pi1 = vnet_buffer(b1)->policer.index;
143 pi1 = (pi1 != ~0) ? pi1 :
144 pm->policer_index_by_sw_if_index [sw_if_index1];
147 len0 = vlib_buffer_length_in_chain (vm, b0);
148 pol0 = &pm->policers [pi0];
149 col0 = vnet_police_packet (pol0, len0,
150 POLICE_CONFORM /* no chaining */,
151 time_in_policer_periods);
153 len1 = vlib_buffer_length_in_chain (vm, b1);
154 pol1 = &pm->policers [pi1];
155 col1 = vnet_police_packet (pol1, len1,
156 POLICE_CONFORM /* no chaining */,
157 time_in_policer_periods);
159 if (PREDICT_FALSE(col0 > 0))
161 next0 = VNET_POLICER_NEXT_DROP;
162 b0->error = node->errors[VNET_POLICER_ERROR_DROP];
167 if (PREDICT_FALSE(col1 > 0))
169 next1 = VNET_POLICER_NEXT_DROP;
170 b1->error = node->errors[VNET_POLICER_ERROR_DROP];
176 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)))
178 if (b0->flags & VLIB_BUFFER_IS_TRACED)
180 vnet_policer_trace_t *t =
181 vlib_add_trace (vm, node, b0, sizeof (*t));
182 t->sw_if_index = sw_if_index0;
183 t->next_index = next0;
185 if (b1->flags & VLIB_BUFFER_IS_TRACED)
187 vnet_policer_trace_t *t =
188 vlib_add_trace (vm, node, b1, sizeof (*t));
189 t->sw_if_index = sw_if_index1;
190 t->next_index = next1;
194 /* verify speculative enqueues, maybe switch current next frame */
195 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
196 to_next, n_left_to_next,
197 bi0, bi1, next0, next1);
200 while (n_left_from > 0 && n_left_to_next > 0)
209 policer_read_response_type_st * pol0;
218 b0 = vlib_get_buffer (vm, bi0);
220 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
221 next0 = VNET_POLICER_NEXT_TRANSMIT;
223 if (which == VNET_POLICER_INDEX_BY_SW_IF_INDEX)
224 pi0 = pm->policer_index_by_sw_if_index[sw_if_index0];
226 if (which == VNET_POLICER_INDEX_BY_OPAQUE)
227 pi0 = vnet_buffer(b0)->policer.index;
229 if (which == VNET_POLICER_INDEX_BY_EITHER)
231 pi0 = vnet_buffer(b0)->policer.index;
232 pi0 = (pi0 != ~0) ? pi0 :
233 pm->policer_index_by_sw_if_index [sw_if_index0];
236 len0 = vlib_buffer_length_in_chain (vm, b0);
237 pol0 = &pm->policers [pi0];
238 col0 = vnet_police_packet (pol0, len0,
239 POLICE_CONFORM /* no chaining */,
240 time_in_policer_periods);
242 if (PREDICT_FALSE(col0 > 0))
244 next0 = VNET_POLICER_NEXT_DROP;
245 b0->error = node->errors[VNET_POLICER_ERROR_DROP];
252 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
253 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
255 vnet_policer_trace_t *t =
256 vlib_add_trace (vm, node, b0, sizeof (*t));
257 t->sw_if_index = sw_if_index0;
258 t->next_index = next0;
259 t->policer_index = pi0;
262 /* verify speculative enqueue, maybe switch current next frame */
263 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
264 to_next, n_left_to_next,
268 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
271 vlib_node_increment_counter (vm, node->node_index,
272 VNET_POLICER_ERROR_TRANSMIT,
274 return frame->n_vectors;
277 uword vnet_policer_by_sw_if_index (vlib_main_t * vm,
278 vlib_node_runtime_t * node,
279 vlib_frame_t * frame)
281 return vnet_policer_inline (vm, node, frame,
282 VNET_POLICER_INDEX_BY_SW_IF_INDEX);
285 uword vnet_policer_by_opaque (vlib_main_t * vm,
286 vlib_node_runtime_t * node,
287 vlib_frame_t * frame)
289 return vnet_policer_inline (vm, node, frame,
290 VNET_POLICER_INDEX_BY_OPAQUE);
293 uword vnet_policer_by_either (vlib_main_t * vm,
294 vlib_node_runtime_t * node,
295 vlib_frame_t * frame)
297 return vnet_policer_inline (vm, node, frame,
298 VNET_POLICER_INDEX_BY_EITHER);
301 void vnet_policer_node_funcs_reference (void) { }
308 VLIB_REGISTER_NODE (policer_by_sw_if_index_node, static) = {
309 .function = vnet_policer_by_sw_if_index,
310 .name = "policer-by-sw-if-index",
311 .vector_size = sizeof (u32),
312 .format_trace = format_policer_trace,
313 .type = VLIB_NODE_TYPE_INTERNAL,
315 .n_errors = ARRAY_LEN(vnet_policer_error_strings),
316 .error_strings = vnet_policer_error_strings,
318 .n_next_nodes = VNET_POLICER_N_NEXT,
320 /* edit / add dispositions here */
322 [VNET_POLICER_NEXT_TRANSMIT] = "ethernet-input",
323 [VNET_POLICER_NEXT_DROP] = "error-drop",
328 int test_policer_add_del (u32 rx_sw_if_index, u8 *config_name,
331 vnet_policer_main_t * pm = &vnet_policer_main;
332 policer_read_response_type_st * template;
333 policer_read_response_type_st * policer;
334 vnet_hw_interface_t * rxhi;
337 rxhi = vnet_get_sup_hw_interface (pm->vnet_main, rx_sw_if_index);
339 /* Make sure caller didn't pass a vlan subif, etc. */
340 if (rxhi->sw_if_index != rx_sw_if_index)
341 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
346 p = hash_get_mem (pm->policer_config_by_name, config_name);
351 template = pool_elt_at_index (pm->policer_templates, p[0]);
353 vnet_hw_interface_rx_redirect_to_node
356 policer_by_sw_if_index_node.index);
358 pool_get_aligned (pm->policers, policer, CLIB_CACHE_LINE_BYTES);
360 policer[0] = template[0];
362 vec_validate (pm->policer_index_by_sw_if_index, rx_sw_if_index);
363 pm->policer_index_by_sw_if_index[rx_sw_if_index]
364 = policer - pm->policers;
369 vnet_hw_interface_rx_redirect_to_node (pm->vnet_main,
373 pi = pm->policer_index_by_sw_if_index[rx_sw_if_index];
374 pm->policer_index_by_sw_if_index[rx_sw_if_index] = ~0;
375 pool_put_index (pm->policers, pi);
381 static clib_error_t *
382 test_policer_command_fn (vlib_main_t * vm,
383 unformat_input_t * input,
384 vlib_cli_command_t * cmd)
386 vnet_policer_main_t * pm = &vnet_policer_main;
387 unformat_input_t _line_input, * line_input = &_line_input;
390 u8 * config_name = 0;
395 /* Get a line of input. */
396 if (! unformat_user (input, unformat_line_input, line_input))
399 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
401 if (unformat (line_input, "intfc %U", unformat_vnet_sw_interface,
402 pm->vnet_main, &rx_sw_if_index))
404 else if (unformat (line_input, "show"))
406 else if (unformat (line_input, "policer %s", &config_name))
408 else if (unformat (line_input, "del"))
414 return clib_error_return (0, "interface not set");
418 u32 pi = pm->policer_index_by_sw_if_index[rx_sw_if_index];
419 policer_read_response_type_st * policer;
420 policer = pool_elt_at_index (pm->policers, pi);
422 vlib_cli_output (vm, "%U", format_policer_instance, policer);
426 if (is_add && config_name == 0)
428 return clib_error_return (0, "policer config name required");
431 rv = test_policer_add_del (rx_sw_if_index, config_name, is_add);
439 return clib_error_return
440 (0, "WARNING: vnet_vnet_policer_add_del returned %d", rv);
446 VLIB_CLI_COMMAND (test_patch_command, static) = {
447 .path = "test policer",
449 "intfc <intfc> policer <policer-config-name> [del]",
450 .function = test_policer_command_fn,
454 #endif /* TEST_CODE */