pipeline: add traffic metering action
Add traffic metering action implementation. Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
This commit is contained in:
parent
406a2bc0c6
commit
7c9e5b9a12
@ -8,10 +8,11 @@ include $(RTE_SDK)/mk/rte.vars.mk
|
||||
#
|
||||
LIB = librte_pipeline.a
|
||||
|
||||
CFLAGS += -DALLOW_EXPERIMENTAL_API
|
||||
CFLAGS += -O3
|
||||
CFLAGS += $(WERROR_FLAGS)
|
||||
LDLIBS += -lrte_eal -lrte_mempool -lrte_mbuf -lrte_table
|
||||
LDLIBS += -lrte_port
|
||||
LDLIBS += -lrte_port -lrte_meter
|
||||
|
||||
EXPORT_MAP := rte_pipeline_version.map
|
||||
|
||||
|
@ -5,4 +5,4 @@ version = 3
|
||||
allow_experimental_apis = true
|
||||
sources = files('rte_pipeline.c', 'rte_table_action.c')
|
||||
headers = files('rte_pipeline.h', 'rte_table_action.h')
|
||||
deps += ['port', 'table']
|
||||
deps += ['port', 'table', 'meter']
|
||||
|
@ -51,7 +51,11 @@ EXPERIMENTAL {
|
||||
|
||||
rte_table_action_apply;
|
||||
rte_table_action_create;
|
||||
rte_table_action_dscp_table_update;
|
||||
rte_table_action_free;
|
||||
rte_table_action_meter_profile_add;
|
||||
rte_table_action_meter_profile_delete;
|
||||
rte_table_action_meter_read;
|
||||
rte_table_action_profile_action_register;
|
||||
rte_table_action_profile_create;
|
||||
rte_table_action_profile_free;
|
||||
|
@ -5,13 +5,21 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <rte_malloc.h>
|
||||
|
||||
#include <rte_common.h>
|
||||
#include <rte_byteorder.h>
|
||||
#include <rte_cycles.h>
|
||||
#include <rte_malloc.h>
|
||||
#include <rte_ip.h>
|
||||
|
||||
|
||||
#include "rte_table_action.h"
|
||||
|
||||
#define rte_htons rte_cpu_to_be_16
|
||||
#define rte_htonl rte_cpu_to_be_32
|
||||
|
||||
#define rte_ntohs rte_be_to_cpu_16
|
||||
#define rte_ntohl rte_be_to_cpu_32
|
||||
|
||||
/**
|
||||
* RTE_TABLE_ACTION_FWD
|
||||
*/
|
||||
@ -32,6 +40,264 @@ fwd_apply(struct fwd_data *data,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* RTE_TABLE_ACTION_MTR
|
||||
*/
|
||||
static int
|
||||
mtr_cfg_check(struct rte_table_action_mtr_config *mtr)
|
||||
{
|
||||
if ((mtr->alg == RTE_TABLE_ACTION_METER_SRTCM) ||
|
||||
((mtr->n_tc != 1) && (mtr->n_tc != 4)) ||
|
||||
(mtr->n_bytes_enabled != 0))
|
||||
return -ENOTSUP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MBUF_SCHED_QUEUE_TC_COLOR(queue, tc, color) \
|
||||
((uint16_t)((((uint64_t)(queue)) & 0x3) | \
|
||||
((((uint64_t)(tc)) & 0x3) << 2) | \
|
||||
((((uint64_t)(color)) & 0x3) << 4)))
|
||||
|
||||
#define MBUF_SCHED_COLOR(sched, color) \
|
||||
(((sched) & (~0x30LLU)) | ((color) << 4))
|
||||
|
||||
struct mtr_trtcm_data {
|
||||
struct rte_meter_trtcm trtcm;
|
||||
uint64_t stats[e_RTE_METER_COLORS];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#define MTR_TRTCM_DATA_METER_PROFILE_ID_GET(data) \
|
||||
(((data)->stats[e_RTE_METER_GREEN] & 0xF8LLU) >> 3)
|
||||
|
||||
static void
|
||||
mtr_trtcm_data_meter_profile_id_set(struct mtr_trtcm_data *data,
|
||||
uint32_t profile_id)
|
||||
{
|
||||
data->stats[e_RTE_METER_GREEN] &= ~0xF8LLU;
|
||||
data->stats[e_RTE_METER_GREEN] |= (profile_id % 32) << 3;
|
||||
}
|
||||
|
||||
#define MTR_TRTCM_DATA_POLICER_ACTION_DROP_GET(data, color)\
|
||||
(((data)->stats[(color)] & 4LLU) >> 2)
|
||||
|
||||
#define MTR_TRTCM_DATA_POLICER_ACTION_COLOR_GET(data, color)\
|
||||
((enum rte_meter_color)((data)->stats[(color)] & 3LLU))
|
||||
|
||||
static void
|
||||
mtr_trtcm_data_policer_action_set(struct mtr_trtcm_data *data,
|
||||
enum rte_meter_color color,
|
||||
enum rte_table_action_policer action)
|
||||
{
|
||||
if (action == RTE_TABLE_ACTION_POLICER_DROP) {
|
||||
data->stats[color] |= 4LLU;
|
||||
} else {
|
||||
data->stats[color] &= ~7LLU;
|
||||
data->stats[color] |= color & 3LLU;
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
mtr_trtcm_data_stats_get(struct mtr_trtcm_data *data,
|
||||
enum rte_meter_color color)
|
||||
{
|
||||
return data->stats[color] >> 8;
|
||||
}
|
||||
|
||||
static void
|
||||
mtr_trtcm_data_stats_reset(struct mtr_trtcm_data *data,
|
||||
enum rte_meter_color color)
|
||||
{
|
||||
data->stats[color] &= 0xFFLU;
|
||||
}
|
||||
|
||||
#define MTR_TRTCM_DATA_STATS_INC(data, color) \
|
||||
((data)->stats[(color)] += (1LLU << 8))
|
||||
|
||||
static size_t
|
||||
mtr_data_size(struct rte_table_action_mtr_config *mtr)
|
||||
{
|
||||
return mtr->n_tc * sizeof(struct mtr_trtcm_data);
|
||||
}
|
||||
|
||||
struct dscp_table_entry_data {
|
||||
enum rte_meter_color color;
|
||||
uint16_t tc;
|
||||
uint16_t queue_tc_color;
|
||||
};
|
||||
|
||||
struct dscp_table_data {
|
||||
struct dscp_table_entry_data entry[64];
|
||||
};
|
||||
|
||||
struct meter_profile_data {
|
||||
struct rte_meter_trtcm_profile profile;
|
||||
uint32_t profile_id;
|
||||
int valid;
|
||||
};
|
||||
|
||||
static struct meter_profile_data *
|
||||
meter_profile_data_find(struct meter_profile_data *mp,
|
||||
uint32_t mp_size,
|
||||
uint32_t profile_id)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < mp_size; i++) {
|
||||
struct meter_profile_data *mp_data = &mp[i];
|
||||
|
||||
if (mp_data->valid && (mp_data->profile_id == profile_id))
|
||||
return mp_data;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct meter_profile_data *
|
||||
meter_profile_data_find_unused(struct meter_profile_data *mp,
|
||||
uint32_t mp_size)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < mp_size; i++) {
|
||||
struct meter_profile_data *mp_data = &mp[i];
|
||||
|
||||
if (!mp_data->valid)
|
||||
return mp_data;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
mtr_apply_check(struct rte_table_action_mtr_params *p,
|
||||
struct rte_table_action_mtr_config *cfg,
|
||||
struct meter_profile_data *mp,
|
||||
uint32_t mp_size)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
if (p->tc_mask > RTE_LEN2MASK(cfg->n_tc, uint32_t))
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
|
||||
struct rte_table_action_mtr_tc_params *p_tc = &p->mtr[i];
|
||||
struct meter_profile_data *mp_data;
|
||||
|
||||
if ((p->tc_mask & (1LLU << i)) == 0)
|
||||
continue;
|
||||
|
||||
mp_data = meter_profile_data_find(mp,
|
||||
mp_size,
|
||||
p_tc->meter_profile_id);
|
||||
if (!mp_data)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mtr_apply(struct mtr_trtcm_data *data,
|
||||
struct rte_table_action_mtr_params *p,
|
||||
struct rte_table_action_mtr_config *cfg,
|
||||
struct meter_profile_data *mp,
|
||||
uint32_t mp_size)
|
||||
{
|
||||
uint32_t i;
|
||||
int status;
|
||||
|
||||
/* Check input arguments */
|
||||
status = mtr_apply_check(p, cfg, mp, mp_size);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
/* Apply */
|
||||
for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
|
||||
struct rte_table_action_mtr_tc_params *p_tc = &p->mtr[i];
|
||||
struct mtr_trtcm_data *data_tc = &data[i];
|
||||
struct meter_profile_data *mp_data;
|
||||
|
||||
if ((p->tc_mask & (1LLU << i)) == 0)
|
||||
continue;
|
||||
|
||||
/* Find profile */
|
||||
mp_data = meter_profile_data_find(mp,
|
||||
mp_size,
|
||||
p_tc->meter_profile_id);
|
||||
if (!mp_data)
|
||||
return -EINVAL;
|
||||
|
||||
memset(data_tc, 0, sizeof(*data_tc));
|
||||
|
||||
/* Meter object */
|
||||
status = rte_meter_trtcm_config(&data_tc->trtcm,
|
||||
&mp_data->profile);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
/* Meter profile */
|
||||
mtr_trtcm_data_meter_profile_id_set(data_tc,
|
||||
mp_data - mp);
|
||||
|
||||
/* Policer actions */
|
||||
mtr_trtcm_data_policer_action_set(data_tc,
|
||||
e_RTE_METER_GREEN,
|
||||
p_tc->policer[e_RTE_METER_GREEN]);
|
||||
|
||||
mtr_trtcm_data_policer_action_set(data_tc,
|
||||
e_RTE_METER_YELLOW,
|
||||
p_tc->policer[e_RTE_METER_YELLOW]);
|
||||
|
||||
mtr_trtcm_data_policer_action_set(data_tc,
|
||||
e_RTE_METER_RED,
|
||||
p_tc->policer[e_RTE_METER_RED]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __rte_always_inline uint64_t
|
||||
pkt_work_mtr(struct rte_mbuf *mbuf,
|
||||
struct mtr_trtcm_data *data,
|
||||
struct dscp_table_data *dscp_table,
|
||||
struct meter_profile_data *mp,
|
||||
uint64_t time,
|
||||
uint32_t dscp,
|
||||
uint16_t total_length)
|
||||
{
|
||||
uint64_t drop_mask, sched;
|
||||
uint64_t *sched_ptr = (uint64_t *) &mbuf->hash.sched;
|
||||
struct dscp_table_entry_data *dscp_entry = &dscp_table->entry[dscp];
|
||||
enum rte_meter_color color_in, color_meter, color_policer;
|
||||
uint32_t tc, mp_id;
|
||||
|
||||
tc = dscp_entry->tc;
|
||||
color_in = dscp_entry->color;
|
||||
data += tc;
|
||||
mp_id = MTR_TRTCM_DATA_METER_PROFILE_ID_GET(data);
|
||||
sched = *sched_ptr;
|
||||
|
||||
/* Meter */
|
||||
color_meter = rte_meter_trtcm_color_aware_check(
|
||||
&data->trtcm,
|
||||
&mp[mp_id].profile,
|
||||
time,
|
||||
total_length,
|
||||
color_in);
|
||||
|
||||
/* Stats */
|
||||
MTR_TRTCM_DATA_STATS_INC(data, color_meter);
|
||||
|
||||
/* Police */
|
||||
drop_mask = MTR_TRTCM_DATA_POLICER_ACTION_DROP_GET(data, color_meter);
|
||||
color_policer =
|
||||
MTR_TRTCM_DATA_POLICER_ACTION_COLOR_GET(data, color_meter);
|
||||
*sched_ptr = MBUF_SCHED_COLOR(sched, color_policer);
|
||||
|
||||
return drop_mask;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Action profile
|
||||
*/
|
||||
@ -40,6 +306,7 @@ action_valid(enum rte_table_action_type action)
|
||||
{
|
||||
switch (action) {
|
||||
case RTE_TABLE_ACTION_FWD:
|
||||
case RTE_TABLE_ACTION_MTR:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
@ -52,22 +319,28 @@ action_valid(enum rte_table_action_type action)
|
||||
struct ap_config {
|
||||
uint64_t action_mask;
|
||||
struct rte_table_action_common_config common;
|
||||
struct rte_table_action_mtr_config mtr;
|
||||
};
|
||||
|
||||
static size_t
|
||||
action_cfg_size(enum rte_table_action_type action)
|
||||
{
|
||||
switch (action) {
|
||||
case RTE_TABLE_ACTION_MTR:
|
||||
return sizeof(struct rte_table_action_mtr_config);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void*
|
||||
action_cfg_get(struct ap_config *ap_config __rte_unused,
|
||||
action_cfg_get(struct ap_config *ap_config,
|
||||
enum rte_table_action_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case RTE_TABLE_ACTION_MTR:
|
||||
return &ap_config->mtr;
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
@ -93,12 +366,15 @@ struct ap_data {
|
||||
|
||||
static size_t
|
||||
action_data_size(enum rte_table_action_type action,
|
||||
struct ap_config *ap_config __rte_unused)
|
||||
struct ap_config *ap_config)
|
||||
{
|
||||
switch (action) {
|
||||
case RTE_TABLE_ACTION_FWD:
|
||||
return sizeof(struct fwd_data);
|
||||
|
||||
case RTE_TABLE_ACTION_MTR:
|
||||
return mtr_data_size(&ap_config->mtr);
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@ -158,6 +434,8 @@ rte_table_action_profile_action_register(struct rte_table_action_profile *profil
|
||||
enum rte_table_action_type type,
|
||||
void *action_config)
|
||||
{
|
||||
int status;
|
||||
|
||||
/* Check input arguments */
|
||||
if ((profile == NULL) ||
|
||||
profile->frozen ||
|
||||
@ -167,6 +445,19 @@ rte_table_action_profile_action_register(struct rte_table_action_profile *profil
|
||||
(action_cfg_size(type) && (action_config == NULL)))
|
||||
return -EINVAL;
|
||||
|
||||
switch (type) {
|
||||
case RTE_TABLE_ACTION_MTR:
|
||||
status = mtr_cfg_check(action_config);
|
||||
break;
|
||||
|
||||
default:
|
||||
status = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
/* Action enable */
|
||||
action_cfg_set(&profile->cfg, type, action_config);
|
||||
|
||||
@ -196,9 +487,16 @@ rte_table_action_profile_free(struct rte_table_action_profile *profile)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Action
|
||||
*/
|
||||
#define METER_PROFILES_MAX 32
|
||||
|
||||
struct rte_table_action {
|
||||
struct ap_config cfg;
|
||||
struct ap_data data;
|
||||
struct dscp_table_data dscp_table;
|
||||
struct meter_profile_data mp[METER_PROFILES_MAX];
|
||||
};
|
||||
|
||||
struct rte_table_action *
|
||||
@ -262,29 +560,336 @@ rte_table_action_apply(struct rte_table_action *action,
|
||||
return fwd_apply(action_data,
|
||||
action_params);
|
||||
|
||||
case RTE_TABLE_ACTION_MTR:
|
||||
return mtr_apply(action_data,
|
||||
action_params,
|
||||
&action->cfg.mtr,
|
||||
action->mp,
|
||||
RTE_DIM(action->mp));
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static __rte_always_inline uint64_t
|
||||
pkt_work(struct rte_mbuf *mbuf __rte_unused,
|
||||
struct rte_pipeline_table_entry *table_entry __rte_unused,
|
||||
uint64_t time __rte_unused,
|
||||
struct rte_table_action *action __rte_unused,
|
||||
struct ap_config *cfg __rte_unused)
|
||||
int
|
||||
rte_table_action_dscp_table_update(struct rte_table_action *action,
|
||||
uint64_t dscp_mask,
|
||||
struct rte_table_action_dscp_table *table)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
/* Check input arguments */
|
||||
if ((action == NULL) ||
|
||||
(action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) ||
|
||||
(dscp_mask == 0) ||
|
||||
(table == NULL))
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < RTE_DIM(table->entry); i++) {
|
||||
struct dscp_table_entry_data *data =
|
||||
&action->dscp_table.entry[i];
|
||||
struct rte_table_action_dscp_table_entry *entry =
|
||||
&table->entry[i];
|
||||
uint16_t queue_tc_color =
|
||||
MBUF_SCHED_QUEUE_TC_COLOR(entry->tc_queue_id,
|
||||
entry->tc_id,
|
||||
entry->color);
|
||||
|
||||
if ((dscp_mask & (1LLU << i)) == 0)
|
||||
continue;
|
||||
|
||||
data->color = entry->color;
|
||||
data->tc = entry->tc_id;
|
||||
data->queue_tc_color = queue_tc_color;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
rte_table_action_meter_profile_add(struct rte_table_action *action,
|
||||
uint32_t meter_profile_id,
|
||||
struct rte_table_action_meter_profile *profile)
|
||||
{
|
||||
struct meter_profile_data *mp_data;
|
||||
uint32_t status;
|
||||
|
||||
/* Check input arguments */
|
||||
if ((action == NULL) ||
|
||||
((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0) ||
|
||||
(profile == NULL))
|
||||
return -EINVAL;
|
||||
|
||||
if (profile->alg != RTE_TABLE_ACTION_METER_TRTCM)
|
||||
return -ENOTSUP;
|
||||
|
||||
mp_data = meter_profile_data_find(action->mp,
|
||||
RTE_DIM(action->mp),
|
||||
meter_profile_id);
|
||||
if (mp_data)
|
||||
return -EEXIST;
|
||||
|
||||
mp_data = meter_profile_data_find_unused(action->mp,
|
||||
RTE_DIM(action->mp));
|
||||
if (!mp_data)
|
||||
return -ENOSPC;
|
||||
|
||||
/* Install new profile */
|
||||
status = rte_meter_trtcm_profile_config(&mp_data->profile,
|
||||
&profile->trtcm);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
mp_data->profile_id = meter_profile_id;
|
||||
mp_data->valid = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
rte_table_action_meter_profile_delete(struct rte_table_action *action,
|
||||
uint32_t meter_profile_id)
|
||||
{
|
||||
struct meter_profile_data *mp_data;
|
||||
|
||||
/* Check input arguments */
|
||||
if ((action == NULL) ||
|
||||
((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0))
|
||||
return -EINVAL;
|
||||
|
||||
mp_data = meter_profile_data_find(action->mp,
|
||||
RTE_DIM(action->mp),
|
||||
meter_profile_id);
|
||||
if (!mp_data)
|
||||
return 0;
|
||||
|
||||
/* Uninstall profile */
|
||||
mp_data->valid = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
rte_table_action_meter_read(struct rte_table_action *action,
|
||||
void *data,
|
||||
uint32_t tc_mask,
|
||||
struct rte_table_action_mtr_counters *stats,
|
||||
int clear)
|
||||
{
|
||||
struct mtr_trtcm_data *mtr_data;
|
||||
uint32_t i;
|
||||
|
||||
/* Check input arguments */
|
||||
if ((action == NULL) ||
|
||||
((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0) ||
|
||||
(data == NULL) ||
|
||||
(tc_mask > RTE_LEN2MASK(action->cfg.mtr.n_tc, uint32_t)))
|
||||
return -EINVAL;
|
||||
|
||||
mtr_data = action_data_get(data, action, RTE_TABLE_ACTION_MTR);
|
||||
|
||||
/* Read */
|
||||
if (stats) {
|
||||
for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
|
||||
struct rte_table_action_mtr_counters_tc *dst =
|
||||
&stats->stats[i];
|
||||
struct mtr_trtcm_data *src = &mtr_data[i];
|
||||
|
||||
if ((tc_mask & (1 << i)) == 0)
|
||||
continue;
|
||||
|
||||
dst->n_packets[e_RTE_METER_GREEN] =
|
||||
mtr_trtcm_data_stats_get(src, e_RTE_METER_GREEN);
|
||||
|
||||
dst->n_packets[e_RTE_METER_YELLOW] =
|
||||
mtr_trtcm_data_stats_get(src, e_RTE_METER_YELLOW);
|
||||
|
||||
dst->n_packets[e_RTE_METER_RED] =
|
||||
mtr_trtcm_data_stats_get(src, e_RTE_METER_RED);
|
||||
|
||||
dst->n_packets_valid = 1;
|
||||
dst->n_bytes_valid = 0;
|
||||
}
|
||||
|
||||
stats->tc_mask = tc_mask;
|
||||
}
|
||||
|
||||
/* Clear */
|
||||
if (clear)
|
||||
for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
|
||||
struct mtr_trtcm_data *src = &mtr_data[i];
|
||||
|
||||
if ((tc_mask & (1 << i)) == 0)
|
||||
continue;
|
||||
|
||||
mtr_trtcm_data_stats_reset(src, e_RTE_METER_GREEN);
|
||||
mtr_trtcm_data_stats_reset(src, e_RTE_METER_YELLOW);
|
||||
mtr_trtcm_data_stats_reset(src, e_RTE_METER_RED);
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __rte_always_inline uint64_t
|
||||
pkt4_work(struct rte_mbuf **mbufs __rte_unused,
|
||||
struct rte_pipeline_table_entry **table_entries __rte_unused,
|
||||
uint64_t time __rte_unused,
|
||||
struct rte_table_action *action __rte_unused,
|
||||
struct ap_config *cfg __rte_unused)
|
||||
pkt_work(struct rte_mbuf *mbuf,
|
||||
struct rte_pipeline_table_entry *table_entry,
|
||||
uint64_t time,
|
||||
struct rte_table_action *action,
|
||||
struct ap_config *cfg)
|
||||
{
|
||||
return 0;
|
||||
uint64_t drop_mask = 0;
|
||||
|
||||
uint32_t ip_offset = action->cfg.common.ip_offset;
|
||||
void *ip = RTE_MBUF_METADATA_UINT32_PTR(mbuf, ip_offset);
|
||||
|
||||
uint32_t dscp;
|
||||
uint16_t total_length;
|
||||
|
||||
if (cfg->common.ip_version) {
|
||||
struct ipv4_hdr *hdr = ip;
|
||||
|
||||
dscp = hdr->type_of_service >> 2;
|
||||
total_length = rte_ntohs(hdr->total_length);
|
||||
} else {
|
||||
struct ipv6_hdr *hdr = ip;
|
||||
|
||||
dscp = (rte_ntohl(hdr->vtc_flow) & 0x0F600000) >> 18;
|
||||
total_length =
|
||||
rte_ntohs(hdr->payload_len) + sizeof(struct ipv6_hdr);
|
||||
}
|
||||
|
||||
if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
|
||||
void *data =
|
||||
action_data_get(table_entry, action, RTE_TABLE_ACTION_MTR);
|
||||
|
||||
drop_mask |= pkt_work_mtr(mbuf,
|
||||
data,
|
||||
&action->dscp_table,
|
||||
action->mp,
|
||||
time,
|
||||
dscp,
|
||||
total_length);
|
||||
}
|
||||
|
||||
return drop_mask;
|
||||
}
|
||||
|
||||
static __rte_always_inline uint64_t
|
||||
pkt4_work(struct rte_mbuf **mbufs,
|
||||
struct rte_pipeline_table_entry **table_entries,
|
||||
uint64_t time,
|
||||
struct rte_table_action *action,
|
||||
struct ap_config *cfg)
|
||||
{
|
||||
uint64_t drop_mask0 = 0;
|
||||
uint64_t drop_mask1 = 0;
|
||||
uint64_t drop_mask2 = 0;
|
||||
uint64_t drop_mask3 = 0;
|
||||
|
||||
struct rte_mbuf *mbuf0 = mbufs[0];
|
||||
struct rte_mbuf *mbuf1 = mbufs[1];
|
||||
struct rte_mbuf *mbuf2 = mbufs[2];
|
||||
struct rte_mbuf *mbuf3 = mbufs[3];
|
||||
|
||||
struct rte_pipeline_table_entry *table_entry0 = table_entries[0];
|
||||
struct rte_pipeline_table_entry *table_entry1 = table_entries[1];
|
||||
struct rte_pipeline_table_entry *table_entry2 = table_entries[2];
|
||||
struct rte_pipeline_table_entry *table_entry3 = table_entries[3];
|
||||
|
||||
uint32_t ip_offset = action->cfg.common.ip_offset;
|
||||
void *ip0 = RTE_MBUF_METADATA_UINT32_PTR(mbuf0, ip_offset);
|
||||
void *ip1 = RTE_MBUF_METADATA_UINT32_PTR(mbuf1, ip_offset);
|
||||
void *ip2 = RTE_MBUF_METADATA_UINT32_PTR(mbuf2, ip_offset);
|
||||
void *ip3 = RTE_MBUF_METADATA_UINT32_PTR(mbuf3, ip_offset);
|
||||
|
||||
uint32_t dscp0, dscp1, dscp2, dscp3;
|
||||
uint16_t total_length0, total_length1, total_length2, total_length3;
|
||||
|
||||
if (cfg->common.ip_version) {
|
||||
struct ipv4_hdr *hdr0 = ip0;
|
||||
struct ipv4_hdr *hdr1 = ip1;
|
||||
struct ipv4_hdr *hdr2 = ip2;
|
||||
struct ipv4_hdr *hdr3 = ip3;
|
||||
|
||||
dscp0 = hdr0->type_of_service >> 2;
|
||||
dscp1 = hdr1->type_of_service >> 2;
|
||||
dscp2 = hdr2->type_of_service >> 2;
|
||||
dscp3 = hdr3->type_of_service >> 2;
|
||||
|
||||
total_length0 = rte_ntohs(hdr0->total_length);
|
||||
total_length1 = rte_ntohs(hdr1->total_length);
|
||||
total_length2 = rte_ntohs(hdr2->total_length);
|
||||
total_length3 = rte_ntohs(hdr3->total_length);
|
||||
} else {
|
||||
struct ipv6_hdr *hdr0 = ip0;
|
||||
struct ipv6_hdr *hdr1 = ip1;
|
||||
struct ipv6_hdr *hdr2 = ip2;
|
||||
struct ipv6_hdr *hdr3 = ip3;
|
||||
|
||||
dscp0 = (rte_ntohl(hdr0->vtc_flow) & 0x0F600000) >> 18;
|
||||
dscp1 = (rte_ntohl(hdr1->vtc_flow) & 0x0F600000) >> 18;
|
||||
dscp2 = (rte_ntohl(hdr2->vtc_flow) & 0x0F600000) >> 18;
|
||||
dscp3 = (rte_ntohl(hdr3->vtc_flow) & 0x0F600000) >> 18;
|
||||
|
||||
total_length0 =
|
||||
rte_ntohs(hdr0->payload_len) + sizeof(struct ipv6_hdr);
|
||||
total_length1 =
|
||||
rte_ntohs(hdr1->payload_len) + sizeof(struct ipv6_hdr);
|
||||
total_length2 =
|
||||
rte_ntohs(hdr2->payload_len) + sizeof(struct ipv6_hdr);
|
||||
total_length3 =
|
||||
rte_ntohs(hdr3->payload_len) + sizeof(struct ipv6_hdr);
|
||||
}
|
||||
|
||||
if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
|
||||
void *data0 =
|
||||
action_data_get(table_entry0, action, RTE_TABLE_ACTION_MTR);
|
||||
void *data1 =
|
||||
action_data_get(table_entry1, action, RTE_TABLE_ACTION_MTR);
|
||||
void *data2 =
|
||||
action_data_get(table_entry2, action, RTE_TABLE_ACTION_MTR);
|
||||
void *data3 =
|
||||
action_data_get(table_entry3, action, RTE_TABLE_ACTION_MTR);
|
||||
|
||||
drop_mask0 |= pkt_work_mtr(mbuf0,
|
||||
data0,
|
||||
&action->dscp_table,
|
||||
action->mp,
|
||||
time,
|
||||
dscp0,
|
||||
total_length0);
|
||||
|
||||
drop_mask1 |= pkt_work_mtr(mbuf1,
|
||||
data1,
|
||||
&action->dscp_table,
|
||||
action->mp,
|
||||
time,
|
||||
dscp1,
|
||||
total_length1);
|
||||
|
||||
drop_mask2 |= pkt_work_mtr(mbuf2,
|
||||
data2,
|
||||
&action->dscp_table,
|
||||
action->mp,
|
||||
time,
|
||||
dscp2,
|
||||
total_length2);
|
||||
|
||||
drop_mask3 |= pkt_work_mtr(mbuf3,
|
||||
data3,
|
||||
&action->dscp_table,
|
||||
action->mp,
|
||||
time,
|
||||
dscp3,
|
||||
total_length3);
|
||||
}
|
||||
|
||||
return drop_mask0 |
|
||||
(drop_mask1 << 1) |
|
||||
(drop_mask2 << 2) |
|
||||
(drop_mask3 << 3);
|
||||
}
|
||||
|
||||
static __rte_always_inline int
|
||||
@ -298,6 +903,9 @@ ah(struct rte_pipeline *p,
|
||||
uint64_t pkts_drop_mask = 0;
|
||||
uint64_t time = 0;
|
||||
|
||||
if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR))
|
||||
time = rte_rdtsc();
|
||||
|
||||
if ((pkts_mask & (pkts_mask + 1)) == 0) {
|
||||
uint64_t n_pkts = __builtin_popcountll(pkts_mask);
|
||||
uint32_t i;
|
||||
|
@ -59,6 +59,7 @@ extern "C" {
|
||||
#include <stdint.h>
|
||||
|
||||
#include <rte_compat.h>
|
||||
#include <rte_meter.h>
|
||||
|
||||
#include "rte_pipeline.h"
|
||||
|
||||
@ -66,6 +67,9 @@ extern "C" {
|
||||
enum rte_table_action_type {
|
||||
/** Forward to next pipeline table, output port or drop. */
|
||||
RTE_TABLE_ACTION_FWD = 0,
|
||||
|
||||
/** Traffic Metering and Policing. */
|
||||
RTE_TABLE_ACTION_MTR,
|
||||
};
|
||||
|
||||
/** Common action configuration (per table action profile). */
|
||||
@ -93,6 +97,164 @@ struct rte_table_action_fwd_params {
|
||||
uint32_t id;
|
||||
};
|
||||
|
||||
/**
|
||||
* RTE_TABLE_ACTION_MTR
|
||||
*/
|
||||
/** Max number of traffic classes (TCs). */
|
||||
#define RTE_TABLE_ACTION_TC_MAX 4
|
||||
|
||||
/** Max number of queues per traffic class. */
|
||||
#define RTE_TABLE_ACTION_TC_QUEUE_MAX 4
|
||||
|
||||
/** Differentiated Services Code Point (DSCP) translation table entry. */
|
||||
struct rte_table_action_dscp_table_entry {
|
||||
/** Traffic class. Used by the meter or the traffic management actions.
|
||||
* Has to be strictly smaller than *RTE_TABLE_ACTION_TC_MAX*. Traffic
|
||||
* class 0 is the highest priority.
|
||||
*/
|
||||
uint32_t tc_id;
|
||||
|
||||
/** Traffic class queue. Used by the traffic management action. Has to
|
||||
* be strictly smaller than *RTE_TABLE_ACTION_TC_QUEUE_MAX*.
|
||||
*/
|
||||
uint32_t tc_queue_id;
|
||||
|
||||
/** Packet color. Used by the meter action as the packet input color
|
||||
* for the color aware mode of the traffic metering algorithm.
|
||||
*/
|
||||
enum rte_meter_color color;
|
||||
};
|
||||
|
||||
/** DSCP translation table. */
|
||||
struct rte_table_action_dscp_table {
|
||||
/** Array of DSCP table entries */
|
||||
struct rte_table_action_dscp_table_entry entry[64];
|
||||
};
|
||||
|
||||
/** Supported traffic metering algorithms. */
|
||||
enum rte_table_action_meter_algorithm {
|
||||
/** Single Rate Three Color Marker (srTCM) - IETF RFC 2697. */
|
||||
RTE_TABLE_ACTION_METER_SRTCM,
|
||||
|
||||
/** Two Rate Three Color Marker (trTCM) - IETF RFC 2698. */
|
||||
RTE_TABLE_ACTION_METER_TRTCM,
|
||||
};
|
||||
|
||||
/** Traffic metering profile (configuration template). */
|
||||
struct rte_table_action_meter_profile {
|
||||
/** Traffic metering algorithm. */
|
||||
enum rte_table_action_meter_algorithm alg;
|
||||
|
||||
RTE_STD_C11
|
||||
union {
|
||||
/** Only valid when *alg* is set to srTCM - IETF RFC 2697. */
|
||||
struct rte_meter_srtcm_params srtcm;
|
||||
|
||||
/** Only valid when *alg* is set to trTCM - IETF RFC 2698. */
|
||||
struct rte_meter_trtcm_params trtcm;
|
||||
};
|
||||
};
|
||||
|
||||
/** Policer actions. */
|
||||
enum rte_table_action_policer {
|
||||
/** Recolor the packet as green. */
|
||||
RTE_TABLE_ACTION_POLICER_COLOR_GREEN = 0,
|
||||
|
||||
/** Recolor the packet as yellow. */
|
||||
RTE_TABLE_ACTION_POLICER_COLOR_YELLOW,
|
||||
|
||||
/** Recolor the packet as red. */
|
||||
RTE_TABLE_ACTION_POLICER_COLOR_RED,
|
||||
|
||||
/** Drop the packet. */
|
||||
RTE_TABLE_ACTION_POLICER_DROP,
|
||||
|
||||
/** Number of policer actions. */
|
||||
RTE_TABLE_ACTION_POLICER_MAX
|
||||
};
|
||||
|
||||
/** Meter action configuration per traffic class. */
|
||||
struct rte_table_action_mtr_tc_params {
|
||||
/** Meter profile ID. */
|
||||
uint32_t meter_profile_id;
|
||||
|
||||
/** Policer actions. */
|
||||
enum rte_table_action_policer policer[e_RTE_METER_COLORS];
|
||||
};
|
||||
|
||||
/** Meter action statistics counters per traffic class. */
|
||||
struct rte_table_action_mtr_counters_tc {
|
||||
/** Number of packets per color at the output of the traffic metering
|
||||
* and before the policer actions are executed. Only valid when
|
||||
* *n_packets_valid* is non-zero.
|
||||
*/
|
||||
uint64_t n_packets[e_RTE_METER_COLORS];
|
||||
|
||||
/** Number of packet bytes per color at the output of the traffic
|
||||
* metering and before the policer actions are executed. Only valid when
|
||||
* *n_bytes_valid* is non-zero.
|
||||
*/
|
||||
uint64_t n_bytes[e_RTE_METER_COLORS];
|
||||
|
||||
/** When non-zero, the *n_packets* field is valid. */
|
||||
int n_packets_valid;
|
||||
|
||||
/** When non-zero, the *n_bytes* field is valid. */
|
||||
int n_bytes_valid;
|
||||
};
|
||||
|
||||
/** Meter action configuration (per table action profile). */
|
||||
struct rte_table_action_mtr_config {
|
||||
/** Meter algorithm. */
|
||||
enum rte_table_action_meter_algorithm alg;
|
||||
|
||||
/** Number of traffic classes. Each traffic class has its own traffic
|
||||
* meter and policer instances. Needs to be equal to either 1 or to
|
||||
* *RTE_TABLE_ACTION_TC_MAX*.
|
||||
*/
|
||||
uint32_t n_tc;
|
||||
|
||||
/** When non-zero, the *n_packets* meter stats counter is enabled,
|
||||
* otherwise it is disabled.
|
||||
*
|
||||
* @see struct rte_table_action_mtr_counters_tc
|
||||
*/
|
||||
int n_packets_enabled;
|
||||
|
||||
/** When non-zero, the *n_bytes* meter stats counter is enabled,
|
||||
* otherwise it is disabled.
|
||||
*
|
||||
* @see struct rte_table_action_mtr_counters_tc
|
||||
*/
|
||||
int n_bytes_enabled;
|
||||
};
|
||||
|
||||
/** Meter action parameters (per table rule). */
|
||||
struct rte_table_action_mtr_params {
|
||||
/** Traffic meter and policer parameters for each of the *tc_mask*
|
||||
* traffic classes.
|
||||
*/
|
||||
struct rte_table_action_mtr_tc_params mtr[RTE_TABLE_ACTION_TC_MAX];
|
||||
|
||||
/** Bit mask defining which traffic class parameters are valid in *mtr*.
|
||||
* If bit N is set in *tc_mask*, then parameters for traffic class N are
|
||||
* valid in *mtr*.
|
||||
*/
|
||||
uint32_t tc_mask;
|
||||
};
|
||||
|
||||
/** Meter action statistics counters (per table rule). */
|
||||
struct rte_table_action_mtr_counters {
|
||||
/** Stats counters for each of the *tc_mask* traffic classes. */
|
||||
struct rte_table_action_mtr_counters_tc stats[RTE_TABLE_ACTION_TC_MAX];
|
||||
|
||||
/** Bit mask defining which traffic class parameters are valid in *mtr*.
|
||||
* If bit N is set in *tc_mask*, then parameters for traffic class N are
|
||||
* valid in *mtr*.
|
||||
*/
|
||||
uint32_t tc_mask;
|
||||
};
|
||||
|
||||
/**
|
||||
* Table action profile.
|
||||
*/
|
||||
@ -231,6 +393,92 @@ rte_table_action_apply(struct rte_table_action *action,
|
||||
enum rte_table_action_type type,
|
||||
void *action_params);
|
||||
|
||||
/**
|
||||
* Table action DSCP table update.
|
||||
*
|
||||
* @param[in] action
|
||||
* Handle to table action object (needs to be valid).
|
||||
* @param[in] dscp_mask
|
||||
* 64-bit mask defining the DSCP table entries to be updated. If bit N is set
|
||||
* in this bit mask, then DSCP table entry N is to be updated, otherwise not.
|
||||
* @param[in] table
|
||||
* DSCP table.
|
||||
* @return
|
||||
* Zero on success, non-zero error code otherwise.
|
||||
*/
|
||||
int __rte_experimental
|
||||
rte_table_action_dscp_table_update(struct rte_table_action *action,
|
||||
uint64_t dscp_mask,
|
||||
struct rte_table_action_dscp_table *table);
|
||||
|
||||
/**
|
||||
* Table action meter profile add.
|
||||
*
|
||||
* @param[in] action
|
||||
* Handle to table action object (needs to be valid).
|
||||
* @param[in] meter_profile_id
|
||||
* Meter profile ID to be used for the *profile* once it is successfully added
|
||||
* to the *action* object (needs to be unused by the set of meter profiles
|
||||
* currently registered for the *action* object).
|
||||
* @param[in] profile
|
||||
* Meter profile to be added.
|
||||
* @return
|
||||
* Zero on success, non-zero error code otherwise.
|
||||
*/
|
||||
int __rte_experimental
|
||||
rte_table_action_meter_profile_add(struct rte_table_action *action,
|
||||
uint32_t meter_profile_id,
|
||||
struct rte_table_action_meter_profile *profile);
|
||||
|
||||
/**
|
||||
* Table action meter profile delete.
|
||||
*
|
||||
* @param[in] action
|
||||
* Handle to table action object (needs to be valid).
|
||||
* @param[in] meter_profile_id
|
||||
* Meter profile ID of the meter profile to be deleted from the *action*
|
||||
* object (needs to be valid for the *action* object).
|
||||
* @return
|
||||
* Zero on success, non-zero error code otherwise.
|
||||
*/
|
||||
int __rte_experimental
|
||||
rte_table_action_meter_profile_delete(struct rte_table_action *action,
|
||||
uint32_t meter_profile_id);
|
||||
|
||||
/**
|
||||
* Table action meter read.
|
||||
*
|
||||
* @param[in] action
|
||||
* Handle to table action object (needs to be valid).
|
||||
* @param[in] data
|
||||
* Data byte array (typically table rule data) with meter action previously
|
||||
* applied on it.
|
||||
* @param[in] tc_mask
|
||||
* Bit mask defining which traffic classes should have the meter stats
|
||||
* counters read from *data* and stored into *stats*. If bit N is set in this
|
||||
* bit mask, then traffic class N is part of this operation, otherwise it is
|
||||
* not. If bit N is set in this bit mask, then traffic class N must be one of
|
||||
* the traffic classes that are enabled for the meter action in the table
|
||||
* action profile used by the *action* object.
|
||||
* @param[inout] stats
|
||||
* When non-NULL, it points to the area where the meter stats counters read
|
||||
* from *data* are saved. Only the meter stats counters for the *tc_mask*
|
||||
* traffic classes are read and stored to *stats*.
|
||||
* @param[in] clear
|
||||
* When non-zero, the meter stats counters are cleared (i.e. set to zero),
|
||||
* otherwise the counters are not modified. When the read operation is enabled
|
||||
* (*stats* is non-NULL), the clear operation is performed after the read
|
||||
* operation is completed.
|
||||
* @return
|
||||
* Zero on success, non-zero error code otherwise.
|
||||
*/
|
||||
int __rte_experimental
|
||||
rte_table_action_meter_read(struct rte_table_action *action,
|
||||
void *data,
|
||||
uint32_t tc_mask,
|
||||
struct rte_table_action_mtr_counters *stats,
|
||||
int clear);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user