pipeline: add meter array to SWX
Meter arrays are stateful objects that are updated by the data plane and configured & monitored by the control plane. The meters implement the RFC 2698 Two Rate Three Color Marker (trTCM) algorithm. Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
This commit is contained in:
parent
64cfcebd68
commit
f38913b7fb
@ -1355,6 +1355,398 @@ cmd_pipeline_regwr(char **tokens,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char cmd_pipeline_meter_profile_add_help[] =
|
||||||
|
"pipeline <pipeline_name> meter profile <profile_name> add "
|
||||||
|
"cir <cir> pir <pir> cbs <cbs> pbs <pbs>\n";
|
||||||
|
|
||||||
|
static void
|
||||||
|
cmd_pipeline_meter_profile_add(char **tokens,
|
||||||
|
uint32_t n_tokens,
|
||||||
|
char *out,
|
||||||
|
size_t out_size,
|
||||||
|
void *obj)
|
||||||
|
{
|
||||||
|
struct rte_meter_trtcm_params params;
|
||||||
|
struct pipeline *p;
|
||||||
|
const char *profile_name;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
if (n_tokens != 14) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = pipeline_find(obj, tokens[1]);
|
||||||
|
if (!p || !p->ctl) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(tokens[2], "meter")) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(tokens[3], "profile")) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
profile_name = tokens[4];
|
||||||
|
|
||||||
|
if (strcmp(tokens[5], "add")) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(tokens[6], "cir")) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parser_read_uint64(¶ms.cir, tokens[7])) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_INVALID, "cir");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(tokens[8], "pir")) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pir");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parser_read_uint64(¶ms.pir, tokens[9])) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_INVALID, "pir");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(tokens[10], "cbs")) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parser_read_uint64(¶ms.cbs, tokens[11])) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(tokens[12], "pbs")) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pbs");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parser_read_uint64(¶ms.pbs, tokens[13])) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_INVALID, "pbs");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = rte_swx_ctl_meter_profile_add(p->p, profile_name, ¶ms);
|
||||||
|
if (status) {
|
||||||
|
snprintf(out, out_size, "Command failed.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char cmd_pipeline_meter_profile_delete_help[] =
|
||||||
|
"pipeline <pipeline_name> meter profile <profile_name> delete\n";
|
||||||
|
|
||||||
|
static void
|
||||||
|
cmd_pipeline_meter_profile_delete(char **tokens,
|
||||||
|
uint32_t n_tokens,
|
||||||
|
char *out,
|
||||||
|
size_t out_size,
|
||||||
|
void *obj)
|
||||||
|
{
|
||||||
|
struct pipeline *p;
|
||||||
|
const char *profile_name;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
if (n_tokens != 6) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = pipeline_find(obj, tokens[1]);
|
||||||
|
if (!p || !p->ctl) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(tokens[2], "meter")) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(tokens[3], "profile")) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
profile_name = tokens[4];
|
||||||
|
|
||||||
|
if (strcmp(tokens[5], "delete")) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = rte_swx_ctl_meter_profile_delete(p->p, profile_name);
|
||||||
|
if (status) {
|
||||||
|
snprintf(out, out_size, "Command failed.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char cmd_pipeline_meter_reset_help[] =
|
||||||
|
"pipeline <pipeline_name> meter <meter_array_name> from <index0> to <index1> "
|
||||||
|
"reset\n";
|
||||||
|
|
||||||
|
static void
|
||||||
|
cmd_pipeline_meter_reset(char **tokens,
|
||||||
|
uint32_t n_tokens,
|
||||||
|
char *out,
|
||||||
|
size_t out_size,
|
||||||
|
void *obj)
|
||||||
|
{
|
||||||
|
struct pipeline *p;
|
||||||
|
const char *name;
|
||||||
|
uint32_t idx0, idx1;
|
||||||
|
|
||||||
|
if (n_tokens != 9) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = pipeline_find(obj, tokens[1]);
|
||||||
|
if (!p || !p->ctl) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(tokens[2], "meter")) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = tokens[3];
|
||||||
|
|
||||||
|
if (strcmp(tokens[4], "from")) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parser_read_uint32(&idx0, tokens[5])) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_INVALID, "index0");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(tokens[6], "to")) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parser_read_uint32(&idx1, tokens[7]) || (idx1 < idx0)) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_INVALID, "index1");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(tokens[8], "reset")) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_NOT_FOUND, "reset");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( ; idx0 <= idx1; idx0++) {
|
||||||
|
int status;
|
||||||
|
|
||||||
|
status = rte_swx_ctl_meter_reset(p->p, name, idx0);
|
||||||
|
if (status) {
|
||||||
|
snprintf(out, out_size, "Command failed for index %u.\n", idx0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char cmd_pipeline_meter_set_help[] =
|
||||||
|
"pipeline <pipeline_name> meter <meter_array_name> from <index0> to <index1> "
|
||||||
|
"set profile <profile_name>\n";
|
||||||
|
|
||||||
|
static void
|
||||||
|
cmd_pipeline_meter_set(char **tokens,
|
||||||
|
uint32_t n_tokens,
|
||||||
|
char *out,
|
||||||
|
size_t out_size,
|
||||||
|
void *obj)
|
||||||
|
{
|
||||||
|
struct pipeline *p;
|
||||||
|
const char *name, *profile_name;
|
||||||
|
uint32_t idx0, idx1;
|
||||||
|
|
||||||
|
if (n_tokens != 11) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = pipeline_find(obj, tokens[1]);
|
||||||
|
if (!p || !p->ctl) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(tokens[2], "meter")) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = tokens[3];
|
||||||
|
|
||||||
|
if (strcmp(tokens[4], "from")) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parser_read_uint32(&idx0, tokens[5])) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_INVALID, "index0");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(tokens[6], "to")) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parser_read_uint32(&idx1, tokens[7]) || (idx1 < idx0)) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_INVALID, "index1");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(tokens[8], "set")) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_NOT_FOUND, "set");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(tokens[9], "profile")) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
profile_name = tokens[10];
|
||||||
|
|
||||||
|
for ( ; idx0 <= idx1; idx0++) {
|
||||||
|
int status;
|
||||||
|
|
||||||
|
status = rte_swx_ctl_meter_set(p->p, name, idx0, profile_name);
|
||||||
|
if (status) {
|
||||||
|
snprintf(out, out_size, "Command failed for index %u.\n", idx0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char cmd_pipeline_meter_stats_help[] =
|
||||||
|
"pipeline <pipeline_name> meter <meter_array_name> from <index0> to <index1> "
|
||||||
|
"stats\n";
|
||||||
|
|
||||||
|
static void
|
||||||
|
cmd_pipeline_meter_stats(char **tokens,
|
||||||
|
uint32_t n_tokens,
|
||||||
|
char *out,
|
||||||
|
size_t out_size,
|
||||||
|
void *obj)
|
||||||
|
{
|
||||||
|
struct rte_swx_ctl_meter_stats stats;
|
||||||
|
struct pipeline *p;
|
||||||
|
const char *name;
|
||||||
|
uint32_t idx0, idx1;
|
||||||
|
|
||||||
|
if (n_tokens != 9) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = pipeline_find(obj, tokens[1]);
|
||||||
|
if (!p || !p->ctl) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(tokens[2], "meter")) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = tokens[3];
|
||||||
|
|
||||||
|
if (strcmp(tokens[4], "from")) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parser_read_uint32(&idx0, tokens[5])) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_INVALID, "index0");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(tokens[6], "to")) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parser_read_uint32(&idx1, tokens[7]) || (idx1 < idx0)) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_INVALID, "index1");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(tokens[8], "stats")) {
|
||||||
|
snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Table header. */
|
||||||
|
snprintf(out, out_size, "+-%7s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+\n",
|
||||||
|
"-------",
|
||||||
|
"----------------", "----------------", "----------------",
|
||||||
|
"----------------", "----------------", "----------------");
|
||||||
|
out_size -= strlen(out);
|
||||||
|
out += strlen(out);
|
||||||
|
|
||||||
|
snprintf(out, out_size, "| %4s | %16s | %16s | %16s | %16s | %16s | %16s |\n",
|
||||||
|
"METER #",
|
||||||
|
"GREEN (packets)", "YELLOW (packets)", "RED (packets)",
|
||||||
|
"GREEN (bytes)", "YELLOW (bytes)", "RED (bytes)");
|
||||||
|
out_size -= strlen(out);
|
||||||
|
out += strlen(out);
|
||||||
|
|
||||||
|
snprintf(out, out_size, "+-%7s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+\n",
|
||||||
|
"-------",
|
||||||
|
"----------------", "----------------", "----------------",
|
||||||
|
"----------------", "----------------", "----------------");
|
||||||
|
out_size -= strlen(out);
|
||||||
|
out += strlen(out);
|
||||||
|
|
||||||
|
/* Table rows. */
|
||||||
|
for ( ; idx0 <= idx1; idx0++) {
|
||||||
|
int status;
|
||||||
|
|
||||||
|
status = rte_swx_ctl_meter_stats_read(p->p, name, idx0, &stats);
|
||||||
|
if (status) {
|
||||||
|
snprintf(out, out_size, "Pipeline meter stats error at index %u.\n", idx0);
|
||||||
|
out_size -= strlen(out);
|
||||||
|
out += strlen(out);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(out, out_size, "| %7d | %16" PRIx64 " | %16" PRIx64 " | %16" PRIx64
|
||||||
|
" | %16" PRIx64 " | %16" PRIx64 " | %16" PRIx64 " |\n",
|
||||||
|
idx0,
|
||||||
|
stats.n_pkts[RTE_COLOR_GREEN],
|
||||||
|
stats.n_pkts[RTE_COLOR_YELLOW],
|
||||||
|
stats.n_pkts[RTE_COLOR_RED],
|
||||||
|
stats.n_bytes[RTE_COLOR_GREEN],
|
||||||
|
stats.n_bytes[RTE_COLOR_YELLOW],
|
||||||
|
stats.n_bytes[RTE_COLOR_RED]);
|
||||||
|
out_size -= strlen(out);
|
||||||
|
out += strlen(out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static const char cmd_pipeline_stats_help[] =
|
static const char cmd_pipeline_stats_help[] =
|
||||||
"pipeline <pipeline_name> stats\n";
|
"pipeline <pipeline_name> stats\n";
|
||||||
|
|
||||||
@ -1551,6 +1943,11 @@ cmd_help(char **tokens,
|
|||||||
"\tpipeline table update\n"
|
"\tpipeline table update\n"
|
||||||
"\tpipeline regrd\n"
|
"\tpipeline regrd\n"
|
||||||
"\tpipeline regwr\n"
|
"\tpipeline regwr\n"
|
||||||
|
"\tpipeline meter profile add\n"
|
||||||
|
"\tpipeline meter profile delete\n"
|
||||||
|
"\tpipeline meter reset\n"
|
||||||
|
"\tpipeline meter set\n"
|
||||||
|
"\tpipeline meter stats\n"
|
||||||
"\tpipeline stats\n"
|
"\tpipeline stats\n"
|
||||||
"\tthread pipeline enable\n"
|
"\tthread pipeline enable\n"
|
||||||
"\tthread pipeline disable\n\n");
|
"\tthread pipeline disable\n\n");
|
||||||
@ -1625,6 +2022,43 @@ cmd_help(char **tokens,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!strcmp(tokens[0], "pipeline") &&
|
||||||
|
(n_tokens == 4) && !strcmp(tokens[1], "meter")
|
||||||
|
&& !strcmp(tokens[2], "profile")
|
||||||
|
&& !strcmp(tokens[3], "add")) {
|
||||||
|
snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_profile_add_help);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(tokens[0], "pipeline") &&
|
||||||
|
(n_tokens == 4) && !strcmp(tokens[1], "meter")
|
||||||
|
&& !strcmp(tokens[2], "profile")
|
||||||
|
&& !strcmp(tokens[3], "delete")) {
|
||||||
|
snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_profile_delete_help);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(tokens[0], "pipeline") &&
|
||||||
|
(n_tokens == 3) && !strcmp(tokens[1], "meter")
|
||||||
|
&& !strcmp(tokens[2], "reset")) {
|
||||||
|
snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_reset_help);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(tokens[0], "pipeline") &&
|
||||||
|
(n_tokens == 3) && !strcmp(tokens[1], "meter")
|
||||||
|
&& !strcmp(tokens[2], "set")) {
|
||||||
|
snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_set_help);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(tokens[0], "pipeline") &&
|
||||||
|
(n_tokens == 3) && !strcmp(tokens[1], "meter")
|
||||||
|
&& !strcmp(tokens[2], "stats")) {
|
||||||
|
snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_stats_help);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ((strcmp(tokens[0], "pipeline") == 0) &&
|
if ((strcmp(tokens[0], "pipeline") == 0) &&
|
||||||
(n_tokens == 2) && (strcmp(tokens[1], "stats") == 0)) {
|
(n_tokens == 2) && (strcmp(tokens[1], "stats") == 0)) {
|
||||||
snprintf(out, out_size, "\n%s\n", cmd_pipeline_stats_help);
|
snprintf(out, out_size, "\n%s\n", cmd_pipeline_stats_help);
|
||||||
@ -1749,6 +2183,43 @@ cli_process(char *in, char *out, size_t out_size, void *obj)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((n_tokens >= 6) &&
|
||||||
|
(strcmp(tokens[2], "meter") == 0) &&
|
||||||
|
(strcmp(tokens[3], "profile") == 0) &&
|
||||||
|
(strcmp(tokens[5], "add") == 0)) {
|
||||||
|
cmd_pipeline_meter_profile_add(tokens, n_tokens, out, out_size, obj);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((n_tokens >= 6) &&
|
||||||
|
(strcmp(tokens[2], "meter") == 0) &&
|
||||||
|
(strcmp(tokens[3], "profile") == 0) &&
|
||||||
|
(strcmp(tokens[5], "delete") == 0)) {
|
||||||
|
cmd_pipeline_meter_profile_delete(tokens, n_tokens, out, out_size, obj);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((n_tokens >= 9) &&
|
||||||
|
(strcmp(tokens[2], "meter") == 0) &&
|
||||||
|
(strcmp(tokens[8], "reset") == 0)) {
|
||||||
|
cmd_pipeline_meter_reset(tokens, n_tokens, out, out_size, obj);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((n_tokens >= 9) &&
|
||||||
|
(strcmp(tokens[2], "meter") == 0) &&
|
||||||
|
(strcmp(tokens[8], "set") == 0)) {
|
||||||
|
cmd_pipeline_meter_set(tokens, n_tokens, out, out_size, obj);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((n_tokens >= 9) &&
|
||||||
|
(strcmp(tokens[2], "meter") == 0) &&
|
||||||
|
(strcmp(tokens[8], "stats") == 0)) {
|
||||||
|
cmd_pipeline_meter_stats(tokens, n_tokens, out, out_size, obj);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ((n_tokens >= 3) &&
|
if ((n_tokens >= 3) &&
|
||||||
(strcmp(tokens[2], "stats") == 0)) {
|
(strcmp(tokens[2], "stats") == 0)) {
|
||||||
cmd_pipeline_stats(tokens, n_tokens, out, out_size,
|
cmd_pipeline_stats(tokens, n_tokens, out, out_size,
|
||||||
|
31
examples/pipeline/examples/meter.cli
Normal file
31
examples/pipeline/examples/meter.cli
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
; SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
; Copyright(c) 2020 Intel Corporation
|
||||||
|
|
||||||
|
; Example command line:
|
||||||
|
; ./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/meter.cli
|
||||||
|
|
||||||
|
mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
|
||||||
|
|
||||||
|
link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
|
||||||
|
link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
|
||||||
|
link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
|
||||||
|
link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
|
||||||
|
|
||||||
|
pipeline PIPELINE0 create 0
|
||||||
|
|
||||||
|
pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
|
||||||
|
pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
|
||||||
|
pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
|
||||||
|
pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
|
||||||
|
|
||||||
|
pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
|
||||||
|
pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
|
||||||
|
pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
|
||||||
|
pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
|
||||||
|
|
||||||
|
pipeline PIPELINE0 build ./examples/pipeline/examples/meter.spec
|
||||||
|
|
||||||
|
pipeline PIPELINE0 meter profile platinum add cir 46000000 pir 138000000 cbs 1000000 pbs 1000000
|
||||||
|
pipeline PIPELINE0 meter meters from 0 to 15 set profile platinum
|
||||||
|
|
||||||
|
thread 1 pipeline PIPELINE0 enable
|
63
examples/pipeline/examples/meter.spec
Normal file
63
examples/pipeline/examples/meter.spec
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
; SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
; Copyright(c) 2021 Intel Corporation
|
||||||
|
|
||||||
|
; This program is setting up an array of Two Rate Three Color Marker (trTCM) meters called "meters".
|
||||||
|
; Every input packet (Ethernet/IPv4) is metered by the meter at the location indexed by the IPv4
|
||||||
|
; header "Source Address" field. All green packets are sent out on port 0, the yellow ones on port 1
|
||||||
|
; and the red ones on port 2.
|
||||||
|
;
|
||||||
|
; The "meter stats" CLI command can be used to read the packet and byte statistics counters of any
|
||||||
|
; meter in the array.
|
||||||
|
|
||||||
|
//
|
||||||
|
// Headers.
|
||||||
|
//
|
||||||
|
struct ethernet_h {
|
||||||
|
bit<48> dst_addr
|
||||||
|
bit<48> src_addr
|
||||||
|
bit<16> ethertype
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ipv4_h {
|
||||||
|
bit<8> ver_ihl
|
||||||
|
bit<8> diffserv
|
||||||
|
bit<16> total_len
|
||||||
|
bit<16> identification
|
||||||
|
bit<16> flags_offset
|
||||||
|
bit<8> ttl
|
||||||
|
bit<8> protocol
|
||||||
|
bit<16> hdr_checksum
|
||||||
|
bit<32> src_addr
|
||||||
|
bit<32> dst_addr
|
||||||
|
}
|
||||||
|
|
||||||
|
header ethernet instanceof ethernet_h
|
||||||
|
header ipv4 instanceof ipv4_h
|
||||||
|
|
||||||
|
//
|
||||||
|
// Meta-data.
|
||||||
|
//
|
||||||
|
struct metadata_t {
|
||||||
|
bit<32> port_in
|
||||||
|
bit<32> port_out
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata instanceof metadata_t
|
||||||
|
|
||||||
|
//
|
||||||
|
// Registers.
|
||||||
|
//
|
||||||
|
metarray meters size 65536
|
||||||
|
|
||||||
|
//
|
||||||
|
// Pipeline.
|
||||||
|
//
|
||||||
|
apply {
|
||||||
|
rx m.port_in
|
||||||
|
extract h.ethernet
|
||||||
|
extract h.ipv4
|
||||||
|
meter meters h.ipv4.src_addr h.ipv4.total_len 0 m.port_out
|
||||||
|
emit h.ethernet
|
||||||
|
emit h.ipv4
|
||||||
|
tx m.port_out
|
||||||
|
}
|
@ -18,6 +18,7 @@ extern "C" {
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <rte_compat.h>
|
#include <rte_compat.h>
|
||||||
|
#include <rte_meter.h>
|
||||||
|
|
||||||
#include "rte_swx_port.h"
|
#include "rte_swx_port.h"
|
||||||
#include "rte_swx_table.h"
|
#include "rte_swx_table.h"
|
||||||
@ -49,6 +50,9 @@ struct rte_swx_ctl_pipeline_info {
|
|||||||
|
|
||||||
/** Number of register arrays. */
|
/** Number of register arrays. */
|
||||||
uint32_t n_regarrays;
|
uint32_t n_regarrays;
|
||||||
|
|
||||||
|
/** Number of meter arrays. */
|
||||||
|
uint32_t n_metarrays;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -636,6 +640,157 @@ rte_swx_ctl_pipeline_regarray_write(struct rte_swx_pipeline *p,
|
|||||||
uint32_t regarray_index,
|
uint32_t regarray_index,
|
||||||
uint64_t value);
|
uint64_t value);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Meter Array Query and Configuration API.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Meter array info. */
|
||||||
|
struct rte_swx_ctl_metarray_info {
|
||||||
|
/** Meter array name. */
|
||||||
|
char name[RTE_SWX_CTL_NAME_SIZE];
|
||||||
|
|
||||||
|
/** Meter array size. */
|
||||||
|
uint32_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Meter array info get
|
||||||
|
*
|
||||||
|
* @param[in] p
|
||||||
|
* Pipeline handle.
|
||||||
|
* @param[in] metarray_id
|
||||||
|
* Meter array ID (0 .. *n_metarrays* - 1).
|
||||||
|
* @param[out] metarray
|
||||||
|
* Meter array info.
|
||||||
|
* @return
|
||||||
|
* 0 on success or the following error codes otherwise:
|
||||||
|
* -EINVAL: Invalid argument.
|
||||||
|
*/
|
||||||
|
__rte_experimental
|
||||||
|
int
|
||||||
|
rte_swx_ctl_metarray_info_get(struct rte_swx_pipeline *p,
|
||||||
|
uint32_t metarray_id,
|
||||||
|
struct rte_swx_ctl_metarray_info *metarray);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Meter profile add
|
||||||
|
*
|
||||||
|
* @param[in] p
|
||||||
|
* Pipeline handle.
|
||||||
|
* @param[in] name
|
||||||
|
* Meter profile name.
|
||||||
|
* @param[in] params
|
||||||
|
* Meter profile parameters.
|
||||||
|
* @return
|
||||||
|
* 0 on success or the following error codes otherwise:
|
||||||
|
* -EINVAL: Invalid argument;
|
||||||
|
* -ENOMEM: Not enough space/cannot allocate memory;
|
||||||
|
* -EEXIST: Meter profile with this name already exists.
|
||||||
|
*/
|
||||||
|
__rte_experimental
|
||||||
|
int
|
||||||
|
rte_swx_ctl_meter_profile_add(struct rte_swx_pipeline *p,
|
||||||
|
const char *name,
|
||||||
|
struct rte_meter_trtcm_params *params);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Meter profile delete
|
||||||
|
*
|
||||||
|
* @param[in] p
|
||||||
|
* Pipeline handle.
|
||||||
|
* @param[in] name
|
||||||
|
* Meter profile name.
|
||||||
|
* @return
|
||||||
|
* 0 on success or the following error codes otherwise:
|
||||||
|
* -EINVAL: Invalid argument;
|
||||||
|
* -EBUSY: Meter profile is currently in use.
|
||||||
|
*/
|
||||||
|
__rte_experimental
|
||||||
|
int
|
||||||
|
rte_swx_ctl_meter_profile_delete(struct rte_swx_pipeline *p,
|
||||||
|
const char *name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Meter reset
|
||||||
|
*
|
||||||
|
* Reset a meter within a given meter array to use the default profile that
|
||||||
|
* causes all the input packets to be colored as green. It is the responsibility
|
||||||
|
* of the control plane to make sure this meter is not used by the data plane
|
||||||
|
* pipeline before calling this function.
|
||||||
|
*
|
||||||
|
* @param[in] p
|
||||||
|
* Pipeline handle.
|
||||||
|
* @param[in] metarray_name
|
||||||
|
* Meter array name.
|
||||||
|
* @param[in] metarray_index
|
||||||
|
* Meter index within the meter array.
|
||||||
|
* @return
|
||||||
|
* 0 on success or the following error codes otherwise:
|
||||||
|
* -EINVAL: Invalid argument.
|
||||||
|
*/
|
||||||
|
__rte_experimental
|
||||||
|
int
|
||||||
|
rte_swx_ctl_meter_reset(struct rte_swx_pipeline *p,
|
||||||
|
const char *metarray_name,
|
||||||
|
uint32_t metarray_index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Meter set
|
||||||
|
*
|
||||||
|
* Set a meter within a given meter array to use a specific profile. It is the
|
||||||
|
* responsibility of the control plane to make sure this meter is not used by
|
||||||
|
* the data plane pipeline before calling this function.
|
||||||
|
*
|
||||||
|
* @param[in] p
|
||||||
|
* Pipeline handle.
|
||||||
|
* @param[in] metarray_name
|
||||||
|
* Meter array name.
|
||||||
|
* @param[in] metarray_index
|
||||||
|
* Meter index within the meter array.
|
||||||
|
* @param[in] profile_name
|
||||||
|
* Existing meter profile name.
|
||||||
|
* @return
|
||||||
|
* 0 on success or the following error codes otherwise:
|
||||||
|
* -EINVAL: Invalid argument.
|
||||||
|
*/
|
||||||
|
__rte_experimental
|
||||||
|
int
|
||||||
|
rte_swx_ctl_meter_set(struct rte_swx_pipeline *p,
|
||||||
|
const char *metarray_name,
|
||||||
|
uint32_t metarray_index,
|
||||||
|
const char *profile_name);
|
||||||
|
|
||||||
|
/** Meter statistics counters. */
|
||||||
|
struct rte_swx_ctl_meter_stats {
|
||||||
|
/** Number of packets tagged by the meter for each color. */
|
||||||
|
uint64_t n_pkts[RTE_COLORS];
|
||||||
|
|
||||||
|
/** Number of bytes tagged by the meter for each color. */
|
||||||
|
uint64_t n_bytes[RTE_COLORS];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Meter statistics counters read
|
||||||
|
*
|
||||||
|
* @param[in] p
|
||||||
|
* Pipeline handle.
|
||||||
|
* @param[in] metarray_name
|
||||||
|
* Meter array name.
|
||||||
|
* @param[in] metarray_index
|
||||||
|
* Meter index within the meter array.
|
||||||
|
* @param[out] stats
|
||||||
|
* Meter statistics counters.
|
||||||
|
* @return
|
||||||
|
* 0 on success or the following error codes otherwise:
|
||||||
|
* -EINVAL: Invalid argument.
|
||||||
|
*/
|
||||||
|
__rte_experimental
|
||||||
|
int
|
||||||
|
rte_swx_ctl_meter_stats_read(struct rte_swx_pipeline *p,
|
||||||
|
const char *metarray_name,
|
||||||
|
uint32_t metarray_index,
|
||||||
|
struct rte_swx_ctl_meter_stats *stats);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pipeline control free
|
* Pipeline control free
|
||||||
*
|
*
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -640,6 +640,28 @@ rte_swx_pipeline_regarray_config(struct rte_swx_pipeline *p,
|
|||||||
uint32_t size,
|
uint32_t size,
|
||||||
uint64_t init_val);
|
uint64_t init_val);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pipeline meter array configure
|
||||||
|
*
|
||||||
|
* @param[in] p
|
||||||
|
* Pipeline handle.
|
||||||
|
* @param[in] name
|
||||||
|
* Meter array name.
|
||||||
|
* @param[in] size
|
||||||
|
* Number of meters in the array. Each meter in the array implements the Two
|
||||||
|
* Rate Three Color Marker (trTCM) algorithm, as specified by RFC 2698.
|
||||||
|
* @return
|
||||||
|
* 0 on success or the following error codes otherwise:
|
||||||
|
* -EINVAL: Invalid argument;
|
||||||
|
* -ENOMEM: Not enough space/cannot allocate memory;
|
||||||
|
* -EEXIST: Meter array with this name already exists.
|
||||||
|
*/
|
||||||
|
__rte_experimental
|
||||||
|
int
|
||||||
|
rte_swx_pipeline_metarray_config(struct rte_swx_pipeline *p,
|
||||||
|
const char *name,
|
||||||
|
uint32_t size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pipeline instructions configure
|
* Pipeline instructions configure
|
||||||
*
|
*
|
||||||
|
@ -1015,6 +1015,68 @@ regarray_statement_parse(struct regarray_spec *s,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* metarray.
|
||||||
|
*
|
||||||
|
* metarray NAME size SIZE
|
||||||
|
*/
|
||||||
|
struct metarray_spec {
|
||||||
|
char *name;
|
||||||
|
uint32_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
metarray_spec_free(struct metarray_spec *s)
|
||||||
|
{
|
||||||
|
if (!s)
|
||||||
|
return;
|
||||||
|
|
||||||
|
free(s->name);
|
||||||
|
s->name = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
metarray_statement_parse(struct metarray_spec *s,
|
||||||
|
char **tokens,
|
||||||
|
uint32_t n_tokens,
|
||||||
|
uint32_t n_lines,
|
||||||
|
uint32_t *err_line,
|
||||||
|
const char **err_msg)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
/* Check format. */
|
||||||
|
if ((n_tokens != 4) || strcmp(tokens[2], "size")) {
|
||||||
|
if (err_line)
|
||||||
|
*err_line = n_lines;
|
||||||
|
if (err_msg)
|
||||||
|
*err_msg = "Invalid metarray statement.";
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* spec. */
|
||||||
|
s->name = strdup(tokens[1]);
|
||||||
|
if (!s->name) {
|
||||||
|
if (err_line)
|
||||||
|
*err_line = n_lines;
|
||||||
|
if (err_msg)
|
||||||
|
*err_msg = "Memory allocation failed.";
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = tokens[3];
|
||||||
|
s->size = strtoul(p, &p, 0);
|
||||||
|
if (p[0] || !s->size) {
|
||||||
|
if (err_line)
|
||||||
|
*err_line = n_lines;
|
||||||
|
if (err_msg)
|
||||||
|
*err_msg = "Invalid size argument.";
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* apply.
|
* apply.
|
||||||
*
|
*
|
||||||
@ -1142,6 +1204,7 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
|
|||||||
struct action_spec action_spec = {0};
|
struct action_spec action_spec = {0};
|
||||||
struct table_spec table_spec = {0};
|
struct table_spec table_spec = {0};
|
||||||
struct regarray_spec regarray_spec = {0};
|
struct regarray_spec regarray_spec = {0};
|
||||||
|
struct metarray_spec metarray_spec = {0};
|
||||||
struct apply_spec apply_spec = {0};
|
struct apply_spec apply_spec = {0};
|
||||||
uint32_t n_lines;
|
uint32_t n_lines;
|
||||||
uint32_t block_mask = 0;
|
uint32_t block_mask = 0;
|
||||||
@ -1509,6 +1572,33 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* metarray. */
|
||||||
|
if (!strcmp(tokens[0], "metarray")) {
|
||||||
|
status = metarray_statement_parse(&metarray_spec,
|
||||||
|
tokens,
|
||||||
|
n_tokens,
|
||||||
|
n_lines,
|
||||||
|
err_line,
|
||||||
|
err_msg);
|
||||||
|
if (status)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
status = rte_swx_pipeline_metarray_config(p,
|
||||||
|
metarray_spec.name,
|
||||||
|
metarray_spec.size);
|
||||||
|
if (status) {
|
||||||
|
if (err_line)
|
||||||
|
*err_line = n_lines;
|
||||||
|
if (err_msg)
|
||||||
|
*err_msg = "Meter array configuration error.";
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
metarray_spec_free(&metarray_spec);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* apply. */
|
/* apply. */
|
||||||
if (!strcmp(tokens[0], "apply")) {
|
if (!strcmp(tokens[0], "apply")) {
|
||||||
status = apply_statement_parse(&block_mask,
|
status = apply_statement_parse(&block_mask,
|
||||||
@ -1562,6 +1652,7 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
|
|||||||
action_spec_free(&action_spec);
|
action_spec_free(&action_spec);
|
||||||
table_spec_free(&table_spec);
|
table_spec_free(&table_spec);
|
||||||
regarray_spec_free(®array_spec);
|
regarray_spec_free(®array_spec);
|
||||||
|
metarray_spec_free(&metarray_spec);
|
||||||
apply_spec_free(&apply_spec);
|
apply_spec_free(&apply_spec);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -104,8 +104,15 @@ EXPERIMENTAL {
|
|||||||
rte_swx_pipeline_table_type_register;
|
rte_swx_pipeline_table_type_register;
|
||||||
|
|
||||||
#added in 21.05
|
#added in 21.05
|
||||||
|
rte_swx_ctl_metarray_info_get;
|
||||||
|
rte_swx_ctl_meter_profile_add;
|
||||||
|
rte_swx_ctl_meter_profile_delete;
|
||||||
|
rte_swx_ctl_meter_reset;
|
||||||
|
rte_swx_ctl_meter_set;
|
||||||
|
rte_swx_ctl_meter_stats_read;
|
||||||
rte_swx_ctl_pipeline_regarray_read;
|
rte_swx_ctl_pipeline_regarray_read;
|
||||||
rte_swx_ctl_pipeline_regarray_write;
|
rte_swx_ctl_pipeline_regarray_write;
|
||||||
rte_swx_ctl_regarray_info_get;
|
rte_swx_ctl_regarray_info_get;
|
||||||
|
rte_swx_pipeline_metarray_config;
|
||||||
rte_swx_pipeline_regarray_config;
|
rte_swx_pipeline_regarray_config;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user