pipeline: add traffic metering action

Add traffic metering action implementation.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
This commit is contained in:
Jasvinder Singh 2018-03-29 19:31:22 +01:00 committed by Cristian Dumitrescu
parent 406a2bc0c6
commit 7c9e5b9a12
5 changed files with 879 additions and 18 deletions

View File

@ -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

View File

@ -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']

View File

@ -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;

View File

@ -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;

View File

@ -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