From 4ac74c9599c73510900c18ff4c86ca390993adac Mon Sep 17 00:00:00 2001 From: Matus Fabian Date: Tue, 31 May 2016 07:33:29 -0700 Subject: 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 - sets the DSCP value and transmits the packet Change-Id: I59c037e55e7e2a9fc9b9752e92426f3977f5587b Signed-off-by: Matus Fabian --- vnet/vnet/policer/node_funcs.c | 72 +++++++++++++++++++++++++++++----- vnet/vnet/policer/police.h | 4 +- vnet/vnet/policer/policer.c | 87 +++++++++++++++++++++++++++++++++++++++++- vnet/vnet/policer/policer.h | 32 +++++++++++++++- vnet/vnet/policer/xlate.c | 7 ++++ vnet/vnet/policer/xlate.h | 27 +++++++++++++ 6 files changed, 215 insertions(+), 14 deletions(-) (limited to 'vnet') diff --git a/vnet/vnet/policer/node_funcs.c b/vnet/vnet/policer/node_funcs.c index 739ce455..6147ea51 100644 --- a/vnet/vnet/policer/node_funcs.c +++ b/vnet/vnet/policer/node_funcs.c @@ -18,6 +18,12 @@ #include #include #include +#include + +#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 d2e369c6..89f5ffee 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 9e98de17..8ffa967b 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 02c2d228..fba866f4 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 d1eab304..f47982e3 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 b41666c8..d3fdeded 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; -- cgit 1.2.3-korg