@@ -132,6 +132,7 @@ enum index {
/* Queue arguments. */
QUEUE_CREATE,
QUEUE_DESTROY,
+ QUEUE_UPDATE,
QUEUE_AGED,
QUEUE_INDIRECT_ACTION,
@@ -146,6 +147,9 @@ enum index {
QUEUE_DESTROY_ID,
QUEUE_DESTROY_POSTPONE,
+ /* Queue update arguments. */
+ QUEUE_UPDATE_ID,
+
/* Queue indirect action arguments */
QUEUE_INDIRECT_ACTION_CREATE,
QUEUE_INDIRECT_ACTION_LIST_CREATE,
@@ -1312,6 +1316,7 @@ static const enum index next_table_destroy_attr[] = {
static const enum index next_queue_subcmd[] = {
QUEUE_CREATE,
QUEUE_DESTROY,
+ QUEUE_UPDATE,
QUEUE_AGED,
QUEUE_INDIRECT_ACTION,
ZERO,
@@ -3408,6 +3413,14 @@ static const struct token token_list[] = {
.args = ARGS(ARGS_ENTRY(struct buffer, queue)),
.call = parse_qo_destroy,
},
+ [QUEUE_UPDATE] = {
+ .name = "update",
+ .help = "update a flow rule",
+ .next = NEXT(NEXT_ENTRY(QUEUE_UPDATE_ID),
+ NEXT_ENTRY(COMMON_QUEUE_ID)),
+ .args = ARGS(ARGS_ENTRY(struct buffer, queue)),
+ .call = parse_qo,
+ },
[QUEUE_AGED] = {
.name = "aged",
.help = "list and destroy aged flows",
@@ -3484,6 +3497,15 @@ static const struct token token_list[] = {
args.destroy.rule)),
.call = parse_qo_destroy,
},
+ [QUEUE_UPDATE_ID] = {
+ .name = "rule",
+ .help = "specify rule id to update",
+ .next = NEXT(NEXT_ENTRY(QUEUE_ACTIONS_TEMPLATE),
+ NEXT_ENTRY(COMMON_UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY(struct buffer,
+ args.vc.rule_id)),
+ .call = parse_qo,
+ },
/* Queue indirect action arguments */
[QUEUE_INDIRECT_ACTION_CREATE] = {
.name = "create",
@@ -10207,6 +10229,7 @@ parse_qo(struct context *ctx, const struct token *token,
}
switch (ctx->curr) {
case QUEUE_CREATE:
+ case QUEUE_UPDATE:
out->command = ctx->curr;
ctx->objdata = 0;
ctx->object = out;
@@ -10218,6 +10241,7 @@ parse_qo(struct context *ctx, const struct token *token,
case QUEUE_ACTIONS_TEMPLATE:
case QUEUE_CREATE_POSTPONE:
case QUEUE_RULE_ID:
+ case QUEUE_UPDATE_ID:
return len;
case ITEM_PATTERN:
out->args.vc.pattern =
@@ -12233,6 +12257,11 @@ cmd_flow_parsed(const struct buffer *in)
in->args.destroy.rule_n,
in->args.destroy.rule);
break;
+ case QUEUE_UPDATE:
+ port_queue_flow_update(in->port, in->queue, in->postpone,
+ in->args.vc.rule_id, in->args.vc.act_templ_id,
+ in->args.vc.actions);
+ break;
case PUSH:
port_queue_flow_push(in->port, in->queue);
break;
@@ -2799,6 +2799,7 @@ port_queue_flow_create(portid_t port_id, queueid_t queue_id,
pf->next = port->flow_list;
pf->id = id;
+ pf->table = pt;
pf->flow = flow;
job->pf = pf;
port->flow_list = pf;
@@ -2905,6 +2906,94 @@ queue_action_list_handle_create(portid_t port_id, uint32_t queue_id,
job, error);
}
+/** Enqueue update flow rule operation. */
+int
+port_queue_flow_update(portid_t port_id, queueid_t queue_id,
+ bool postpone, uint32_t rule_idx, uint32_t actions_idx,
+ const struct rte_flow_action *actions)
+{
+ struct rte_flow_op_attr op_attr = { .postpone = postpone };
+ struct rte_port *port;
+ struct port_flow *pf, *uf;
+ struct port_flow **tmp;
+ struct port_table *pt;
+ bool found;
+ struct rte_flow_error error = { RTE_FLOW_ERROR_TYPE_NONE, NULL, NULL };
+ struct rte_flow_action_age *age = age_action_get(actions);
+ struct queue_job *job;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN) ||
+ port_id == (portid_t)RTE_PORT_ALL)
+ return -EINVAL;
+ port = &ports[port_id];
+
+ if (queue_id >= port->queue_nb) {
+ printf("Queue #%u is invalid\n", queue_id);
+ return -EINVAL;
+ }
+
+ found = false;
+ tmp = &port->flow_list;
+ while (*tmp) {
+ pf = *tmp;
+ if (rule_idx == pf->id) {
+ found = true;
+ break;
+ }
+ tmp = &(*tmp)->next;
+ }
+ if (!found) {
+ printf("Flow rule #%u is invalid\n", rule_idx);
+ return -EINVAL;
+ }
+
+ pt = pf->table;
+ if (actions_idx >= pt->nb_actions_templates) {
+ printf("Actions template index #%u is invalid,"
+ " %u templates present in the table\n",
+ actions_idx, pt->nb_actions_templates);
+ return -EINVAL;
+ }
+
+ job = calloc(1, sizeof(*job));
+ if (!job) {
+ printf("Queue flow create job allocate failed\n");
+ return -ENOMEM;
+ }
+ job->type = QUEUE_JOB_TYPE_FLOW_UPDATE;
+
+ uf = port_flow_new(&pt->flow_attr, pf->rule.pattern_ro, actions, &error);
+ if (!uf) {
+ free(job);
+ return port_flow_complain(&error);
+ }
+
+ if (age) {
+ uf->age_type = ACTION_AGE_CONTEXT_TYPE_FLOW;
+ age->context = &uf->age_type;
+ }
+
+ /*
+ * Poisoning to make sure PMD update it in case of error.
+ */
+ memset(&error, 0x44, sizeof(error));
+ if (rte_flow_async_actions_update(port_id, queue_id, &op_attr, pf->flow,
+ actions, actions_idx, job, &error)) {
+ free(uf);
+ free(job);
+ return port_flow_complain(&error);
+ }
+ uf->next = pf->next;
+ uf->id = pf->id;
+ uf->table = pt;
+ uf->flow = pf->flow;
+ *tmp = uf;
+ job->pf = pf;
+
+ printf("Flow rule #%u update enqueued\n", pf->id);
+ return 0;
+}
+
/** Enqueue indirect action create operation. */
int
port_queue_action_handle_create(portid_t port_id, uint32_t queue_id,
@@ -3394,7 +3483,8 @@ port_queue_flow_pull(portid_t port_id, queueid_t queue_id)
if (res[i].status == RTE_FLOW_OP_SUCCESS)
success++;
job = (struct queue_job *)res[i].user_data;
- if (job->type == QUEUE_JOB_TYPE_FLOW_DESTROY)
+ if (job->type == QUEUE_JOB_TYPE_FLOW_DESTROY ||
+ job->type == QUEUE_JOB_TYPE_FLOW_UPDATE)
free(job->pf);
else if (job->type == QUEUE_JOB_TYPE_ACTION_DESTROY)
free(job->pia);
@@ -110,6 +110,7 @@ enum {
enum {
QUEUE_JOB_TYPE_FLOW_CREATE,
QUEUE_JOB_TYPE_FLOW_DESTROY,
+ QUEUE_JOB_TYPE_FLOW_UPDATE,
QUEUE_JOB_TYPE_ACTION_CREATE,
QUEUE_JOB_TYPE_ACTION_DESTROY,
QUEUE_JOB_TYPE_ACTION_UPDATE,
@@ -225,6 +226,7 @@ struct port_flow {
struct port_flow *next; /**< Next flow in list. */
struct port_flow *tmp; /**< Temporary linking. */
uint32_t id; /**< Flow rule ID. */
+ struct port_table *table; /**< Flow table. */
struct rte_flow *flow; /**< Opaque flow object returned by PMD. */
struct rte_flow_conv_rule rule; /**< Saved flow rule description. */
enum age_action_context_type age_type; /**< Age action context type. */
@@ -983,6 +985,9 @@ int port_queue_flow_create(portid_t port_id, queueid_t queue_id,
const struct rte_flow_action *actions);
int port_queue_flow_destroy(portid_t port_id, queueid_t queue_id,
bool postpone, uint32_t n, const uint32_t *rule);
+int port_queue_flow_update(portid_t port_id, queueid_t queue_id,
+ bool postpone, uint32_t rule_idx, uint32_t actions_idx,
+ const struct rte_flow_action *actions);
int port_queue_action_handle_create(portid_t port_id, uint32_t queue_id,
bool postpone, uint32_t id,
const struct rte_flow_indir_action_conf *conf,