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>
21 #include <vnet/ip/ip.h>
23 #define IP4_NON_DSCP_BITS 0x03
24 #define IP4_DSCP_SHIFT 2
25 #define IP6_NON_DSCP_BITS 0xf03fffff
26 #define IP6_DSCP_SHIFT 22
28 /* Dispatch functions meant to be instantiated elsewhere */
34 } vnet_policer_trace_t;
36 /* packet trace format function */
37 static u8 * format_policer_trace (u8 * s, va_list * args)
39 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
40 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
41 vnet_policer_trace_t * t = va_arg (*args, vnet_policer_trace_t *);
43 s = format (s, "VNET_POLICER: sw_if_index %d policer_index %d next %d",
44 t->sw_if_index, t->policer_index, t->next_index);
48 #define foreach_vnet_policer_error \
49 _(TRANSMIT, "Packets Transmitted") \
50 _(DROP, "Packets Dropped")
53 #define _(sym,str) VNET_POLICER_ERROR_##sym,
54 foreach_vnet_policer_error
57 } vnet_policer_error_t;
59 static char * vnet_policer_error_strings[] = {
60 #define _(sym,string) string,
61 foreach_vnet_policer_error
66 void vnet_policer_mark (vlib_buffer_t * b, u8 dscp)
68 ethernet_header_t * eh;
73 eh = (ethernet_header_t *) b->data;
74 type = clib_net_to_host_u16 (eh->type);
76 if (PREDICT_TRUE(type == ETHERNET_TYPE_IP4))
78 ip4h = (ip4_header_t *) &(b->data[sizeof(ethernet_header_t)]);;
79 ip4h->tos &= IP4_NON_DSCP_BITS;
80 ip4h->tos |= dscp << IP4_DSCP_SHIFT;
81 ip4h->checksum = ip4_header_checksum (ip4h);
85 if (PREDICT_TRUE(type == ETHERNET_TYPE_IP6))
87 ip6h = (ip6_header_t *) &(b->data[sizeof(ethernet_header_t)]);
88 ip6h->ip_version_traffic_class_and_flow_label &=
89 clib_host_to_net_u32(IP6_NON_DSCP_BITS);
90 ip6h->ip_version_traffic_class_and_flow_label |=
91 clib_host_to_net_u32(dscp << IP6_DSCP_SHIFT);
97 uword vnet_policer_inline (vlib_main_t * vm,
98 vlib_node_runtime_t * node,
100 vnet_policer_index_t which)
102 u32 n_left_from, * from, * to_next;
103 vnet_policer_next_t next_index;
104 vnet_policer_main_t * pm = &vnet_policer_main;
105 u64 time_in_policer_periods;
108 time_in_policer_periods =
109 clib_cpu_time_now() >> POLICER_TICKS_PER_PERIOD_SHIFT;
111 from = vlib_frame_vector_args (frame);
112 n_left_from = frame->n_vectors;
113 next_index = node->cached_next_index;
115 while (n_left_from > 0)
119 vlib_get_next_frame (vm, node, next_index,
120 to_next, n_left_to_next);
122 while (n_left_from >= 4 && n_left_to_next >= 2)
125 vlib_buffer_t * b0, * b1;
127 u32 sw_if_index0, sw_if_index1;
128 u32 pi0 = 0, pi1 = 0;
131 policer_read_response_type_st * pol0, * pol1;
134 /* Prefetch next iteration. */
136 vlib_buffer_t * b2, * b3;
138 b2 = vlib_get_buffer (vm, from[2]);
139 b3 = vlib_get_buffer (vm, from[3]);
141 vlib_prefetch_buffer_header (b2, LOAD);
142 vlib_prefetch_buffer_header (b3, LOAD);
145 /* speculatively enqueue b0 and b1 to the current next frame */
146 to_next[0] = bi0 = from[0];
147 to_next[1] = bi1 = from[1];
153 b0 = vlib_get_buffer (vm, bi0);
154 b1 = vlib_get_buffer (vm, bi1);
156 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
157 next0 = VNET_POLICER_NEXT_TRANSMIT;
159 sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
160 next1 = VNET_POLICER_NEXT_TRANSMIT;
163 if (which == VNET_POLICER_INDEX_BY_SW_IF_INDEX)
165 pi0 = pm->policer_index_by_sw_if_index[sw_if_index0];
166 pi1 = pm->policer_index_by_sw_if_index[sw_if_index1];
169 if (which == VNET_POLICER_INDEX_BY_OPAQUE)
171 pi0 = vnet_buffer(b0)->policer.index;
172 pi1 = vnet_buffer(b1)->policer.index;
175 if (which == VNET_POLICER_INDEX_BY_EITHER)
177 pi0 = vnet_buffer(b0)->policer.index;
178 pi0 = (pi0 != ~0) ? pi0 :
179 pm->policer_index_by_sw_if_index [sw_if_index0];
180 pi1 = vnet_buffer(b1)->policer.index;
181 pi1 = (pi1 != ~0) ? pi1 :
182 pm->policer_index_by_sw_if_index [sw_if_index1];
185 len0 = vlib_buffer_length_in_chain (vm, b0);
186 pol0 = &pm->policers [pi0];
187 col0 = vnet_police_packet (pol0, len0,
188 POLICE_CONFORM /* no chaining */,
189 time_in_policer_periods);
190 act0 = pol0->action[col0];
192 len1 = vlib_buffer_length_in_chain (vm, b1);
193 pol1 = &pm->policers [pi1];
194 col1 = vnet_police_packet (pol1, len1,
195 POLICE_CONFORM /* no chaining */,
196 time_in_policer_periods);
197 act1 = pol1->action[col1];
199 if (PREDICT_FALSE(act0 == SSE2_QOS_ACTION_DROP)) /* drop action */
201 next0 = VNET_POLICER_NEXT_DROP;
202 b0->error = node->errors[VNET_POLICER_ERROR_DROP];
204 else /* transmit or mark-and-transmit action */
206 if (PREDICT_TRUE(act0 == SSE2_QOS_ACTION_MARK_AND_TRANSMIT))
207 vnet_policer_mark(b0, pol0->mark_dscp[col0]);
211 if (PREDICT_FALSE(act1 == SSE2_QOS_ACTION_DROP)) /* drop action */
213 next1 = VNET_POLICER_NEXT_DROP;
214 b1->error = node->errors[VNET_POLICER_ERROR_DROP];
216 else /* transmit or mark-and-transmit action */
218 if (PREDICT_TRUE(act1 == SSE2_QOS_ACTION_MARK_AND_TRANSMIT))
219 vnet_policer_mark(b1, pol1->mark_dscp[col1]);
224 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)))
226 if (b0->flags & VLIB_BUFFER_IS_TRACED)
228 vnet_policer_trace_t *t =
229 vlib_add_trace (vm, node, b0, sizeof (*t));
230 t->sw_if_index = sw_if_index0;
231 t->next_index = next0;
233 if (b1->flags & VLIB_BUFFER_IS_TRACED)
235 vnet_policer_trace_t *t =
236 vlib_add_trace (vm, node, b1, sizeof (*t));
237 t->sw_if_index = sw_if_index1;
238 t->next_index = next1;
242 /* verify speculative enqueues, maybe switch current next frame */
243 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
244 to_next, n_left_to_next,
245 bi0, bi1, next0, next1);
248 while (n_left_from > 0 && n_left_to_next > 0)
257 policer_read_response_type_st * pol0;
267 b0 = vlib_get_buffer (vm, bi0);
269 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
270 next0 = VNET_POLICER_NEXT_TRANSMIT;
272 if (which == VNET_POLICER_INDEX_BY_SW_IF_INDEX)
273 pi0 = pm->policer_index_by_sw_if_index[sw_if_index0];
275 if (which == VNET_POLICER_INDEX_BY_OPAQUE)
276 pi0 = vnet_buffer(b0)->policer.index;
278 if (which == VNET_POLICER_INDEX_BY_EITHER)
280 pi0 = vnet_buffer(b0)->policer.index;
281 pi0 = (pi0 != ~0) ? pi0 :
282 pm->policer_index_by_sw_if_index [sw_if_index0];
285 len0 = vlib_buffer_length_in_chain (vm, b0);
286 pol0 = &pm->policers [pi0];
287 col0 = vnet_police_packet (pol0, len0,
288 POLICE_CONFORM /* no chaining */,
289 time_in_policer_periods);
290 act0 = pol0->action[col0];
292 if (PREDICT_FALSE(act0 == SSE2_QOS_ACTION_DROP)) /* drop action */
294 next0 = VNET_POLICER_NEXT_DROP;
295 b0->error = node->errors[VNET_POLICER_ERROR_DROP];
297 else /* transmit or mark-and-transmit action */
299 if (PREDICT_TRUE(act0 == SSE2_QOS_ACTION_MARK_AND_TRANSMIT))
300 vnet_policer_mark(b0, pol0->mark_dscp[col0]);
304 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
305 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
307 vnet_policer_trace_t *t =
308 vlib_add_trace (vm, node, b0, sizeof (*t));
309 t->sw_if_index = sw_if_index0;
310 t->next_index = next0;
311 t->policer_index = pi0;
314 /* verify speculative enqueue, maybe switch current next frame */
315 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
316 to_next, n_left_to_next,
320 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
323 vlib_node_increment_counter (vm, node->node_index,
324 VNET_POLICER_ERROR_TRANSMIT,
326 return frame->n_vectors;
329 uword vnet_policer_by_sw_if_index (vlib_main_t * vm,
330 vlib_node_runtime_t * node,
331 vlib_frame_t * frame)
333 return vnet_policer_inline (vm, node, frame,
334 VNET_POLICER_INDEX_BY_SW_IF_INDEX);
337 uword vnet_policer_by_opaque (vlib_main_t * vm,
338 vlib_node_runtime_t * node,
339 vlib_frame_t * frame)
341 return vnet_policer_inline (vm, node, frame,
342 VNET_POLICER_INDEX_BY_OPAQUE);
345 uword vnet_policer_by_either (vlib_main_t * vm,
346 vlib_node_runtime_t * node,
347 vlib_frame_t * frame)
349 return vnet_policer_inline (vm, node, frame,
350 VNET_POLICER_INDEX_BY_EITHER);
353 void vnet_policer_node_funcs_reference (void) { }
360 VLIB_REGISTER_NODE (policer_by_sw_if_index_node, static) = {
361 .function = vnet_policer_by_sw_if_index,
362 .name = "policer-by-sw-if-index",
363 .vector_size = sizeof (u32),
364 .format_trace = format_policer_trace,
365 .type = VLIB_NODE_TYPE_INTERNAL,
367 .n_errors = ARRAY_LEN(vnet_policer_error_strings),
368 .error_strings = vnet_policer_error_strings,
370 .n_next_nodes = VNET_POLICER_N_NEXT,
372 /* edit / add dispositions here */
374 [VNET_POLICER_NEXT_TRANSMIT] = "ethernet-input",
375 [VNET_POLICER_NEXT_DROP] = "error-drop",
379 VLIB_NODE_FUNCTION_MULTIARCH (policer_by_sw_if_index_node,
380 vnet_policer_by_sw_if_index);
383 int test_policer_add_del (u32 rx_sw_if_index, u8 *config_name,
386 vnet_policer_main_t * pm = &vnet_policer_main;
387 policer_read_response_type_st * template;
388 policer_read_response_type_st * policer;
389 vnet_hw_interface_t * rxhi;
392 rxhi = vnet_get_sup_hw_interface (pm->vnet_main, rx_sw_if_index);
394 /* Make sure caller didn't pass a vlan subif, etc. */
395 if (rxhi->sw_if_index != rx_sw_if_index)
396 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
401 p = hash_get_mem (pm->policer_config_by_name, config_name);
406 template = pool_elt_at_index (pm->policer_templates, p[0]);
408 vnet_hw_interface_rx_redirect_to_node
411 policer_by_sw_if_index_node.index);
413 pool_get_aligned (pm->policers, policer, CLIB_CACHE_LINE_BYTES);
415 policer[0] = template[0];
417 vec_validate (pm->policer_index_by_sw_if_index, rx_sw_if_index);
418 pm->policer_index_by_sw_if_index[rx_sw_if_index]
419 = policer - pm->policers;
424 vnet_hw_interface_rx_redirect_to_node (pm->vnet_main,
428 pi = pm->policer_index_by_sw_if_index[rx_sw_if_index];
429 pm->policer_index_by_sw_if_index[rx_sw_if_index] = ~0;
430 pool_put_index (pm->policers, pi);
436 static clib_error_t *
437 test_policer_command_fn (vlib_main_t * vm,
438 unformat_input_t * input,
439 vlib_cli_command_t * cmd)
441 vnet_policer_main_t * pm = &vnet_policer_main;
442 unformat_input_t _line_input, * line_input = &_line_input;
445 u8 * config_name = 0;
450 /* Get a line of input. */
451 if (! unformat_user (input, unformat_line_input, line_input))
454 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
456 if (unformat (line_input, "intfc %U", unformat_vnet_sw_interface,
457 pm->vnet_main, &rx_sw_if_index))
459 else if (unformat (line_input, "show"))
461 else if (unformat (line_input, "policer %s", &config_name))
463 else if (unformat (line_input, "del"))
469 return clib_error_return (0, "interface not set");
473 u32 pi = pm->policer_index_by_sw_if_index[rx_sw_if_index];
474 policer_read_response_type_st * policer;
475 policer = pool_elt_at_index (pm->policers, pi);
477 vlib_cli_output (vm, "%U", format_policer_instance, policer);
481 if (is_add && config_name == 0)
483 return clib_error_return (0, "policer config name required");
486 rv = test_policer_add_del (rx_sw_if_index, config_name, is_add);
494 return clib_error_return
495 (0, "WARNING: vnet_vnet_policer_add_del returned %d", rv);
501 VLIB_CLI_COMMAND (test_patch_command, static) = {
502 .path = "test policer",
504 "intfc <intfc> policer <policer-config-name> [del]",
505 .function = test_policer_command_fn,
509 #endif /* TEST_CODE */