@@ -263,6 +263,9 @@ static void cmd_help_long_parsed(void *parsed_result,
"set verbose (level)\n"
" Set the debug verbosity level X.\n\n"
+ "set event_verbose (bitmap)\n"
+ " Set the event debug verbose 32 bits bitmap X.\n\n"
+
"set log global|(type) (level)\n"
" Set the log level.\n\n"
@@ -1125,6 +1128,10 @@ static void cmd_help_long_parsed(void *parsed_result,
" Restrict ingress traffic to the defined"
" flow rules\n\n"
+ "flow aged {port_id} [destroy]\n"
+ " List and destroy aged flows"
+ " flow rules\n\n"
+
"set vxlan ip-version (ipv4|ipv6) vni (vni) udp-src"
" (udp-src) udp-dst (udp-dst) ip-src (ip-src) ip-dst"
" (ip-dst) eth-src (eth-src) eth-dst (eth-dst)\n"
@@ -19387,6 +19394,47 @@ cmdline_parse_inst_t cmd_showport_macs = {
},
};
+/* Set event verbose bitmap*/
+struct cmd_set_event_verbose_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t keyword;
+ uint32_t bitmap;
+};
+cmdline_parse_token_string_t cmd_set_event_verbose_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_event_verbose_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_set_event_verbose_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_event_verbose_result,
+ keyword, "event_verbose");
+cmdline_parse_token_num_t cmd_set_event_verbose_bitmap =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_event_verbose_result,
+ bitmap, UINT32);
+
+static void
+cmd_set_event_verbose_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_event_verbose_result *res = parsed_result;
+
+ printf("Change event verbose bitmap from 0x%x to 0x%x\n",
+ (unsigned int) event_verbose_bitmap,
+ (unsigned int) res->bitmap);
+ event_verbose_bitmap = res->bitmap;
+}
+
+cmdline_parse_inst_t cmd_set_event_verbose = {
+ .f = cmd_set_event_verbose_parsed,
+ .data = NULL,
+ .help_str = "set event_verbose (bitmap)",
+ .tokens = {
+ (void *)&cmd_set_event_verbose_set,
+ (void *)&cmd_set_event_verbose_keyword,
+ (void *)&cmd_set_event_verbose_bitmap,
+ NULL,
+ },
+};
+
/* ******************************************************************************** */
/* list of instructions */
@@ -19684,6 +19732,7 @@ cmdline_parse_ctx_t main_ctx[] = {
(cmdline_parse_inst_t *)&cmd_show_set_raw,
(cmdline_parse_inst_t *)&cmd_show_set_raw_all,
(cmdline_parse_inst_t *)&cmd_config_tx_dynf_specific,
+ (cmdline_parse_inst_t *)&cmd_set_event_verbose,
NULL,
};
@@ -67,6 +67,7 @@ enum index {
DUMP,
QUERY,
LIST,
+ AGED,
ISOLATE,
/* Destroy arguments. */
@@ -78,6 +79,9 @@ enum index {
/* List arguments. */
LIST_GROUP,
+ /* Destroy aged flow arguments. */
+ AGED_DESTROY,
+
/* Validate/create arguments. */
GROUP,
PRIORITY,
@@ -664,6 +668,9 @@ struct buffer {
struct {
int set;
} isolate; /**< Isolated mode arguments. */
+ struct {
+ int destroy;
+ } aged; /**< Aged arguments. */
} args; /**< Command arguments. */
};
@@ -719,6 +726,12 @@ static const enum index next_list_attr[] = {
ZERO,
};
+static const enum index next_aged_attr[] = {
+ AGED_DESTROY,
+ END,
+ ZERO,
+};
+
static const enum index item_param[] = {
ITEM_PARAM_IS,
ITEM_PARAM_SPEC,
@@ -1466,6 +1479,9 @@ static int parse_action(struct context *, const struct token *,
static int parse_list(struct context *, const struct token *,
const char *, unsigned int,
void *, unsigned int);
+static int parse_aged(struct context *, const struct token *,
+ const char *, unsigned int,
+ void *, unsigned int);
static int parse_isolate(struct context *, const struct token *,
const char *, unsigned int,
void *, unsigned int);
@@ -1649,6 +1665,7 @@ static const struct token token_list[] = {
FLUSH,
DUMP,
LIST,
+ AGED,
QUERY,
ISOLATE)),
.call = parse_init,
@@ -1708,6 +1725,13 @@ static const struct token token_list[] = {
.args = ARGS(ARGS_ENTRY(struct buffer, port)),
.call = parse_list,
},
+ [AGED] = {
+ .name = "aged",
+ .help = "list and destroy aged flows",
+ .next = NEXT(next_aged_attr, NEXT_ENTRY(PORT_ID)),
+ .args = ARGS(ARGS_ENTRY(struct buffer, port)),
+ .call = parse_aged,
+ },
[ISOLATE] = {
.name = "isolate",
.help = "restrict ingress traffic to the defined flow rules",
@@ -1741,6 +1765,12 @@ static const struct token token_list[] = {
.args = ARGS(ARGS_ENTRY_PTR(struct buffer, args.list.group)),
.call = parse_list,
},
+ [AGED_DESTROY] = {
+ .name = "destroy",
+ .help = "specify aged flows need be destroyed",
+ .call = parse_aged,
+ .comp = comp_none,
+ },
/* Validate/create attributes. */
[GROUP] = {
.name = "group",
@@ -5367,6 +5397,35 @@ parse_list(struct context *ctx, const struct token *token,
return len;
}
+/** Parse tokens for list all aged flows command. */
+static int
+parse_aged(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = buf;
+
+ /* Token name must match. */
+ if (parse_default(ctx, token, str, len, NULL, 0) < 0)
+ return -1;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return len;
+ if (!out->command) {
+ if (ctx->curr != AGED)
+ return -1;
+ if (sizeof(*out) > size)
+ return -1;
+ out->command = ctx->curr;
+ ctx->objdata = 0;
+ ctx->object = out;
+ ctx->objmask = NULL;
+ }
+ if (ctx->curr == AGED_DESTROY)
+ out->args.aged.destroy = 1;
+ return len;
+}
+
/** Parse tokens for isolate command. */
static int
parse_isolate(struct context *ctx, const struct token *token,
@@ -6367,6 +6426,9 @@ cmd_flow_parsed(const struct buffer *in)
case ISOLATE:
port_flow_isolate(in->port, in->args.isolate.set);
break;
+ case AGED:
+ port_flow_aged(in->port, in->args.aged.destroy);
+ break;
default:
break;
}
@@ -1367,6 +1367,26 @@ port_flow_validate(portid_t port_id,
return 0;
}
+/** Update age action context by port_flow pointer. */
+void
+update_age_action_context(const struct rte_flow_action *actions,
+ struct port_flow *pf)
+{
+ struct rte_flow_action_age *age = NULL;
+
+ for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
+ switch (actions->type) {
+ case RTE_FLOW_ACTION_TYPE_AGE:
+ age = (struct rte_flow_action_age *)
+ (uintptr_t)actions->conf;
+ age->context = pf;
+ return;
+ default:
+ break;
+ }
+ }
+}
+
/** Create flow rule. */
int
port_flow_create(portid_t port_id,
@@ -1377,28 +1397,27 @@ port_flow_create(portid_t port_id,
struct rte_flow *flow;
struct rte_port *port;
struct port_flow *pf;
- uint32_t id;
+ uint32_t id = 0;
struct rte_flow_error error;
- /* Poisoning to make sure PMDs update it in case of error. */
- memset(&error, 0x22, sizeof(error));
- flow = rte_flow_create(port_id, attr, pattern, actions, &error);
- if (!flow)
- return port_flow_complain(&error);
port = &ports[port_id];
if (port->flow_list) {
if (port->flow_list->id == UINT32_MAX) {
printf("Highest rule ID is already assigned, delete"
" it first");
- rte_flow_destroy(port_id, flow, NULL);
return -ENOMEM;
}
id = port->flow_list->id + 1;
- } else
- id = 0;
+ }
pf = port_flow_new(attr, pattern, actions, &error);
- if (!pf) {
- rte_flow_destroy(port_id, flow, NULL);
+ if (!pf)
+ return port_flow_complain(&error);
+ update_age_action_context(actions, pf);
+ /* Poisoning to make sure PMDs update it in case of error. */
+ memset(&error, 0x22, sizeof(error));
+ flow = rte_flow_create(port_id, attr, pattern, actions, &error);
+ if (!flow) {
+ free(pf);
return port_flow_complain(&error);
}
pf->next = port->flow_list;
@@ -1570,6 +1589,73 @@ port_flow_query(portid_t port_id, uint32_t rule,
return 0;
}
+/** List simply and destroy all aged flows. */
+void
+port_flow_aged(portid_t port_id, uint8_t destroy)
+{
+ void **contexts;
+ int nb_context, total = 0, idx;
+ struct rte_flow_error error;
+ struct port_flow *pf;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN) ||
+ port_id == (portid_t)RTE_PORT_ALL)
+ return;
+ total = rte_flow_get_aged_flows(port_id, NULL, 0, &error);
+ printf("Port %u total aged flows: %d\n", port_id, total);
+ if (total < 0) {
+ port_flow_complain(&error);
+ return;
+ }
+ if (total == 0)
+ return;
+ contexts = malloc(sizeof(void *) * total);
+ if (contexts == NULL) {
+ printf("Cannot allocate contexts for aged flow\n");
+ return;
+ }
+ printf("ID\tGroup\tPrio\tAttr\n");
+ nb_context = rte_flow_get_aged_flows(port_id, contexts, total, &error);
+ if (nb_context != total) {
+ printf("Port:%d get aged flows count(%d) != total(%d)\n",
+ port_id, nb_context, total);
+ free(contexts);
+ return;
+ }
+ for (idx = 0; idx < nb_context; idx++) {
+ pf = (struct port_flow *)contexts[idx];
+ if (!pf) {
+ printf("Error: get Null context in port %u\n", port_id);
+ continue;
+ }
+ printf("%" PRIu32 "\t%" PRIu32 "\t%" PRIu32 "\t%c%c%c\t\n",
+ pf->id,
+ pf->rule.attr->group,
+ pf->rule.attr->priority,
+ pf->rule.attr->ingress ? 'i' : '-',
+ pf->rule.attr->egress ? 'e' : '-',
+ pf->rule.attr->transfer ? 't' : '-');
+ }
+ if (destroy) {
+ int ret;
+ uint32_t flow_id;
+
+ total = 0;
+ printf("\n");
+ for (idx = 0; idx < nb_context; idx++) {
+ pf = (struct port_flow *)contexts[idx];
+ if (!pf)
+ continue;
+ flow_id = pf->id;
+ ret = port_flow_destroy(port_id, 1, &flow_id);
+ if (!ret)
+ total++;
+ }
+ printf("%d flows be destroyed\n", total);
+ }
+ free(contexts);
+}
+
/** List flow rules. */
void
port_flow_list(portid_t port_id, uint32_t n, const uint32_t group[n])
@@ -81,6 +81,7 @@
#define EXTBUF_ZONE_SIZE RTE_PGSIZE_2M
uint16_t verbose_level = 0; /**< Silent by default. */
+uint32_t event_verbose_bitmap; /**< Verbose bitmap for all events */
int testpmd_logtype; /**< Log type for testpmd logs */
/* use master core for command line ? */
@@ -3068,6 +3069,15 @@ rmv_port_callback(void *arg)
start_packet_forwarding(0);
}
+static void
+aging_event_output(uint16_t portid)
+{
+ if (event_verbose_bitmap & (1 << RTE_ETH_EVENT_FLOW_AGED)) {
+ printf("port %u RTE_ETH_EVENT_FLOW_AGED triggered\n", portid);
+ fflush(stdout);
+ }
+}
+
/* This function is used by the interrupt thread */
static int
eth_event_callback(portid_t port_id, enum rte_eth_event_type type, void *param,
@@ -3098,6 +3108,8 @@ eth_event_callback(portid_t port_id, enum rte_eth_event_type type, void *param,
rmv_port_callback, (void *)(intptr_t)port_id))
fprintf(stderr, "Could not set up deferred device removal\n");
break;
+ case RTE_ETH_EVENT_FLOW_AGED:
+ aging_event_output(port_id);
default:
break;
}
@@ -323,6 +323,7 @@ extern uint8_t xstats_hide_zero; /**< Hide zero values for xstats display */
/* globals used for configuration */
extern uint16_t verbose_level; /**< Drives messages being displayed, if any. */
+extern uint32_t event_verbose_bitmap; /**< Verbose bitmap for all events */
extern int testpmd_logtype; /**< Log type for testpmd logs */
extern uint8_t interactive;
extern uint8_t auto_start;
@@ -747,12 +748,15 @@ int port_flow_create(portid_t port_id,
const struct rte_flow_attr *attr,
const struct rte_flow_item *pattern,
const struct rte_flow_action *actions);
+void update_age_action_context(const struct rte_flow_action *actions,
+ struct port_flow *pf);
int port_flow_destroy(portid_t port_id, uint32_t n, const uint32_t *rule);
int port_flow_flush(portid_t port_id);
int port_flow_dump(portid_t port_id, const char *file_name);
int port_flow_query(portid_t port_id, uint32_t rule,
const struct rte_flow_action *action);
void port_flow_list(portid_t port_id, uint32_t n, const uint32_t *group);
+void port_flow_aged(portid_t port_id, uint8_t destroy);
int port_flow_isolate(portid_t port_id, int set);
void rx_ring_desc_display(portid_t port_id, queueid_t rxq_id, uint16_t rxd_id);
@@ -632,6 +632,23 @@ Available levels are as following:
* ``2`` fully verbose except for Rx packets.
* ``> 2`` fully verbose.
+set event_verbose
+~~~~~~~~~~~~~~~~~
+
+Set the debug verbosity bitmaps for all events defined in enum rte_eth_event_type,
+the maximum bits of the bitmap is 32::
+
+ testpmd> set event_verbose (bitmap)
+
+For examine, to start the event:RTE_ETH_EVENT_FLOW_AGED log::
+
+ testpmd> set event_verbose 0x400
+ Change event verbose bitmap from 0x0 to 0x400
+
+When aged flow be checkout, there will be one output log for it::
+
+ testpmd> port 0 RTE_ETH_EVENT_FLOW_AGED triggered
+
set log
~~~~~~~
@@ -3616,6 +3633,10 @@ following sections.
flow dump {port_id} {output_file}
+- List and destroy aged flow rules::
+
+ flow aged {port_id} [destroy]
+
Validating flow rules
~~~~~~~~~~~~~~~~~~~~~
@@ -4503,6 +4524,64 @@ Otherwise, it will complain error occurred::
Caught error type [...] ([...]): [...]
+Listing and destroying aged flow rules
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+``flow aged`` simply lists aged flow rules be get from api ``rte_flow_get_aged_flows``,
+and ``destroy`` parameter can be used to destroy those flow rules in PMD.
+
+ flow aged {port_id} [destroy]
+
+Listing current aged flow rules::
+
+ testpmd> flow aged 0
+ Port 0 total aged flows: 0
+ testpmd> flow create 0 ingress pattern eth / ipv4 src is 2.2.2.14 / end
+ actions age timeout 5 / queue index 0 / end
+ Flow rule #0 created
+ testpmd> flow create 0 ingress pattern eth / ipv4 src is 2.2.2.15 / end
+ actions age timeout 4 / queue index 0 / end
+ Flow rule #1 created
+ testpmd> flow create 0 ingress pattern eth / ipv4 src is 2.2.2.16 / end
+ actions age timeout 2 / queue index 0 / end
+ Flow rule #2 created
+ testpmd> flow create 0 ingress pattern eth / ipv4 src is 2.2.2.17 / end
+ actions age timeout 3 / queue index 0 / end
+ Flow rule #3 created
+
+
+Aged Rules are simply list as command ``flow list {port_id}``, but strip the detail rule
+information, all the aged flows are sorted by the longest timeout time. For example, if
+those rules be configured in the same time, ID 2 will be the first aged out rule, the next
+will be ID 3, ID 1, ID 0::
+
+ testpmd> flow aged 0
+ Port 0 total aged flows: 4
+ ID Group Prio Attr
+ 2 0 0 i--
+ 3 0 0 i--
+ 1 0 0 i--
+ 0 0 0 i--
+
+If attach ``destroy`` parameter, the command will destroy all the list aged flow rules.
+
+ testpmd> flow aged 0 destroy
+ Port 0 total aged flows: 4
+ ID Group Prio Attr
+ 2 0 0 i--
+ 3 0 0 i--
+ 1 0 0 i--
+ 0 0 0 i--
+
+ Flow rule #2 destroyed
+ Flow rule #3 destroyed
+ Flow rule #1 destroyed
+ Flow rule #0 destroyed
+ 4 flows be destroyed
+ testpmd> flow aged 0
+ Port 0 total aged flows: 0
+
+
Sample QinQ flow rules
~~~~~~~~~~~~~~~~~~~~~~