aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatus Fabian <matfabia@cisco.com>2016-06-20 08:10:42 -0700
committerDave Barach <openvpp@barachs.net>2016-07-26 15:52:03 +0000
commit70e6a8dd52b5c2814737b9a75763ff239a7e053d (patch)
tree403733620fb32f571da1b9bf5be9ce740a9b1054
parentac0798db359eb0de2eae1a54b63dfaa9534984c8 (diff)
policer classify
JIRA: VPP-114 If the classifier finds a matching entry, it sends packet to the policer, packet should be pre-colored for color-aware policers. Change-Id: I10cb53b49907137769418f230df2cab577d0f3a0 Signed-off-by: Matus Fabian <matfabia@cisco.com>
-rw-r--r--vnet/Makefile.am4
-rw-r--r--vnet/vnet/classify/policer_classify.c232
-rw-r--r--vnet/vnet/classify/policer_classify.h55
-rw-r--r--vnet/vnet/classify/vnet_classify.c45
-rw-r--r--vnet/vnet/classify/vnet_classify.h4
-rw-r--r--vnet/vnet/ip/ip4.h1
-rw-r--r--vnet/vnet/ip/ip4_forward.c9
-rw-r--r--vnet/vnet/ip/ip6.h1
-rw-r--r--vnet/vnet/ip/ip6_forward.c8
-rw-r--r--vnet/vnet/ip/ip_init.c3
-rw-r--r--vnet/vnet/l2/l2_input.h3
-rw-r--r--vnet/vnet/policer/node_funcs.c477
-rw-r--r--vnet/vnet/policer/policer.c72
-rw-r--r--vnet/vnet/policer/policer.h7
-rw-r--r--vnet/vnet/policer/xlate.c6
-rw-r--r--vnet/vnet/policer/xlate.h1
-rw-r--r--vpp-api-test/vat/api_format.c210
-rw-r--r--vpp/vpp-api/api.c84
-rw-r--r--vpp/vpp-api/custom_dump.c160
-rw-r--r--vpp/vpp-api/vpe.api56
20 files changed, 1386 insertions, 52 deletions
diff --git a/vnet/Makefile.am b/vnet/Makefile.am
index 47e14b732bb..e9a734743db 100644
--- a/vnet/Makefile.am
+++ b/vnet/Makefile.am
@@ -230,11 +230,13 @@ libvnet_la_SOURCES += \
vnet/classify/vnet_classify.c \
vnet/classify/ip_classify.c \
vnet/classify/input_acl.c \
+ vnet/classify/policer_classify.c \
vnet/classify/vnet_classify.h
nobase_include_HEADERS += \
vnet/classify/vnet_classify.h \
- vnet/classify/input_acl.h
+ vnet/classify/input_acl.h \
+ vnet/classify/policer_classify.h
########################################
# Layer 3 protocols go here
diff --git a/vnet/vnet/classify/policer_classify.c b/vnet/vnet/classify/policer_classify.c
new file mode 100644
index 00000000000..c4c44849e1d
--- /dev/null
+++ b/vnet/vnet/classify/policer_classify.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <vnet/classify/policer_classify.h>
+
+static void
+vnet_policer_classify_feature_enable (vlib_main_t * vnm,
+ policer_classify_main_t * pcm,
+ u32 sw_if_index,
+ policer_classify_table_id_t tid,
+ int feature_enable)
+{
+ if (tid == POLICER_CLASSIFY_TABLE_L2)
+ {
+ l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_POLICER_CLAS,
+ feature_enable);
+ }
+ else
+ {
+ ip_lookup_main_t * lm;
+ ip_config_main_t * ipcm;
+ u32 ftype;
+ u32 ci;
+
+ if (tid == POLICER_CLASSIFY_TABLE_IP4)
+ {
+ lm = &ip4_main.lookup_main;
+ ftype = ip4_main.ip4_unicast_rx_feature_policer_classify;
+ }
+ else
+ {
+ lm = &ip6_main.lookup_main;
+ ftype = ip6_main.ip6_unicast_rx_feature_policer_classify;
+ }
+
+ ipcm = &lm->rx_config_mains[VNET_UNICAST];
+
+ ci = ipcm->config_index_by_sw_if_index[sw_if_index];
+ ci = (feature_enable ? vnet_config_add_feature : vnet_config_del_feature)
+ (vnm, &ipcm->config_main, ci, ftype, 0, 0);
+
+ ipcm->config_index_by_sw_if_index[sw_if_index] = ci;
+ pcm->vnet_config_main[tid] = &ipcm->config_main;
+ }
+}
+
+int vnet_set_policer_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
+ u32 ip4_table_index, u32 ip6_table_index,
+ u32 l2_table_index, u32 is_add)
+{
+ policer_classify_main_t * pcm = &policer_classify_main;
+ vnet_classify_main_t * vcm = pcm->vnet_classify_main;
+ u32 pct[POLICER_CLASSIFY_N_TABLES] = {ip4_table_index, ip6_table_index,
+ l2_table_index};
+ u32 ti;
+
+ /* Assume that we've validated sw_if_index in the API layer */
+
+ for (ti = 0; ti < POLICER_CLASSIFY_N_TABLES; ti++)
+ {
+ if (pct[ti] == ~0)
+ continue;
+
+ if (pool_is_free_index (vcm->tables, pct[ti]))
+ return VNET_API_ERROR_NO_SUCH_TABLE;
+
+ vec_validate_init_empty
+ (pcm->classify_table_index_by_sw_if_index[ti], sw_if_index, ~0);
+
+ /* Reject any DEL operation with wrong sw_if_index */
+ if (!is_add &&
+ (pct[ti] != pcm->classify_table_index_by_sw_if_index[ti][sw_if_index]))
+ {
+ clib_warning ("Non-existent intf_idx=%d with table_index=%d for delete",
+ sw_if_index, pct[ti]);
+ return VNET_API_ERROR_NO_SUCH_TABLE;
+ }
+
+ /* Return ok on ADD operaton if feature is already enabled */
+ if (is_add &&
+ pcm->classify_table_index_by_sw_if_index[ti][sw_if_index] != ~0)
+ return 0;
+
+ vnet_policer_classify_feature_enable (vm, pcm, sw_if_index, ti, is_add);
+
+ if (is_add)
+ pcm->classify_table_index_by_sw_if_index[ti][sw_if_index] = pct[ti];
+ else
+ pcm->classify_table_index_by_sw_if_index[ti][sw_if_index] = ~0;
+ }
+
+
+ return 0;
+}
+
+static clib_error_t *
+set_policer_classify_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ vnet_main_t * vnm = vnet_get_main();
+ u32 sw_if_index = ~0;
+ u32 ip4_table_index = ~0;
+ u32 ip6_table_index = ~0;
+ u32 l2_table_index = ~0;
+ u32 is_add = 1;
+ u32 idx_cnt = 0;
+ int rv;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "interface %U", unformat_vnet_sw_interface,
+ vnm, &sw_if_index))
+ ;
+ else if (unformat (input, "ip4-table %d", &ip4_table_index))
+ idx_cnt++;
+ else if (unformat (input, "ip6-table %d", &ip6_table_index))
+ idx_cnt++;
+ else if (unformat (input, "l2-table %d", &l2_table_index))
+ idx_cnt++;
+ else if (unformat (input, "del"))
+ is_add = 0;
+ else
+ break;
+ }
+
+ if (sw_if_index == ~0)
+ return clib_error_return (0, "Interface must be specified.");
+
+ if (!idx_cnt)
+ return clib_error_return (0, "Table index should be specified.");
+
+ if (idx_cnt > 1)
+ return clib_error_return (0, "Only one table index per API is allowed.");
+
+ rv = vnet_set_policer_classify_intfc(vm, sw_if_index, ip4_table_index,
+ ip6_table_index, l2_table_index, is_add);
+
+ switch (rv)
+ {
+ case 0:
+ break;
+
+ case VNET_API_ERROR_NO_MATCHING_INTERFACE:
+ return clib_error_return (0, "No such interface");
+
+ case VNET_API_ERROR_NO_SUCH_ENTRY:
+ return clib_error_return (0, "No such classifier table");
+ }
+ return 0;
+}
+
+VLIB_CLI_COMMAND (set_input_acl_command, static) = {
+ .path = "set policer classify",
+ .short_help =
+ "set policer classify interface <int> [ip4-table <index>]\n"
+ " [ip6-table <index>] [l2-table <index>] [del]",
+ .function = set_policer_classify_command_fn,
+};
+
+static uword
+unformat_table_type (unformat_input_t * input, va_list * va)
+{
+ u32 * r = va_arg (*va, u32 *);
+ u32 tid;
+
+ if (unformat (input, "ip4"))
+ tid = POLICER_CLASSIFY_TABLE_IP4;
+ else if (unformat (input, "ip6"))
+ tid = POLICER_CLASSIFY_TABLE_IP6;
+ else if (unformat (input, "l2"))
+ tid = POLICER_CLASSIFY_TABLE_L2;
+ else
+ return 0;
+
+ *r = tid;
+ return 1;
+}
+static clib_error_t *
+show_policer_classify_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ policer_classify_main_t * pcm = &policer_classify_main;
+ u32 type = POLICER_CLASSIFY_N_TABLES;
+ u32 * vec_tbl;
+ int i;
+
+ if (unformat (input, "type %U", unformat_table_type, &type))
+ ;
+ else
+ return clib_error_return (0, "Type must be specified.");;
+
+ if (type == POLICER_CLASSIFY_N_TABLES)
+ return clib_error_return (0, "Invalid table type.");
+
+ vec_tbl = pcm->classify_table_index_by_sw_if_index[type];
+
+ if (vec_len(vec_tbl))
+ vlib_cli_output (vm, "%10s%20s\t\t%s", "Intfc idx", "Classify table",
+ "Interface name");
+ else
+ vlib_cli_output (vm, "No tables configured.");
+
+ for (i = 0; i < vec_len (vec_tbl); i++)
+ {
+ if (vec_elt(vec_tbl, i) == ~0)
+ continue;
+
+ vlib_cli_output (vm, "%10d%20d\t\t%U", i, vec_elt(vec_tbl, i),
+ format_vnet_sw_if_index_name, pcm->vnet_main, i);
+ }
+
+ return 0;
+}
+
+VLIB_CLI_COMMAND (show_policer_classify_command, static) = {
+ .path = "show classify policer",
+ .short_help = "show classify policer type [ip4|ip6|l2]",
+ .function = show_policer_classify_command_fn,
+};
diff --git a/vnet/vnet/classify/policer_classify.h b/vnet/vnet/classify/policer_classify.h
new file mode 100644
index 00000000000..3065644438d
--- /dev/null
+++ b/vnet/vnet/classify/policer_classify.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __included_vnet_policer_classify_h__
+#define __included_vnet_policer_classify_h__
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vnet/classify/vnet_classify.h>
+
+typedef enum {
+ POLICER_CLASSIFY_TABLE_IP4,
+ POLICER_CLASSIFY_TABLE_IP6,
+ POLICER_CLASSIFY_TABLE_L2,
+ POLICER_CLASSIFY_N_TABLES,
+} policer_classify_table_id_t;
+
+typedef enum {
+ POLICER_CLASSIFY_NEXT_INDEX_DROP,
+ POLICER_CLASSIFY_NEXT_INDEX_N_NEXT,
+} policer_classify_next_index_t;
+
+typedef struct {
+ /* Classifier table vectors */
+ u32 * classify_table_index_by_sw_if_index [POLICER_CLASSIFY_N_TABLES];
+
+ /* L2 next nodes for each feature */
+ u32 feat_next_node_index[32];
+
+ /* Convenience variables */
+ vlib_main_t * vlib_main;
+ vnet_main_t * vnet_main;
+ vnet_classify_main_t * vnet_classify_main;
+ vnet_config_main_t * vnet_config_main [POLICER_CLASSIFY_N_TABLES];
+} policer_classify_main_t;
+
+policer_classify_main_t policer_classify_main;
+
+int vnet_set_policer_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
+ u32 ip4_table_index, u32 ip6_table_index,
+ u32 l2_table_index, u32 is_add);
+
+#endif /* __included_vnet_policer_classify_h__ */
diff --git a/vnet/vnet/classify/vnet_classify.c b/vnet/vnet/classify/vnet_classify.c
index 11d3714cc73..23aa51592c2 100644
--- a/vnet/vnet/classify/vnet_classify.c
+++ b/vnet/vnet/classify/vnet_classify.c
@@ -88,6 +88,14 @@ vnet_classify_register_unformat_acl_next_index_fn (unformat_function_t * fn)
vec_add1 (cm->unformat_acl_next_index_fns, fn);
}
+void
+vnet_classify_register_unformat_policer_next_index_fn (unformat_function_t * fn)
+{
+ vnet_classify_main_t * cm = &vnet_classify_main;
+
+ vec_add1 (cm->unformat_policer_next_index_fns, fn);
+}
+
void vnet_classify_register_unformat_opaque_index_fn (unformat_function_t * fn)
{
vnet_classify_main_t * cm = &vnet_classify_main;
@@ -1141,6 +1149,37 @@ uword unformat_acl_next_index (unformat_input_t * input, va_list * args)
return 1;
}
+uword unformat_policer_next_index (unformat_input_t * input, va_list * args)
+{
+ u32 * next_indexp = va_arg (*args, u32 *);
+ vnet_classify_main_t * cm = &vnet_classify_main;
+ u32 next_index = 0;
+ u32 tmp;
+ int i;
+
+ /* First try registered unformat fns, allowing override... */
+ for (i = 0; i < vec_len (cm->unformat_policer_next_index_fns); i++)
+ {
+ if (unformat (input, "%U", cm->unformat_policer_next_index_fns[i], &tmp))
+ {
+ next_index = tmp;
+ goto out;
+ }
+ }
+
+ if (unformat (input, "%d", &tmp))
+ {
+ next_index = tmp;
+ goto out;
+ }
+
+ return 0;
+
+ out:
+ *next_indexp = next_index;
+ return 1;
+}
+
static clib_error_t *
classify_table_command_fn (vlib_main_t * vm,
unformat_input_t * input,
@@ -1763,6 +1802,9 @@ classify_session_command_fn (vlib_main_t * vm,
else if (unformat (input, "acl-hit-next %U", unformat_acl_next_index,
&hit_next_index))
;
+ else if (unformat (input, "policer-hit-next %U",
+ unformat_policer_next_index, &hit_next_index))
+ ;
else if (unformat (input, "opaque-index %lld", &opaque_index))
;
else if (unformat (input, "match %U", unformat_classify_match,
@@ -1813,7 +1855,8 @@ classify_session_command_fn (vlib_main_t * vm,
VLIB_CLI_COMMAND (classify_session_command, static) = {
.path = "classify session",
.short_help =
- "classify session [hit-next|l2-hit-next|acl-hit-next <next_index>]"
+ "classify session [hit-next|l2-hit-next|acl-hit-next <next_index>|"
+ "policer-hit-next <policer_name>]"
"\n table-index <nn> match [hex] [l2] [l3 ip4] [opaque-index <index>]",
.function = classify_session_command_fn,
};
diff --git a/vnet/vnet/classify/vnet_classify.h b/vnet/vnet/classify/vnet_classify.h
index b19704ebd0f..f609aaa49d6 100644
--- a/vnet/vnet/classify/vnet_classify.h
+++ b/vnet/vnet/classify/vnet_classify.h
@@ -162,6 +162,7 @@ struct _vnet_classify_main {
unformat_function_t ** unformat_l2_next_index_fns;
unformat_function_t ** unformat_ip_next_index_fns;
unformat_function_t ** unformat_acl_next_index_fns;
+ unformat_function_t ** unformat_policer_next_index_fns;
unformat_function_t ** unformat_opaque_index_fns;
/* convenience variables */
@@ -484,6 +485,9 @@ void vnet_classify_register_unformat_l2_next_index_fn
void vnet_classify_register_unformat_acl_next_index_fn
(unformat_function_t * fn);
+void vnet_classify_register_unformat_policer_next_index_fn
+(unformat_function_t * fn);
+
void vnet_classify_register_unformat_opaque_index_fn (unformat_function_t * fn);
#endif /* __included_vnet_classify_h__ */
diff --git a/vnet/vnet/ip/ip4.h b/vnet/vnet/ip/ip4.h
index 5ea4ebf56ef..fb04893a0f7 100644
--- a/vnet/vnet/ip/ip4.h
+++ b/vnet/vnet/ip/ip4.h
@@ -137,6 +137,7 @@ typedef struct ip4_main_t {
u32 ip4_unicast_rx_feature_check_access;
u32 ip4_unicast_rx_feature_source_reachable_via_rx;
u32 ip4_unicast_rx_feature_source_reachable_via_any;
+ u32 ip4_unicast_rx_feature_policer_classify;
u32 ip4_unicast_rx_feature_ipsec;
u32 ip4_unicast_rx_feature_vpath;
u32 ip4_unicast_rx_feature_lookup;
diff --git a/vnet/vnet/ip/ip4_forward.c b/vnet/vnet/ip/ip4_forward.c
index d2e761fe9ea..2ccdd37cbc2 100644
--- a/vnet/vnet/ip/ip4_forward.c
+++ b/vnet/vnet/ip/ip4_forward.c
@@ -1380,11 +1380,18 @@ VNET_IP4_UNICAST_FEATURE_INIT (ip4_source_check_1, static) = {
VNET_IP4_UNICAST_FEATURE_INIT (ip4_source_check_2, static) = {
.node_name = "ip4-source-check-via-any",
- .runs_before = {"ipsec-input-ip4", 0},
+ .runs_before = {"ip4-policer-classify", 0},
.feature_index =
&ip4_main.ip4_unicast_rx_feature_source_reachable_via_any,
};
+VNET_IP4_UNICAST_FEATURE_INIT (ip4_policer_classify, static) = {
+ .node_name = "ip4-policer-classify",
+ .runs_before = {"ipsec-input-ip4", 0},
+ .feature_index =
+ &ip4_main.ip4_unicast_rx_feature_policer_classify,
+};
+
VNET_IP4_UNICAST_FEATURE_INIT (ip4_ipsec, static) = {
.node_name = "ipsec-input-ip4",
.runs_before = {"vpath-input-ip4", 0},
diff --git a/vnet/vnet/ip/ip6.h b/vnet/vnet/ip/ip6.h
index 22d1a4feaa0..3d6c9f422e8 100644
--- a/vnet/vnet/ip/ip6.h
+++ b/vnet/vnet/ip/ip6.h
@@ -148,6 +148,7 @@ typedef struct ip6_main_t {
/* Built-in unicast feature path indices, see ip_feature_init_cast(...) */
u32 ip6_unicast_rx_feature_check_access;
+ u32 ip6_unicast_rx_feature_policer_classify;
u32 ip6_unicast_rx_feature_ipsec;
u32 ip6_unicast_rx_feature_l2tp_decap;
u32 ip6_unicast_rx_feature_vpath;
diff --git a/vnet/vnet/ip/ip6_forward.c b/vnet/vnet/ip/ip6_forward.c
index 823daa69699..57057a729c1 100644
--- a/vnet/vnet/ip/ip6_forward.c
+++ b/vnet/vnet/ip/ip6_forward.c
@@ -1260,10 +1260,16 @@ VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip6_sw_interface_admin_up_down);
/* Built-in ip6 unicast rx feature path definition */
VNET_IP6_UNICAST_FEATURE_INIT (ip6_inacl, static) = {
.node_name = "ip6-inacl",
- .runs_before = {"ipsec-input-ip6", 0},
+ .runs_before = {"ip6-policer-classify", 0},
.feature_index = &ip6_main.ip6_unicast_rx_feature_check_access,
};
+VNET_IP6_UNICAST_FEATURE_INIT (ip6_policer_classify, static) = {
+ .node_name = "ip6-policer-classify",
+ .runs_before = {"ipsec-input-ip6", 0},
+ .feature_index = &ip6_main.ip6_unicast_rx_feature_policer_classify,
+};
+
VNET_IP6_UNICAST_FEATURE_INIT (ip6_ipsec, static) = {
.node_name = "ipsec-input-ip6",
.runs_before = {"l2tp-decap", 0},
diff --git a/vnet/vnet/ip/ip_init.c b/vnet/vnet/ip/ip_init.c
index 8b6659dedd3..c0c1c9560bc 100644
--- a/vnet/vnet/ip/ip_init.c
+++ b/vnet/vnet/ip/ip_init.c
@@ -133,6 +133,9 @@ do { \
if ((error = vlib_call_init_function (vm, input_acl_init)))
return error;
+ if ((error = vlib_call_init_function (vm, policer_classify_init)))
+ return error;
+
return error;
}
diff --git a/vnet/vnet/l2/l2_input.h b/vnet/vnet/l2/l2_input.h
index 50649e79061..f04075549aa 100644
--- a/vnet/vnet/l2/l2_input.h
+++ b/vnet/vnet/l2/l2_input.h
@@ -109,7 +109,8 @@ l2input_bd_config_from_index (l2input_main_t * l2im, u32 bd_index)
_(ACL, "l2-input-acl") \
_(QOS, "feature-bitmap-drop") \
_(CFM, "feature-bitmap-drop") \
- _(SPAN, "feature-bitmap-drop")
+ _(SPAN, "feature-bitmap-drop") \
+ _(POLICER_CLAS, "l2-policer-classify")
// Feature bitmap positions
typedef enum {
diff --git a/vnet/vnet/policer/node_funcs.c b/vnet/vnet/policer/node_funcs.c
index 6147ea51c1a..0858a86d2a2 100644
--- a/vnet/vnet/policer/node_funcs.c
+++ b/vnet/vnet/policer/node_funcs.c
@@ -19,6 +19,8 @@
#include <vnet/vnet.h>
#include <vnet/policer/policer.h>
#include <vnet/ip/ip.h>
+#include <vnet/classify/policer_classify.h>
+#include <vnet/classify/vnet_classify.h>
#define IP4_NON_DSCP_BITS 0x03
#define IP4_DSCP_SHIFT 2
@@ -93,6 +95,31 @@ void vnet_policer_mark (vlib_buffer_t * b, u8 dscp)
}
}
+static_always_inline
+u8 vnet_policer_police (vlib_main_t * vm,
+ vlib_buffer_t * b,
+ u32 policer_index,
+ u64 time_in_policer_periods,
+ policer_result_e packet_color)
+{
+ u8 act;
+ u32 len;
+ u32 col;
+ policer_read_response_type_st *pol;
+ vnet_policer_main_t * pm = &vnet_policer_main;
+
+ len = vlib_buffer_length_in_chain (vm, b);
+ pol = &pm->policers [policer_index];
+ col = vnet_police_packet (pol, len,
+ packet_color,
+ time_in_policer_periods);
+ act = pol->action[col];
+ if (PREDICT_TRUE(act == SSE2_QOS_ACTION_MARK_AND_TRANSMIT))
+ vnet_policer_mark(b, pol->mark_dscp[col]);
+
+ return act;
+ }
+
static inline
uword vnet_policer_inline (vlib_main_t * vm,
vlib_node_runtime_t * node,
@@ -126,9 +153,6 @@ uword vnet_policer_inline (vlib_main_t * vm,
u32 next0, next1;
u32 sw_if_index0, sw_if_index1;
u32 pi0 = 0, pi1 = 0;
- u32 len0, len1;
- u32 col0, col1;
- policer_read_response_type_st * pol0, * pol1;
u8 act0, act1;
/* Prefetch next iteration. */
@@ -182,19 +206,11 @@ uword vnet_policer_inline (vlib_main_t * vm,
pm->policer_index_by_sw_if_index [sw_if_index1];
}
- len0 = vlib_buffer_length_in_chain (vm, b0);
- pol0 = &pm->policers [pi0];
- col0 = vnet_police_packet (pol0, len0,
- POLICE_CONFORM /* no chaining */,
- time_in_policer_periods);
- act0 = pol0->action[col0];
+ act0 = vnet_policer_police(vm, b0, pi0, time_in_policer_periods,
+ POLICE_CONFORM /* no chaining */);
- len1 = vlib_buffer_length_in_chain (vm, b1);
- pol1 = &pm->policers [pi1];
- col1 = vnet_police_packet (pol1, len1,
- POLICE_CONFORM /* no chaining */,
- time_in_policer_periods);
- act1 = pol1->action[col1];
+ act1 = vnet_policer_police(vm, b1, pi1, time_in_policer_periods,
+ POLICE_CONFORM /* no chaining */);
if (PREDICT_FALSE(act0 == SSE2_QOS_ACTION_DROP)) /* drop action */
{
@@ -203,8 +219,6 @@ uword vnet_policer_inline (vlib_main_t * vm,
}
else /* transmit or mark-and-transmit action */
{
- if (PREDICT_TRUE(act0 == SSE2_QOS_ACTION_MARK_AND_TRANSMIT))
- vnet_policer_mark(b0, pol0->mark_dscp[col0]);
transmitted++;
}
@@ -215,8 +229,6 @@ uword vnet_policer_inline (vlib_main_t * vm,
}
else /* transmit or mark-and-transmit action */
{
- if (PREDICT_TRUE(act1 == SSE2_QOS_ACTION_MARK_AND_TRANSMIT))
- vnet_policer_mark(b1, pol1->mark_dscp[col1]);
transmitted++;
}
@@ -252,9 +264,6 @@ uword vnet_policer_inline (vlib_main_t * vm,
u32 next0;
u32 sw_if_index0;
u32 pi0 = 0;
- u32 len0;
- u32 col0;
- policer_read_response_type_st * pol0;
u8 act0;
bi0 = from[0];
@@ -282,13 +291,9 @@ uword vnet_policer_inline (vlib_main_t * vm,
pm->policer_index_by_sw_if_index [sw_if_index0];
}
- len0 = vlib_buffer_length_in_chain (vm, b0);
- pol0 = &pm->policers [pi0];
- col0 = vnet_police_packet (pol0, len0,
- POLICE_CONFORM /* no chaining */,
- time_in_policer_periods);
- act0 = pol0->action[col0];
-
+ act0 = vnet_policer_police(vm, b0, pi0, time_in_policer_periods,
+ POLICE_CONFORM /* no chaining */);
+
if (PREDICT_FALSE(act0 == SSE2_QOS_ACTION_DROP)) /* drop action */
{
next0 = VNET_POLICER_NEXT_DROP;
@@ -296,8 +301,6 @@ uword vnet_policer_inline (vlib_main_t * vm,
}
else /* transmit or mark-and-transmit action */
{
- if (PREDICT_TRUE(act0 == SSE2_QOS_ACTION_MARK_AND_TRANSMIT))
- vnet_policer_mark(b0, pol0->mark_dscp[col0]);
transmitted++;
}
@@ -507,3 +510,415 @@ VLIB_CLI_COMMAND (test_patch_command, static) = {
#endif /* TEST_CODE */
+
+
+typedef struct {
+ u32 sw_if_index;
+ u32 next_index;
+ u32 table_index;
+ u32 offset;
+ u32 policer_index;
+} policer_classify_trace_t;
+
+static u8 *
+format_policer_classify_trace (u8 * s, va_list * args)
+{
+ CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+ CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+ policer_classify_trace_t * t = va_arg (*args, policer_classify_trace_t *);
+
+ s = format (s, "POLICER_CLASSIFY: sw_if_index %d next %d table %d offset %d"
+ " policer_index %d",
+ t->sw_if_index, t->next_index, t->table_index, t->offset,
+ t->policer_index);
+ return s;
+}
+
+#define foreach_policer_classify_error \
+_(MISS, "Policer classify misses") \
+_(HIT, "Policer classify hits") \
+_(CHAIN_HIT, "Polcier classify hits after chain walk") \
+_(DROP, "Policer classify action drop")
+
+typedef enum {
+#define _(sym,str) POLICER_CLASSIFY_ERROR_##sym,
+ foreach_policer_classify_error
+#undef _
+ POLICER_CLASSIFY_N_ERROR,
+} policer_classify_error_t;
+
+static char * policer_classify_error_strings[] = {
+#define _(sym,string) string,
+ foreach_policer_classify_error
+#undef _
+};
+
+static inline uword
+policer_classify_inline (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame,
+ policer_classify_table_id_t tid)
+{
+ u32 n_left_from, * from, * to_next;
+ policer_classify_next_index_t next_index;
+ policer_classify_main_t * pcm = &policer_classify_main;
+ vnet_classify_main_t * vcm = pcm->vnet_classify_main;
+ f64 now = vlib_time_now (vm);
+ u32 hits = 0;
+ u32 misses = 0;
+ u32 chain_hits = 0;
+ u32 drop = 0;
+ u32 n_next_nodes;
+ u64 time_in_policer_periods;
+
+ time_in_policer_periods =
+ clib_cpu_time_now() >> POLICER_TICKS_PER_PERIOD_SHIFT;
+
+ n_next_nodes = node->n_next_nodes;
+
+ from = vlib_frame_vector_args (frame);
+ n_left_from = frame->n_vectors;
+
+ /* First pass: compute hashes */
+ while (n_left_from > 2)
+ {
+ vlib_buffer_t * b0, * b1;
+ u32 bi0, bi1;
+ u8 * h0, * h1;
+ u32 sw_if_index0, sw_if_index1;
+ u32 table_index0, table_index1;
+ vnet_classify_table_t * t0, * t1;
+
+ /* Prefetch next iteration */
+ {
+ vlib_buffer_t * p1, * p2;
+
+ p1 = vlib_get_buffer (vm, from[1]);
+ p2 = vlib_get_buffer (vm, from[2]);
+
+ vlib_prefetch_buffer_header (p1, STORE);
+ CLIB_PREFETCH (p1->data, CLIB_CACHE_LINE_BYTES, STORE);
+ vlib_prefetch_buffer_header (p2, STORE);
+ CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
+ }
+
+ bi0 = from[0];
+ b0 = vlib_get_buffer (vm, bi0);
+ h0 = b0->data;
+
+ bi1 = from[1];
+ b1 = vlib_get_buffer (vm, bi1);
+ h1 = b1->data;
+
+ sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+ table_index0 = pcm->classify_table_index_by_sw_if_index[tid][sw_if_index0];
+
+ sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
+ table_index1 = pcm->classify_table_index_by_sw_if_index[tid][sw_if_index1];
+
+ t0 = pool_elt_at_index (vcm->tables, table_index0);
+
+ t1 = pool_elt_at_index (vcm->tables, table_index1);
+
+ vnet_buffer(b0)->l2_classify.hash =
+ vnet_classify_hash_packet (t0, (u8 *) h0);
+
+ vnet_classify_prefetch_bucket (t0, vnet_buffer(b0)->l2_classify.hash);
+
+ vnet_buffer(b1)->l2_classify.hash =
+ vnet_classify_hash_packet (t1, (u8 *) h1);
+
+ vnet_classify_prefetch_bucket (t1, vnet_buffer(b1)->l2_classify.hash);
+
+ vnet_buffer(b0)->l2_classify.table_index = table_index0;
+
+ vnet_buffer(b1)->l2_classify.table_index = table_index1;
+
+ from += 2;
+ n_left_from -= 2;
+ }
+
+ while (n_left_from > 0)
+ {
+ vlib_buffer_t * b0;
+ u32 bi0;
+ u8 * h0;
+ u32 sw_if_index0;
+ u32 table_index0;
+ vnet_classify_table_t * t0;
+
+ bi0 = from[0];
+ b0 = vlib_get_buffer (vm, bi0);
+ h0 = b0->data;
+
+ sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+ table_index0 = pcm->classify_table_index_by_sw_if_index[tid][sw_if_index0];
+
+ t0 = pool_elt_at_index (vcm->tables, table_index0);
+ vnet_buffer(b0)->l2_classify.hash =
+ vnet_classify_hash_packet (t0, (u8 *) h0);
+
+ vnet_buffer(b0)->l2_classify.table_index = table_index0;
+ vnet_classify_prefetch_bucket (t0, vnet_buffer(b0)->l2_classify.hash);
+
+ from++;
+ n_left_from--;
+ }
+
+ next_index = node->cached_next_index;
+ from = vlib_frame_vector_args (frame);
+ n_left_from = frame->n_vectors;
+
+ while (n_left_from > 0)
+ {
+ u32 n_left_to_next;
+
+ vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+ /* Not enough load/store slots to dual loop... */
+ while (n_left_from > 0 && n_left_to_next > 0)
+ {
+ u32 bi0;
+ vlib_buffer_t * b0;
+ u32 next0 = POLICER_CLASSIFY_NEXT_INDEX_DROP;
+ u32 table_index0;
+ vnet_classify_table_t * t0;
+ vnet_classify_entry_t * e0;
+ u64 hash0;
+ u8 * h0;
+ u8 act0;
+
+ /* Stride 3 seems to work best */
+ if (PREDICT_TRUE (n_left_from > 3))
+ {
+ vlib_buffer_t * p1 = vlib_get_buffer(vm, from[3]);
+ vnet_classify_table_t * tp1;
+ u32 table_index1;
+ u64 phash1;
+
+ table_index1 = vnet_buffer(p1)->l2_classify.table_index;
+
+ if (PREDICT_TRUE (table_index1 != ~0))
+ {
+ tp1 = pool_elt_at_index (vcm->tables, table_index1);
+ phash1 = vnet_buffer(p1)->l2_classify.hash;
+ vnet_classify_prefetch_entry (tp1, phash1);
+ }
+ }
+
+ /* Speculatively enqueue b0 to the current next frame */
+ bi0 = from[0];
+ to_next[0] = bi0;
+ from += 1;
+ to_next += 1;
+ n_left_from -= 1;
+ n_left_to_next -= 1;
+
+ b0 = vlib_get_buffer (vm, bi0);
+ h0 = b0->data;
+ table_index0 = vnet_buffer(b0)->l2_classify.table_index;
+ e0 = 0;
+ t0 = 0;
+
+ if (tid == POLICER_CLASSIFY_TABLE_L2)
+ {
+ /* Feature bitmap update */
+ vnet_buffer(b0)->l2.feature_bitmap &= ~L2INPUT_FEAT_POLICER_CLAS;
+ /* Determine the next node */
+ next0 = feat_bitmap_get_next_node_index(pcm->feat_next_node_index,
+ vnet_buffer(b0)->l2.feature_bitmap);
+ }
+ else
+ vnet_get_config_data (pcm->vnet_config_main[tid],
+ &b0->current_config_index,
+ &next0,
+ /* # bytes of config data */ 0);
+
+ vnet_buffer(b0)->l2_classify.opaque_index = ~0;
+
+ if (PREDICT_TRUE(table_index0 != ~0))
+ {
+ hash0 = vnet_buffer(b0)->l2_classify.hash;
+ t0 = pool_elt_at_index (vcm->tables, table_index0);
+ e0 = vnet_classify_find_entry (t0, (u8 *) h0, hash0, now);
+
+ if (e0)
+ {
+ act0 = vnet_policer_police(vm,
+ b0,
+ e0->next_index,
+ time_in_policer_periods,
+ e0->opaque_index);
+ if (PREDICT_FALSE(act0 == SSE2_QOS_ACTION_DROP))
+ {
+ next0 = POLICER_CLASSIFY_NEXT_INDEX_DROP;
+ b0->error = node->errors[POLICER_CLASSIFY_ERROR_DROP];
+ drop++;
+ }
+ hits++;
+ }
+ else
+ {
+ while (1)
+ {
+ if (PREDICT_TRUE(t0->next_table_index != ~0))
+ {
+ t0 = pool_elt_at_index (vcm->tables,
+ t0->next_table_index);
+ }
+ else
+ {
+ next0 = (t0->miss_next_index < n_next_nodes)?
+ t0->miss_next_index:next0;
+ misses++;
+ break;
+ }
+
+ hash0 = vnet_classify_hash_packet (t0, (u8 *) h0);
+ e0 = vnet_classify_find_entry (t0, (u8 *) h0, hash0, now);
+ if (e0)
+ {
+ act0 = vnet_policer_police(vm,
+ b0,
+ e0->next_index,
+ time_in_policer_periods,
+ e0->opaque_index);
+ if (PREDICT_FALSE(act0 == SSE2_QOS_ACTION_DROP))
+ {
+ next0 = POLICER_CLASSIFY_NEXT_INDEX_DROP;
+ b0->error = node->errors[POLICER_CLASSIFY_ERROR_DROP];
+ drop++;
+ }
+ hits++;
+ chain_hits++;
+ break;
+ }
+ }
+ }
+ }
+ if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
+ && (b0->flags & VLIB_BUFFER_IS_TRACED)))
+ {
+ policer_classify_trace_t * t =
+ vlib_add_trace (vm, node, b0, sizeof (*t));
+ t->sw_if_index = vnet_buffer(b0)->sw_if_index[VLIB_RX];
+ t->next_index = next0;
+ t->table_index = t0 ? t0 - vcm->tables : ~0;
+ t->offset = e0 ? vnet_classify_get_offset (t0, e0): ~0;
+ t->policer_index = e0 ? e0->next_index: ~0;
+ }
+
+ /* Verify speculative enqueue, maybe switch current next frame */
+ vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
+ n_left_to_next, bi0, next0);
+ }
+
+ vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+ }
+
+ vlib_node_increment_counter (vm, node->node_index,
+ POLICER_CLASSIFY_ERROR_MISS,
+ misses);
+ vlib_node_increment_counter (vm, node->node_index,
+ POLICER_CLASSIFY_ERROR_HIT,
+ hits);
+ vlib_node_increment_counter (vm, node->node_index,
+ POLICER_CLASSIFY_ERROR_CHAIN_HIT,
+ chain_hits);
+ vlib_node_increment_counter (vm, node->node_index,
+ POLICER_CLASSIFY_ERROR_DROP,
+ drop);
+
+ return frame->n_vectors;
+}
+
+static uword
+ip4_policer_classify (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ return policer_classify_inline(vm, node, frame, POLICER_CLASSIFY_TABLE_IP4);
+}
+
+VLIB_REGISTER_NODE (ip4_policer_classify_node) = {
+ .function = ip4_policer_classify,
+ .name = "ip4-policer-classify",
+ .vector_size = sizeof (u32),
+ .format_trace = format_policer_classify_trace,
+ .n_errors = ARRAY_LEN(policer_classify_error_strings),
+ .error_strings = policer_classify_error_strings,
+ .n_next_nodes = POLICER_CLASSIFY_NEXT_INDEX_N_NEXT,
+ .next_nodes = {
+ [POLICER_CLASSIFY_NEXT_INDEX_DROP] = "error-drop",
+ },
+};
+
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_policer_classify_node, ip4_policer_classify);
+
+static uword
+ip6_policer_classify (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ return policer_classify_inline(vm, node, frame, POLICER_CLASSIFY_TABLE_IP6);
+}
+
+VLIB_REGISTER_NODE (ip6_policer_classify_node) = {
+ .function = ip6_policer_classify,
+ .name = "ip6-policer-classify",
+ .vector_size = sizeof (u32),
+ .format_trace = format_policer_classify_trace,
+ .n_errors = ARRAY_LEN(policer_classify_error_strings),
+ .error_strings = policer_classify_error_strings,
+ .n_next_nodes = POLICER_CLASSIFY_NEXT_INDEX_N_NEXT,
+ .next_nodes = {
+ [POLICER_CLASSIFY_NEXT_INDEX_DROP] = "error-drop",
+ },
+};
+
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_policer_classify_node, ip6_policer_classify);
+
+static uword
+l2_policer_classify (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ return policer_classify_inline(vm, node, frame, POLICER_CLASSIFY_TABLE_L2);
+}
+
+VLIB_REGISTER_NODE (l2_policer_classify_node) = {
+ .function = l2_policer_classify,
+ .name = "l2-policer-classify",
+ .vector_size = sizeof (u32),
+ .format_trace = format_policer_classify_trace,
+ .n_errors = ARRAY_LEN(policer_classify_error_strings),
+ .error_strings = policer_classify_error_strings,
+ .n_next_nodes = POLICER_CLASSIFY_NEXT_INDEX_N_NEXT,
+ .next_nodes = {
+ [POLICER_CLASSIFY_NEXT_INDEX_DROP] = "error-drop",
+ },
+};
+
+VLIB_NODE_FUNCTION_MULTIARCH (l2_policer_classify_node, l2_policer_classify);
+
+
+static clib_error_t *
+policer_classify_init (vlib_main_t *vm)
+{
+ policer_classify_main_t * pcm = &policer_classify_main;
+
+ pcm->vlib_main = vm;
+ pcm->vnet_main = vnet_get_main();
+ pcm->vnet_classify_main = &vnet_classify_main;
+
+ /* Initialize L2 feature next-node indexes */
+ feat_bitmap_init_next_nodes(vm,
+ l2_policer_classify_node.index,
+ L2INPUT_N_FEAT,
+ l2input_get_feat_names(),
+ pcm->feat_next_node_index);
+
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (policer_classify_init);
diff --git a/vnet/vnet/policer/policer.c b/vnet/vnet/policer/policer.c
index 8ffa967bd48..f60f7a74ebd 100644
--- a/vnet/vnet/policer/policer.c
+++ b/vnet/vnet/policer/policer.c
@@ -14,30 +14,43 @@
*/
#include <stdint.h>
#include <vnet/policer/policer.h>
+#include <vnet/classify/vnet_classify.h>
clib_error_t *
policer_add_del (vlib_main_t *vm,
- u8 * name, sse2_qos_pol_cfg_params_st * cfg,
+ u8 * name,
+ sse2_qos_pol_cfg_params_st * cfg,
+ u32 * policer_index,
u8 is_add)
{
vnet_policer_main_t *pm = &vnet_policer_main;
policer_read_response_type_st test_policer;
+ policer_read_response_type_st * policer;
uword * p;
+ u32 pi;
int rv;
+ p = hash_get_mem (pm->policer_config_by_name, name);
+
if (is_add == 0)
{
- p = hash_get_mem (pm->policer_config_by_name, name);
if (p == 0)
{
vec_free(name);
return clib_error_return (0, "No such policer configuration");
}
hash_unset_mem (pm->policer_config_by_name, name);
+ hash_unset_mem (pm->policer_index_by_name, name);
vec_free(name);
return 0;
}
+ if (p != 0)
+ {
+ vec_free(name);
+ return clib_error_return (0, "Policer already exists");
+ }
+
/* Vet the configuration before adding it to the table */
rv = sse2_pol_logical_2_physical (cfg, &test_policer);
@@ -55,6 +68,11 @@ policer_add_del (vlib_main_t *vm,
clib_memcpy (pp, &test_policer, sizeof (*pp));
hash_set_mem (pm->policer_config_by_name, name, cp - pm->configs);
+ pool_get_aligned (pm->policers, policer, CLIB_CACHE_LINE_BYTES);
+ policer[0] = pp[0];
+ pi = policer - pm->policers;
+ hash_set_mem (pm->policer_index_by_name, name, pi);
+ *policer_index = pi;
}
else
{
@@ -348,6 +366,44 @@ unformat_policer_action (unformat_input_t * input, va_list * va)
return 0;
}
+static uword
+unformat_policer_classify_next_index (unformat_input_t * input, va_list * va)
+{
+ u32 * r = va_arg (*va, u32 *);
+ vnet_policer_main_t *pm = &vnet_policer_main;
+ uword * p;
+ u8 * match_name = 0;
+
+ if (unformat (input, "%s", &match_name))
+ ;
+ else
+ return 0;
+
+ p = hash_get_mem (pm->policer_index_by_name, match_name);
+
+ if (p == 0)
+ return 0;
+
+ *r = p[0];
+
+ return 1;
+}
+
+static uword
+unformat_policer_classify_precolor (unformat_input_t * input, va_list * va)
+{
+ u32 * r = va_arg (*va, u32 *);
+
+ if (unformat (input, "conform-color"))
+ *r = POLICE_CONFORM;
+ else if (unformat (input, "exceed-color"))
+ *r = POLICE_EXCEED;
+ else
+ return 0;
+
+ return 1;
+}
+
#define foreach_config_param \
_(eb) \
_(cb) \
@@ -367,6 +423,7 @@ configure_policer_command_fn (vlib_main_t * vm,
unformat_input_t _line_input, * line_input = &_line_input;
u8 is_add = 1;
u8 * name = 0;
+ u32 pi;
/* Get a line of input. */
if (! unformat_user (input, unformat_line_input, line_input))
@@ -380,6 +437,8 @@ configure_policer_command_fn (vlib_main_t * vm,
is_add = 0;
else if (unformat(line_input, "name %s", &name))
;
+ else if (unformat(line_input, "color-aware"))
+ c.color_aware = 1;
#define _(a) else if (unformat (line_input, "%U", unformat_policer_##a, &c)) ;
foreach_config_param
@@ -392,7 +451,7 @@ configure_policer_command_fn (vlib_main_t * vm,
unformat_free (line_input);
- return policer_add_del(vm, name, &c, is_add);
+ return policer_add_del(vm, name, &c, &pi, is_add);
}
VLIB_CLI_COMMAND (configure_policer_command, static) = {
@@ -453,6 +512,13 @@ clib_error_t *policer_init (vlib_main_t * vm)
pm->vnet_main = vnet_get_main();
pm->policer_config_by_name = hash_create_string (0, sizeof (uword));
+ pm->policer_index_by_name = hash_create_string (0, sizeof (uword));
+
+ vnet_classify_register_unformat_policer_next_index_fn
+ (unformat_policer_classify_next_index);
+ vnet_classify_register_unformat_opaque_index_fn
+ (unformat_policer_classify_precolor);
+
return 0;
}
diff --git a/vnet/vnet/policer/policer.h b/vnet/vnet/policer/policer.h
index fba866f4773..beef5b644dc 100644
--- a/vnet/vnet/policer/policer.h
+++ b/vnet/vnet/policer/policer.h
@@ -32,6 +32,9 @@ typedef struct {
/* Config by name hash */
uword * policer_config_by_name;
+ /* Policer by name hash */
+ uword * policer_index_by_name;
+
/* Policer by sw_if_index vector */
u32 * policer_index_by_sw_if_index;
@@ -85,7 +88,9 @@ typedef enum {
u8 * format_policer_instance (u8 * s, va_list * va);
clib_error_t * policer_add_del (vlib_main_t *vm,
- u8 * name, sse2_qos_pol_cfg_params_st * cfg,
+ u8 * name,
+ sse2_qos_pol_cfg_params_st * cfg,
+ u32 * policer_index,
u8 is_add);
#endif /* __included_policer_h__ */
diff --git a/vnet/vnet/policer/xlate.c b/vnet/vnet/policer/xlate.c
index f47982e31ee..934c488ccb8 100644
--- a/vnet/vnet/policer/xlate.c
+++ b/vnet/vnet/policer/xlate.c
@@ -1045,10 +1045,6 @@ x86_pol_compute_hw_params (sse2_qos_pol_cfg_params_st *cfg,
(cfg->rfc == SSE2_QOS_POLICER_TYPE_2R3C_RFC_4115)) {
// Two-rate policer
- if (cfg->rfc == SSE2_QOS_POLICER_TYPE_2R3C_RFC_4115) {
- hw->color_aware = 1;
- }
-
if ((cfg->rb.kbps.cir_kbps == 0) || (cfg->rb.kbps.eir_kbps == 0) || (cfg->rb.kbps.eir_kbps < cfg->rb.kbps.cir_kbps) ||
(cfg->rb.kbps.cb_bytes == 0) || (cfg->rb.kbps.eb_bytes == 0)) {
SSE2_QOS_DEBUG_ERROR("Config parameter validation failed.");
@@ -1136,6 +1132,8 @@ sse2_pol_logical_2_physical (sse2_qos_pol_cfg_params_st *cfg,
phys->action[POLICE_VIOLATE] = cfg->violate_action.action_type;
phys->mark_dscp[POLICE_VIOLATE] = cfg->violate_action.dscp;
+ phys->color_aware = cfg->color_aware;
+
#if !defined (INTERNAL_SS) && !defined (X86)
// convert logical into hw params which involves qos calculations
rc = sse2_pol_compute_hw_params(&kbps_cfg, &pol_hw);
diff --git a/vnet/vnet/policer/xlate.h b/vnet/vnet/policer/xlate.h
index d3fdeded55f..69a58d25efb 100644
--- a/vnet/vnet/policer/xlate.h
+++ b/vnet/vnet/policer/xlate.h
@@ -136,6 +136,7 @@ typedef struct sse2_qos_pol_cfg_params_st_ {
uint8_t rate_type; /* sse2_qos_rate_type_en */
uint8_t rnd_type; /* sse2_qos_round_type_en */
uint8_t rfc; /* sse2_qos_policer_type_en */
+ uint8_t color_aware;
uint8_t overwrite_bucket; /* for debugging purposes */
uint32_t current_bucket; /* for debugging purposes */
uint32_t extended_bucket; /* for debugging purposes */
diff --git a/vpp-api-test/vat/api_format.c b/vpp-api-test/vat/api_format.c
index fa37989c3ad..dac6788972c 100644
--- a/vpp-api-test/vat/api_format.c
+++ b/vpp-api-test/vat/api_format.c
@@ -34,6 +34,7 @@
#include <vnet/l2/l2_classify.h>
#include <vnet/l2/l2_vtr.h>
#include <vnet/classify/input_acl.h>
+#include <vnet/classify/policer_classify.h>
#include <vnet/mpls-gre/mpls.h>
#if DPDK > 0
#include <vnet/ipsec/ipsec.h>
@@ -46,6 +47,7 @@
#include <vnet/ip/ip6_hop_by_hop.h>
#include <vnet/policer/xlate.h>
#include <vnet/policer/policer.h>
+#include <vnet/policer/police.h>
#include "vat/json_format.h"
@@ -450,6 +452,25 @@ unformat_policer_action_type (unformat_input_t * input, va_list * va)
return 1;
}
+uword
+unformat_classify_table_type (unformat_input_t * input, va_list * va)
+{
+ u32 * r = va_arg (*va, u32 *);
+ u32 tid;
+
+ if (unformat (input, "ip4"))
+ tid = POLICER_CLASSIFY_TABLE_IP4;
+ else if (unformat (input, "ip6"))
+ tid = POLICER_CLASSIFY_TABLE_IP6;
+ else if (unformat (input, "l2"))
+ tid = POLICER_CLASSIFY_TABLE_L2;
+ else
+ return 0;
+
+ *r = tid;
+ return 1;
+}
+
u8 * format_ip4_address (u8 * s, va_list * args)
{
u8 * a = va_arg (*args, u8 *);
@@ -2513,8 +2534,8 @@ static void vl_api_policer_details_t_handler
format_policer_type, mp->type,
ntohl(mp->cir),
ntohl(mp->eir),
- ntohl(mp->cb),
- ntohl(mp->eb),
+ clib_net_to_host_u64(mp->cb),
+ clib_net_to_host_u64(mp->eb),
format_policer_rate_type, mp->rate_type,
format_policer_round_type, mp->round_type,
mp->single_rate ? "single" : "dual",
@@ -2691,6 +2712,42 @@ static void vl_api_classify_table_by_interface_reply_t_handler_json (vl_api_clas
vam->result_ready = 1;
}
+static void vl_api_policer_add_del_reply_t_handler
+(vl_api_policer_add_del_reply_t * mp)
+{
+ vat_main_t * vam = &vat_main;
+ i32 retval = ntohl(mp->retval);
+ if (vam->async_mode) {
+ vam->async_errors += (retval < 0);
+ } else {
+ vam->retval = retval;
+ vam->result_ready = 1;
+ if (retval == 0 && mp->policer_index != 0xFFFFFFFF)
+ /*
+ * Note: this is just barely thread-safe, depends on
+ * the main thread spinning waiting for an answer...
+ */
+ errmsg ("policer index %d\n", ntohl(mp->policer_index));
+ }
+}
+
+static void vl_api_policer_add_del_reply_t_handler_json
+(vl_api_policer_add_del_reply_t * mp)
+{
+ vat_main_t * vam = &vat_main;
+ vat_json_node_t node;
+
+ vat_json_init_object(&node);
+ vat_json_object_add_int(&node, "retval", ntohl(mp->retval));
+ vat_json_object_add_uint(&node, "policer_index", ntohl(mp->policer_index));
+
+ vat_json_print(vam->ofp, &node);
+ vat_json_free(&node);
+
+ vam->retval = ntohl(mp->retval);
+ vam->result_ready = 1;
+}
+
/* Format hex dump. */
u8 * format_hex_bytes (u8 * s, va_list * va)
{
@@ -2811,6 +2868,33 @@ static void vl_api_pg_create_interface_reply_t_handler_json
vam->result_ready = 1;
}
+static void vl_api_policer_classify_details_t_handler
+(vl_api_policer_classify_details_t * mp)
+{
+ vat_main_t * vam = &vat_main;
+
+ fformat (vam->ofp, "%10d%20d\n", ntohl(mp->sw_if_index),
+ ntohl(mp->table_index));
+}
+
+static void vl_api_policer_classify_details_t_handler_json
+(vl_api_policer_classify_details_t * mp)
+{
+ vat_main_t * vam = &vat_main;
+ vat_json_node_t * node;
+
+ if (VAT_JSON_ARRAY != vam->json_tree.type) {
+ ASSERT(VAT_JSON_NONE == vam->json_tree.type);
+ vat_json_init_array(&vam->json_tree);
+ }
+ node = vat_json_array_add(&vam->json_tree);
+
+ vat_json_init_object(node);
+ vat_json_object_add_uint(node, "sw_if_index", ntohl(mp->sw_if_index));
+ vat_json_object_add_uint(node, "table_index", ntohl(mp->table_index));
+}
+
+
#define vl_api_vnet_ip4_fib_counters_t_endian vl_noop_handler
#define vl_api_vnet_ip4_fib_counters_t_print vl_noop_handler
#define vl_api_vnet_ip6_fib_counters_t_endian vl_noop_handler
@@ -2909,7 +2993,7 @@ _(lisp_add_del_map_request_itr_rlocs_reply) \
_(lisp_eid_table_add_del_map_reply) \
_(vxlan_gpe_add_del_tunnel_reply) \
_(af_packet_delete_reply) \
-_(policer_add_del_reply) \
+_(policer_classify_set_interface_reply) \
_(netmap_create_reply) \
_(netmap_delete_reply) \
_(ipfix_enable_reply) \
@@ -3108,6 +3192,8 @@ _(AF_PACKET_CREATE_REPLY, af_packet_create_reply) \
_(AF_PACKET_DELETE_REPLY, af_packet_delete_reply) \
_(POLICER_ADD_DEL_REPLY, policer_add_del_reply) \
_(POLICER_DETAILS, policer_details) \
+_(POLICER_CLASSIFY_SET_INTERFACE_REPLY, policer_classify_set_interface_reply) \
+_(POLICER_CLASSIFY_DETAILS, policer_classify_details) \
_(NETMAP_CREATE_REPLY, netmap_create_reply) \
_(NETMAP_DELETE_REPLY, netmap_delete_reply) \
_(MPLS_GRE_TUNNEL_DETAILS, mpls_gre_tunnel_details) \
@@ -7060,6 +7146,20 @@ uword unformat_acl_next_index (unformat_input_t * input, va_list * args)
return 1;
}
+uword unformat_policer_precolor (unformat_input_t * input, va_list * args)
+{
+ u32 * r = va_arg (*args, u32 *);
+
+ if (unformat (input, "conform-color"))
+ *r = POLICE_CONFORM;
+ else if (unformat (input, "exceed-color"))
+ *r = POLICE_EXCEED;
+ else
+ return 0;
+
+ return 1;
+}
+
static int api_classify_add_del_table (vat_main_t * vam)
{
unformat_input_t * i = vam->input;
@@ -7553,6 +7653,10 @@ static int api_classify_add_del_session (vat_main_t * vam)
else if (unformat (i, "acl-hit-next %U", unformat_acl_next_index,
&hit_next_index))
;
+ else if (unformat (i, "policer-hit-next %d", &hit_next_index))
+ ;
+ else if (unformat (i, "%U", unformat_policer_precolor, &opaque_index))
+ ;
else if (unformat (i, "opaque-index %d", &opaque_index))
;
else if (unformat (i, "skip_n %d", &skip_n_vectors))
@@ -11705,6 +11809,7 @@ api_policer_add_del (vat_main_t * vam)
u8 rate_type = 0;
u8 round_type = 0;
u8 type = 0;
+ u8 color_aware = 0;
sse2_qos_pol_action_params_st conform_action, exceed_action, violate_action;
while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) {
@@ -11737,6 +11842,8 @@ api_policer_add_del (vat_main_t * vam)
else if (unformat (i, "violate_action %U", unformat_policer_action_type,
&violate_action))
;
+ else if (unformat (i, "color-aware"))
+ color_aware = 1;
else
break;
}
@@ -11769,6 +11876,7 @@ api_policer_add_del (vat_main_t * vam)
mp->exceed_dscp = exceed_action.dscp;
mp->violate_action_type = violate_action.action_type;
mp->violate_dscp = violate_action.dscp;
+ mp->color_aware = color_aware;
S; W;
/* NOTREACHED */
@@ -11813,6 +11921,93 @@ api_policer_dump(vat_main_t *vam)
}
static int
+api_policer_classify_set_interface (vat_main_t * vam)
+{
+ unformat_input_t * i = vam->input;
+ vl_api_policer_classify_set_interface_t *mp;
+ f64 timeout;
+ u32 sw_if_index;
+ int sw_if_index_set;
+ u32 ip4_table_index = ~0;
+ u32 ip6_table_index = ~0;
+ u32 l2_table_index = ~0;
+ u8 is_add = 1;
+
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) {
+ if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
+ sw_if_index_set = 1;
+ else if (unformat (i, "sw_if_index %d", &sw_if_index))
+ sw_if_index_set = 1;
+ else if (unformat (i, "del"))
+ is_add = 0;
+ else if (unformat (i, "ip4-table %d", &ip4_table_index))
+ ;
+ else if (unformat (i, "ip6-table %d", &ip6_table_index))
+ ;
+ else if (unformat (i, "l2-table %d", &l2_table_index))
+ ;
+ else {
+ clib_warning ("parse error '%U'", format_unformat_error, i);
+ return -99;
+ }
+ }
+
+ if (sw_if_index_set == 0) {
+ errmsg ("missing interface name or sw_if_index\n");
+ return -99;
+ }
+
+ M(POLICER_CLASSIFY_SET_INTERFACE, policer_classify_set_interface);
+
+ mp->sw_if_index = ntohl(sw_if_index);
+ mp->ip4_table_index = ntohl(ip4_table_index);
+ mp->ip6_table_index = ntohl(ip6_table_index);
+ mp->l2_table_index = ntohl(l2_table_index);
+ mp->is_add = is_add;
+
+ S; W;
+ /* NOTREACHED */
+ return 0;
+}
+
+static int
+api_policer_classify_dump(vat_main_t *vam)
+{
+ unformat_input_t * i = vam->input;
+ vl_api_policer_classify_dump_t *mp;
+ f64 timeout = ~0;
+ u8 type = POLICER_CLASSIFY_N_TABLES;
+
+ if (unformat (i, "type %U", unformat_classify_table_type, &type))
+ ;
+ else {
+ errmsg ("classify table type must be specified\n");
+ return -99;
+ }
+
+ if (!vam->json_output) {
+ fformat(vam->ofp, "%10s%20s\n", "Intfc idx", "Classify table");
+ }
+
+ M(POLICER_CLASSIFY_DUMP, policer_classify_dump);
+ mp->type = type;
+ /* send it... */
+ S;
+
+ /* Use a control ping for synchronization */
+ {
+ vl_api_control_ping_t * mp;
+ M(CONTROL_PING, control_ping);
+ S;
+ }
+ /* Wait for a reply... */
+ W;
+
+ /* NOTREACHED */
+ return 0;
+}
+
+static int
api_netmap_create (vat_main_t * vam)
{
unformat_input_t * i = vam->input;
@@ -12849,8 +13044,9 @@ _(classify_add_del_table, \
"[del] mask <mask-value>\n" \
" [l2-miss-next | miss-next | acl-miss-next] <name|nn>") \
_(classify_add_del_session, \
- "[hit-next|l2-hit-next|acl-hit-next] <name|nn> table-index <nn>\n" \
- "skip_n <nn> match_n <nn> match [hex] [l2] [l3 [ip4|ip6]]") \
+ "[hit-next|l2-hit-next|acl-hit-next|policer-hit-next] <name|nn>\n" \
+ " table-index <nn> skip_n <nn> match_n <nn> match [hex] [l2]\n" \
+ " [l3 [ip4|ip6]]") \
_(classify_set_interface_ip_table, \
"<intfc> | sw_if_index <nn> table <nn>") \
_(classify_set_interface_l2_tables, \
@@ -12985,6 +13181,10 @@ _(af_packet_create, "name <host interface name> [hw_addr <mac>]") \
_(af_packet_delete, "name <host interface name>") \
_(policer_add_del, "name <policer name> <params> [del]") \
_(policer_dump, "[name <policer name>]") \
+_(policer_classify_set_interface, \
+ "<intfc> | sw_if_index <nn> [ip4-table <nn>] [ip6-table <nn>]\n" \
+ " [l2-table <nn>] [del]") \
+_(policer_classify_dump, "type [ip4|ip6|l2]") \
_(netmap_create, "name <interface name> [hw-addr <mac>] [pipe] " \
"[master|slave]") \
_(netmap_delete, "name <interface name>") \
diff --git a/vpp/vpp-api/api.c b/vpp/vpp-api/api.c
index feb1a61a5b0..822b9906c15 100644
--- a/vpp/vpp-api/api.c
+++ b/vpp/vpp-api/api.c
@@ -66,6 +66,7 @@
#include <vlibmemory/api.h>
#include <vnet/classify/vnet_classify.h>
#include <vnet/classify/input_acl.h>
+#include <vnet/classify/policer_classify.h>
#include <vnet/l2/l2_classify.h>
#include <vnet/vxlan/vxlan.h>
#include <vnet/gre/gre.h>
@@ -353,6 +354,8 @@ _(AF_PACKET_CREATE, af_packet_create) \
_(AF_PACKET_DELETE, af_packet_delete) \
_(POLICER_ADD_DEL, policer_add_del) \
_(POLICER_DUMP, policer_dump) \
+_(POLICER_CLASSIFY_SET_INTERFACE, policer_classify_set_interface) \
+_(POLICER_CLASSIFY_DUMP, policer_classify_dump) \
_(NETMAP_CREATE, netmap_create) \
_(NETMAP_DELETE, netmap_delete) \
_(MPLS_GRE_TUNNEL_DUMP, mpls_gre_tunnel_dump) \
@@ -6435,6 +6438,7 @@ vl_api_policer_add_del_t_handler
u8 *name = NULL;
sse2_qos_pol_cfg_params_st cfg;
clib_error_t * error;
+ u32 policer_index;
name = format(0, "%s", mp->name);
@@ -6452,13 +6456,20 @@ vl_api_policer_add_del_t_handler
cfg.exceed_action.dscp = mp->exceed_dscp;
cfg.violate_action.action_type = mp->violate_action_type;
cfg.violate_action.dscp = mp->violate_dscp;
+ cfg.color_aware = mp->color_aware;
- error = policer_add_del(vm, name, &cfg, mp->is_add);
+ error = policer_add_del(vm, name, &cfg, &policer_index, mp->is_add);
if (error)
rv = VNET_API_ERROR_UNSPECIFIED;
- REPLY_MACRO(VL_API_POLICER_ADD_DEL_REPLY);
+ REPLY_MACRO2(VL_API_POLICER_ADD_DEL_REPLY,
+ ({
+ if (rv == 0 && mp->is_add)
+ rmp->policer_index = ntohl(policer_index);
+ else
+ rmp->policer_index = ~0;
+ }));
}
static void
@@ -6546,6 +6557,75 @@ vl_api_policer_dump_t_handler
}
static void
+vl_api_policer_classify_set_interface_t_handler
+(vl_api_policer_classify_set_interface_t * mp)
+{
+ vlib_main_t *vm = vlib_get_main();
+ vl_api_policer_classify_set_interface_reply_t * rmp;
+ int rv;
+ u32 sw_if_index, ip4_table_index, ip6_table_index, l2_table_index;
+
+ ip4_table_index = ntohl(mp->ip4_table_index);
+ ip6_table_index = ntohl(mp->ip6_table_index);
+ l2_table_index = ntohl(mp->l2_table_index);
+ sw_if_index = ntohl(mp->sw_if_index);
+
+ VALIDATE_SW_IF_INDEX(mp);
+
+ rv = vnet_set_policer_classify_intfc(vm, sw_if_index, ip4_table_index,
+ ip6_table_index, l2_table_index,
+ mp->is_add);
+
+ BAD_SW_IF_INDEX_LABEL;
+
+ REPLY_MACRO(VL_API_POLICER_CLASSIFY_SET_INTERFACE_REPLY);
+}
+
+static void
+send_policer_classify_details (u32 sw_if_index,
+ u32 table_index,
+ unix_shared_memory_queue_t *q,
+ u32 context)
+{
+ vl_api_policer_classify_details_t * mp;
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_POLICER_CLASSIFY_DETAILS);
+ mp->context = context;
+ mp->sw_if_index= htonl(sw_if_index);
+ mp->table_index= htonl(table_index);
+
+ vl_msg_api_send_shmem (q, (u8 *)&mp);
+}
+
+static void
+vl_api_policer_classify_dump_t_handler
+(vl_api_policer_classify_dump_t *mp)
+{
+ unix_shared_memory_queue_t * q;
+ policer_classify_main_t * pcm = &policer_classify_main;
+ u32 * vec_tbl;
+ int i;
+
+ q = vl_api_client_index_to_input_queue (mp->client_index);
+ if (q == 0)
+ return;
+
+ vec_tbl = pcm->classify_table_index_by_sw_if_index[mp->type];
+
+ if (vec_len(vec_tbl)) {
+ for (i = 0; i < vec_len (vec_tbl); i++) {
+ if (vec_elt(vec_tbl, i) == ~0)
+ continue;
+
+ send_policer_classify_details(i, vec_elt(vec_tbl, i), q,
+ mp->context);
+ }
+ }
+}
+
+static void
vl_api_netmap_create_t_handler
(vl_api_netmap_create_t *mp)
{
diff --git a/vpp/vpp-api/custom_dump.c b/vpp/vpp-api/custom_dump.c
index 53eb2c4dac5..651fdd35446 100644
--- a/vpp/vpp-api/custom_dump.c
+++ b/vpp/vpp-api/custom_dump.c
@@ -27,6 +27,9 @@
#include <vnet/l2/l2_input.h>
#include <vnet/sr/sr_packet.h>
#include <vnet/vxlan-gpe/vxlan_gpe.h>
+#include <vnet/classify/policer_classify.h>
+#include <vnet/policer/xlate.h>
+#include <vnet/policer/policer.h>
#include <vlib/vlib.h>
#include <vlib/unix/unix.h>
#include <vlibapi/api.h>
@@ -1746,6 +1749,157 @@ static void * vl_api_af_packet_delete_t_print
FINISH;
}
+static u8 * format_policer_action (u8 * s, va_list * va)
+{
+ u32 action = va_arg (*va, u32);
+ u32 dscp = va_arg (*va, u32);
+ char * t = 0;
+
+ if (action == SSE2_QOS_ACTION_DROP)
+ s = format (s, "drop");
+ else if (action == SSE2_QOS_ACTION_TRANSMIT)
+ s = format (s, "transmit");
+ else if (action == SSE2_QOS_ACTION_MARK_AND_TRANSMIT) {
+ s = format (s, "mark-and-transmit ");
+ switch (dscp) {
+ #define _(v,f,str) case VNET_DSCP_##f: t = str; break;
+ foreach_vnet_dscp
+ #undef _
+ default:
+ break;
+ }
+ s = format (s, "%s", t);
+ }
+
+ return s;
+}
+
+static void * vl_api_policer_add_del_t_print
+(vl_api_policer_add_del_t * mp, void *handle)
+{
+ u8 * s;
+
+ s = format (0, "SCRIPT: policer_add_del ");
+ s = format (s, "name %s ", mp->name);
+ s = format (s, "cir %d ", mp->cir);
+ s = format (s, "eir %d ", mp->eir);
+ s = format (s, "cb %d ", mp->cb);
+ s = format (s, "eb %d ", mp->eb);
+
+ switch (mp->rate_type) {
+ case SSE2_QOS_RATE_KBPS:
+ s = format (s, "rate_type kbps ");
+ break;
+ case SSE2_QOS_RATE_PPS:
+ s = format (s, "rate_type pps ");
+ break;
+ default:
+ break;
+ }
+
+ switch (mp->round_type) {
+ case SSE2_QOS_ROUND_TO_CLOSEST:
+ s = format (s, "round_type closest ");
+ break;
+ case SSE2_QOS_ROUND_TO_UP:
+ s = format (s, "round_type up ");
+ break;
+ case SSE2_QOS_ROUND_TO_DOWN:
+ s = format (s, "round_type down ");
+ break;
+ default:
+ break;
+ }
+
+ switch (mp->type) {
+ case SSE2_QOS_POLICER_TYPE_1R2C:
+ s = format (s, "type 1r2c ");
+ break;
+ case SSE2_QOS_POLICER_TYPE_1R3C_RFC_2697:
+ s = format (s, "type 1r3c ");
+ break;
+ case SSE2_QOS_POLICER_TYPE_2R3C_RFC_2698:
+ s = format (s, "type 2r3c-2698 ");
+ break;
+ case SSE2_QOS_POLICER_TYPE_2R3C_RFC_4115:
+ s = format (s, "type 2r3c-4115 ");
+ break;
+ case SSE2_QOS_POLICER_TYPE_2R3C_RFC_MEF5CF1:
+ s = format (s, "type 2r3c-mef5cf1 ");
+ break;
+ default:
+ break;
+ }
+
+ s = format (s, "conform_action %U ", format_policer_action,
+ mp->conform_action_type, mp->conform_dscp);
+ s = format (s, "exceed_action %U ", format_policer_action,
+ mp->exceed_action_type, mp->exceed_dscp);
+ s = format (s, "violate_action %U ", format_policer_action,
+ mp->violate_action_type, mp->violate_dscp);
+
+ if (mp->color_aware)
+ s = format (s, "color-aware ");
+ if (mp->is_add == 0)
+ s = format (s, "del ");
+
+ FINISH;
+}
+
+static void * vl_api_policer_dump_t_print
+(vl_api_policer_dump_t * mp, void *handle)
+{
+ u8 * s;
+
+ s = format (0, "SCRIPT: policer_dump ");
+ if (mp->match_name_valid)
+ s = format (s, "name %s ", mp->match_name);
+
+ FINISH;
+}
+
+static void * vl_api_policer_classify_set_interface_t_print
+(vl_api_policer_classify_set_interface_t * mp, void *handle)
+{
+ u8 * s;
+
+ s = format (0, "SCRIPT: policer_classify_set_interface ");
+ s = format (s, "sw_if_index %d ", ntohl(mp->sw_if_index));
+ if (mp->ip4_table_index != ~0)
+ s = format (s, "ip4-table %d ", ntohl(mp->ip4_table_index));
+ if (mp->ip6_table_index != ~0)
+ s = format (s, "ip6-table %d ", ntohl(mp->ip6_table_index));
+ if (mp->l2_table_index != ~0)
+ s = format (s, "l2-table %d ", ntohl(mp->l2_table_index));
+ if (mp->is_add == 0)
+ s = format (s, "del ");
+
+ FINISH;
+}
+
+static void * vl_api_policer_classify_dump_t_print
+(vl_api_policer_classify_dump_t * mp, void *handle)
+{
+ u8 * s;
+
+ s = format (0, "SCRIPT: policer_classify_dump ");
+ switch (mp->type) {
+ case POLICER_CLASSIFY_TABLE_IP4:
+ s = format (s, "type ip4 ");
+ break;
+ case POLICER_CLASSIFY_TABLE_IP6:
+ s = format (s, "type ip6 ");
+ break;
+ case POLICER_CLASSIFY_TABLE_L2:
+ s = format (s, "type l2 ");
+ break;
+ default:
+ break;
+ }
+
+ FINISH;
+}
+
static void *vl_api_sw_interface_clear_stats_t_print
(vl_api_sw_interface_clear_stats_t * mp, void *handle)
{
@@ -2031,7 +2185,11 @@ _(IPFIX_DUMP,ipfix_dump) \
_(GET_NEXT_INDEX, get_next_index) \
_(PG_CREATE_INTERFACE,pg_create_interface) \
_(PG_CAPTURE, pg_capture) \
-_(PG_ENABLE_DISABLE, pg_enable_disable)
+_(PG_ENABLE_DISABLE, pg_enable_disable) \
+_(POLICER_ADD_DEL, policer_add_del) \
+_(POLICER_DUMP, policer_dump) \
+_(POLICER_CLASSIFY_SET_INTERFACE, policer_classify_set_interface) \
+_(POLICER_CLASSIFY_DUMP, policer_classify_dump)
void vl_msg_api_custom_dump_configure (api_main_t *am)
{
diff --git a/vpp/vpp-api/vpe.api b/vpp/vpp-api/vpe.api
index 1477289b43d..4571c92df4d 100644
--- a/vpp/vpp-api/vpe.api
+++ b/vpp/vpp-api/vpe.api
@@ -3644,6 +3644,7 @@ define af_packet_delete_reply {
@param rate_type - rate type
@param round_type - rounding type
@param type - policer algorithm
+ @param color_aware - 0=color-blind, 1=color-aware
@param conform_action_type - conform action type
@param conform_dscp - DSCP for conform mar-and-transmit action
@param exceed_action_type - exceed action type
@@ -3664,6 +3665,7 @@ define policer_add_del {
u8 rate_type;
u8 round_type;
u8 type;
+ u8 color_aware;
u8 conform_action_type;
u8 conform_dscp;
u8 exceed_action_type;
@@ -3675,10 +3677,12 @@ define policer_add_del {
/** \brief Add/del policer response
@param context - sender context, to match reply w/ request
@param retval - return value for request
+ @param policer_index - for add, returned index of the new policer
*/
define policer_add_del_reply {
u32 context;
i32 retval;
+ u32 policer_index;
};
/** \brief Get list of policers
@@ -3751,6 +3755,58 @@ define policer_details {
u64 last_update_time;
};
+/** \brief Set/unset policer classify interface
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param sw_if_index - interface to set/unset policer classify
+ @param ip4_table_index - ip4 classify table index (~0 for skip)
+ @param ip6_table_index - ip6 classify table index (~0 for skip)
+ @param l2_table_index - l2 classify table index (~0 for skip)
+ @param is_add - Set if non-zero, else unset
+ Note: User is recommeneded to use just one valid table_index per call.
+ (ip4_table_index, ip6_table_index, or l2_table_index)
+*/
+define policer_classify_set_interface {
+ u32 client_index;
+ u32 context;
+ u32 sw_if_index;
+ u32 ip4_table_index;
+ u32 ip6_table_index;
+ u32 l2_table_index;
+ u8 is_add;
+};
+
+/** \brief Set/unset policer classify interface response
+ @param context - sender context, to match reply w/ request
+ @param retval - return value for request
+*/
+define policer_classify_set_interface_reply {
+ u32 context;
+ i32 retval;
+};
+
+/** \brief Get list of policer classify interfaces and tables
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param type - classify table type
+*/
+define policer_classify_dump {
+ u32 client_index;
+ u32 context;
+ u8 type;
+};
+
+/** \brief Policer iclassify operational state response.
+ @param context - sender context, to match reply w/ request
+ @param sw_if_index - software interface index
+ @param table_index - classify table index
+*/
+define policer_classify_details {
+ u32 context;
+ u32 sw_if_index;
+ u32 table_index;
+};
+
/** \brief Create netmap
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request