aboutsummaryrefslogtreecommitdiffstats
path: root/vnet
diff options
context:
space:
mode:
authorMatus Fabian <matfabia@cisco.com>2016-05-31 07:33:29 -0700
committerDamjan Marion <dmarion.lists@gmail.com>2016-07-12 15:12:58 +0000
commit4ac74c9599c73510900c18ff4c86ca390993adac (patch)
treee02baf9178ddad4f1cf810f04c33af1c2fd33f42 /vnet
parent41da02d96ba145a1778335391b8af7bbd1b4d6e6 (diff)
policer action
JIRA: VPP-90 Policer allows you to specify the action to be taken on a packet: conform-action (green color) exceed-action (yellow color) violate-action (red color) Action to take on packets: drop - drops the packet transmit - transmits the packet, the packet is not altered mark-and-transmit <DSCP> - sets the DSCP value and transmits the packet Change-Id: I59c037e55e7e2a9fc9b9752e92426f3977f5587b Signed-off-by: Matus Fabian <matfabia@cisco.com>
Diffstat (limited to 'vnet')
-rw-r--r--vnet/vnet/policer/node_funcs.c72
-rw-r--r--vnet/vnet/policer/police.h4
-rw-r--r--vnet/vnet/policer/policer.c87
-rw-r--r--vnet/vnet/policer/policer.h32
-rw-r--r--vnet/vnet/policer/xlate.c7
-rw-r--r--vnet/vnet/policer/xlate.h27
6 files changed, 215 insertions, 14 deletions
diff --git a/vnet/vnet/policer/node_funcs.c b/vnet/vnet/policer/node_funcs.c
index 739ce4551b6..6147ea51c1a 100644
--- a/vnet/vnet/policer/node_funcs.c
+++ b/vnet/vnet/policer/node_funcs.c
@@ -18,6 +18,12 @@
#include <vlib/vlib.h>
#include <vnet/vnet.h>
#include <vnet/policer/policer.h>
+#include <vnet/ip/ip.h>
+
+#define IP4_NON_DSCP_BITS 0x03
+#define IP4_DSCP_SHIFT 2
+#define IP6_NON_DSCP_BITS 0xf03fffff
+#define IP6_DSCP_SHIFT 22
/* Dispatch functions meant to be instantiated elsewhere */
@@ -56,6 +62,37 @@ static char * vnet_policer_error_strings[] = {
#undef _
};
+static_always_inline
+void vnet_policer_mark (vlib_buffer_t * b, u8 dscp)
+{
+ ethernet_header_t * eh;
+ ip4_header_t * ip4h;
+ ip6_header_t * ip6h;
+ u16 type;
+
+ eh = (ethernet_header_t *) b->data;
+ type = clib_net_to_host_u16 (eh->type);
+
+ if (PREDICT_TRUE(type == ETHERNET_TYPE_IP4))
+ {
+ ip4h = (ip4_header_t *) &(b->data[sizeof(ethernet_header_t)]);;
+ ip4h->tos &= IP4_NON_DSCP_BITS;
+ ip4h->tos |= dscp << IP4_DSCP_SHIFT;
+ ip4h->checksum = ip4_header_checksum (ip4h);
+ }
+ else
+ {
+ if (PREDICT_TRUE(type == ETHERNET_TYPE_IP6))
+ {
+ ip6h = (ip6_header_t *) &(b->data[sizeof(ethernet_header_t)]);
+ ip6h->ip_version_traffic_class_and_flow_label &=
+ clib_host_to_net_u32(IP6_NON_DSCP_BITS);
+ ip6h->ip_version_traffic_class_and_flow_label |=
+ clib_host_to_net_u32(dscp << IP6_DSCP_SHIFT);
+ }
+ }
+}
+
static inline
uword vnet_policer_inline (vlib_main_t * vm,
vlib_node_runtime_t * node,
@@ -92,6 +129,7 @@ uword vnet_policer_inline (vlib_main_t * vm,
u32 len0, len1;
u32 col0, col1;
policer_read_response_type_st * pol0, * pol1;
+ u8 act0, act1;
/* Prefetch next iteration. */
{
@@ -149,28 +187,38 @@ uword vnet_policer_inline (vlib_main_t * vm,
col0 = vnet_police_packet (pol0, len0,
POLICE_CONFORM /* no chaining */,
time_in_policer_periods);
+ act0 = pol0->action[col0];
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);
-
- if (PREDICT_FALSE(col0 > 0))
+ act1 = pol1->action[col1];
+
+ if (PREDICT_FALSE(act0 == SSE2_QOS_ACTION_DROP)) /* drop action */
{
next0 = VNET_POLICER_NEXT_DROP;
b0->error = node->errors[VNET_POLICER_ERROR_DROP];
}
- else
- transmitted++;
-
- if (PREDICT_FALSE(col1 > 0))
+ 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++;
+ }
+
+ if (PREDICT_FALSE(act1 == SSE2_QOS_ACTION_DROP)) /* drop action */
{
next1 = VNET_POLICER_NEXT_DROP;
b1->error = node->errors[VNET_POLICER_ERROR_DROP];
}
- else
- transmitted++;
+ 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++;
+ }
if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)))
@@ -207,6 +255,7 @@ uword vnet_policer_inline (vlib_main_t * vm,
u32 len0;
u32 col0;
policer_read_response_type_st * pol0;
+ u8 act0;
bi0 = from[0];
to_next[0] = bi0;
@@ -238,14 +287,17 @@ uword vnet_policer_inline (vlib_main_t * vm,
col0 = vnet_police_packet (pol0, len0,
POLICE_CONFORM /* no chaining */,
time_in_policer_periods);
+ act0 = pol0->action[col0];
- if (PREDICT_FALSE(col0 > 0))
+ if (PREDICT_FALSE(act0 == SSE2_QOS_ACTION_DROP)) /* drop action */
{
next0 = VNET_POLICER_NEXT_DROP;
b0->error = node->errors[VNET_POLICER_ERROR_DROP];
}
- else
+ 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++;
}
diff --git a/vnet/vnet/policer/police.h b/vnet/vnet/policer/police.h
index d2e369c655f..89f5ffee2ad 100644
--- a/vnet/vnet/policer/police.h
+++ b/vnet/vnet/policer/police.h
@@ -63,7 +63,9 @@ typedef struct {
uint32_t single_rate; // 1 = single rate policer, 0 = two rate policer
uint32_t color_aware; // for hierarchical policing
uint32_t scale; // power-of-2 shift amount for lower rates
- uint32_t pad[2];
+ uint8_t action[3];
+ uint8_t mark_dscp[3];
+ uint8_t pad[2];
// Fields are marked as 2R if they are only used for a 2-rate policer,
// and MOD if they are modified as part of the update operation.
diff --git a/vnet/vnet/policer/policer.c b/vnet/vnet/policer/policer.c
index 9e98de17cc8..8ffa967bd48 100644
--- a/vnet/vnet/policer/policer.c
+++ b/vnet/vnet/policer/policer.c
@@ -140,6 +140,38 @@ static u8 * format_policer_type (u8 * s, va_list * va)
return s;
}
+static u8 * format_dscp (u8 * s, va_list * va)
+{
+ u32 i = va_arg (*va, u32);
+ char * t = 0;
+
+ switch (i) {
+ #define _(v,f,str) case VNET_DSCP_##f: t = str; break;
+ foreach_vnet_dscp
+ #undef _
+ default:
+ return format (s, "ILLEGAL");
+ }
+ s = format (s, "%s", t);
+ return s;
+}
+
+static u8 * format_policer_action_type (u8 * s, va_list * va)
+{
+ sse2_qos_pol_action_params_st * a
+ = va_arg (*va, sse2_qos_pol_action_params_st *);
+
+ if (a->action_type == SSE2_QOS_ACTION_DROP)
+ s = format (s, "drop");
+ else if (a->action_type == SSE2_QOS_ACTION_TRANSMIT)
+ s = format (s, "transmit");
+ else if (a->action_type == SSE2_QOS_ACTION_MARK_AND_TRANSMIT)
+ s = format (s, "mark-and-transmit %U", format_dscp, a->dscp);
+ else
+ s = format (s, "ILLEGAL");
+ return s;
+}
+
u8 * format_policer_config (u8 * s, va_list * va)
{
sse2_qos_pol_cfg_params_st * c
@@ -154,6 +186,10 @@ u8 * format_policer_config (u8 * s, va_list * va)
s = format (s, "rate type %U, round type %U\n",
format_policer_rate_type, c,
format_policer_round_type, c);
+ s = format (s, "conform action %U, exceed action %U, violate action %U\n",
+ format_policer_action_type, &c->conform_action,
+ format_policer_action_type, &c->exceed_action,
+ format_policer_action_type, &c->violate_action);
return s;
}
@@ -263,6 +299,54 @@ unformat_policer_eb (unformat_input_t * input, va_list * va)
return 0;
}
+static uword
+unformat_dscp (unformat_input_t * input, va_list * va)
+{
+ u8 * r = va_arg (*va, u8 *);
+
+ if (0) ;
+#define _(v,f,str) else if (unformat (input, str)) *r = VNET_DSCP_##f;
+ foreach_vnet_dscp
+#undef _
+ else
+ return 0;
+ return 1;
+}
+
+static uword
+unformat_policer_action_type (unformat_input_t * input, va_list * va)
+{
+ sse2_qos_pol_action_params_st * a
+ = va_arg (*va, sse2_qos_pol_action_params_st *);
+
+ if (unformat (input, "drop"))
+ a->action_type = SSE2_QOS_ACTION_DROP;
+ else if (unformat (input, "transmit"))
+ a->action_type = SSE2_QOS_ACTION_TRANSMIT;
+ else if (unformat (input, "mark-and-transmit %U", unformat_dscp, &a->dscp))
+ a->action_type = SSE2_QOS_ACTION_MARK_AND_TRANSMIT;
+ else
+ return 0;
+ return 1;
+}
+
+static uword
+unformat_policer_action (unformat_input_t * input, va_list * va)
+{
+ sse2_qos_pol_cfg_params_st * c
+ = va_arg (*va, sse2_qos_pol_cfg_params_st *);
+
+ if (unformat (input, "conform-action %U", unformat_policer_action_type,
+ &c->conform_action))
+ return 1;
+ else if (unformat (input, "exceed-action %U", unformat_policer_action_type,
+ &c->exceed_action))
+ return 1;
+ else if (unformat (input, "violate-action %U", unformat_policer_action_type,
+ &c->violate_action))
+ return 1;
+ return 0;
+}
#define foreach_config_param \
_(eb) \
@@ -271,7 +355,8 @@ _(eir) \
_(cir) \
_(rate_type) \
_(round_type) \
-_(type)
+_(type) \
+_(action)
static clib_error_t *
configure_policer_command_fn (vlib_main_t * vm,
diff --git a/vnet/vnet/policer/policer.h b/vnet/vnet/policer/policer.h
index 02c2d228edd..fba866f4773 100644
--- a/vnet/vnet/policer/policer.h
+++ b/vnet/vnet/policer/policer.h
@@ -48,13 +48,41 @@ typedef enum {
VNET_POLICER_INDEX_BY_EITHER,
} vnet_policer_index_t;
-typedef
-enum {
+typedef enum {
VNET_POLICER_NEXT_TRANSMIT,
VNET_POLICER_NEXT_DROP,
VNET_POLICER_N_NEXT,
} vnet_policer_next_t;
+#define foreach_vnet_dscp \
+ _(0 , CS0, "CS0") \
+ _(8 , CS1, "CS1") \
+ _(10, AF11, "AF11") \
+ _(12, AF12, "AF12") \
+ _(14, AF13, "AF13") \
+ _(16, CS2, "CS2") \
+ _(18, AF21, "AF21") \
+ _(20, AF22, "AF22") \
+ _(22, AF23, "AF23") \
+ _(24, CS3, "CS3") \
+ _(26, AF31, "AF31") \
+ _(28, AF32, "AF32") \
+ _(30, AF33, "AF33") \
+ _(32, CS4, "CS4") \
+ _(34, AF41, "AF41") \
+ _(36, AF42, "AF42") \
+ _(38, AF43, "AF43") \
+ _(40, CS5, "CS5") \
+ _(46, EF, "EF") \
+ _(48, CS6, "CS6") \
+ _(50, CS7, "CS7")
+
+typedef enum {
+#define _(v,f,str) VNET_DSCP_##f = v,
+ foreach_vnet_dscp
+#undef _
+} vnet_dscp_t;
+
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,
diff --git a/vnet/vnet/policer/xlate.c b/vnet/vnet/policer/xlate.c
index d1eab304d39..f47982e31ee 100644
--- a/vnet/vnet/policer/xlate.c
+++ b/vnet/vnet/policer/xlate.c
@@ -1129,6 +1129,13 @@ sse2_pol_logical_2_physical (sse2_qos_pol_cfg_params_st *cfg,
kbps_cfg.rnd_type = cfg->rnd_type;
kbps_cfg.rfc = cfg->rfc;
+ phys->action[POLICE_CONFORM] = cfg->conform_action.action_type;
+ phys->mark_dscp[POLICE_CONFORM] = cfg->conform_action.dscp;
+ phys->action[POLICE_EXCEED] = cfg->exceed_action.action_type;
+ phys->mark_dscp[POLICE_EXCEED] = cfg->exceed_action.dscp;
+ phys->action[POLICE_VIOLATE] = cfg->violate_action.action_type;
+ phys->mark_dscp[POLICE_VIOLATE] = cfg->violate_action.dscp;
+
#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 b41666c897e..d3fdeded55f 100644
--- a/vnet/vnet/policer/xlate.h
+++ b/vnet/vnet/policer/xlate.h
@@ -63,6 +63,30 @@ typedef enum {
SSE2_QOS_RATE_INVALID
} sse2_qos_rate_type_en;
+/*
+ * edt: * enum
+ * Defines type of policer actions.
+ */
+typedef enum {
+ SSE2_QOS_ACTION_DROP = 0,
+ SSE2_QOS_ACTION_TRANSMIT,
+ SSE2_QOS_ACTION_MARK_AND_TRANSMIT
+} sse2_qos_action_type_en;
+
+/*
+ * edt * struct sse2_qos_pol_action_params_st
+ * This structure is used to hold user configured police action parameters.
+ *
+ * element: action_type
+ * Action type (see sse2_qos_action_type_en).
+ * elemtnt: dscp
+ * DSCP value to set when action is SSE2_QOS_ACTION_MARK_AND_TRANSMIT.
+ */
+typedef struct sse2_qos_pol_action_params_st_ {
+ uint8_t action_type;
+ uint8_t dscp;
+} sse2_qos_pol_action_params_st;
+
/*
* edt: * struct sse2_qos_pol_cfg_params_st
*
@@ -115,6 +139,9 @@ typedef struct sse2_qos_pol_cfg_params_st_ {
uint8_t overwrite_bucket; /* for debugging purposes */
uint32_t current_bucket; /* for debugging purposes */
uint32_t extended_bucket; /* for debugging purposes */
+ sse2_qos_pol_action_params_st conform_action;
+ sse2_qos_pol_action_params_st exceed_action;
+ sse2_qos_pol_action_params_st violate_action;
} sse2_qos_pol_cfg_params_st;