#define ITEM_RAW_SIZE \
(offsetof(struct rte_flow_item_raw, pattern) + ITEM_RAW_PATTERN_SIZE)
-/** Number of queue[] entries in struct rte_flow_action_rss. */
-#define ACTION_RSS_NUM 32
-
-/** Storage size for struct rte_flow_action_rss including queues. */
-#define ACTION_RSS_SIZE \
- (offsetof(struct rte_flow_action_rss, queue) + \
- sizeof(*((struct rte_flow_action_rss *)0)->queue) * ACTION_RSS_NUM)
+/** Maximum number of queue indices in struct rte_flow_action_rss. */
+#define ACTION_RSS_QUEUE_NUM 32
+
+/** Storage for struct rte_flow_action_rss including external data. */
+union action_rss_data {
+ struct rte_flow_action_rss conf;
+ struct {
+ uint8_t conf_data[offsetof(struct rte_flow_action_rss, queue)];
+ uint16_t queue[ACTION_RSS_QUEUE_NUM];
+ struct rte_eth_rss_conf rss_conf;
+ uint8_t rss_key[RSS_HASH_KEY_LENGTH];
+ } s;
+};
/** Maximum number of subsequent tokens and arguments on the stack. */
#define CTX_STACK_SIZE 16
.size = (sz), \
})
+/** Static initializer for ARGS() with arbitrary offset and size. */
+#define ARGS_ENTRY_ARB(o, s) \
+ (&(const struct arg){ \
+ .offset = (o), \
+ .size = (s), \
+ })
+
/** Same as ARGS_ENTRY() using network byte ordering. */
#define ARGS_ENTRY_HTON(s, f) \
(&(const struct arg){ \
const char *, unsigned int, void *, unsigned int);
static int parse_vc_conf(struct context *, const struct token *,
const char *, unsigned int, void *, unsigned int);
+static int parse_vc_action_rss(struct context *, const struct token *,
+ const char *, unsigned int, void *,
+ unsigned int);
static int parse_vc_action_rss_queue(struct context *, const struct token *,
const char *, unsigned int, void *,
unsigned int);
[ACTION_RSS] = {
.name = "rss",
.help = "spread packets among several queues",
- .priv = PRIV_ACTION(RSS, ACTION_RSS_SIZE),
+ .priv = PRIV_ACTION(RSS, sizeof(union action_rss_data)),
.next = NEXT(action_rss),
- .call = parse_vc,
+ .call = parse_vc_action_rss,
},
[ACTION_RSS_QUEUES] = {
.name = "queues",
return len;
}
+/** Parse RSS action. */
+static int
+parse_vc_action_rss(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = buf;
+ struct rte_flow_action *action;
+ union action_rss_data *action_rss_data;
+ unsigned int i;
+ int ret;
+
+ ret = parse_vc(ctx, token, str, len, buf, size);
+ if (ret < 0)
+ return ret;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return ret;
+ if (!out->args.vc.actions_n)
+ return -1;
+ action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+ /* Point to selected object. */
+ ctx->object = out->args.vc.data;
+ ctx->objmask = NULL;
+ /* Set up default configuration. */
+ action_rss_data = ctx->object;
+ *action_rss_data = (union action_rss_data){
+ .conf = (struct rte_flow_action_rss){
+ .rss_conf = &action_rss_data->s.rss_conf,
+ .num = RTE_MIN(nb_rxq, ACTION_RSS_QUEUE_NUM),
+ },
+ };
+ action_rss_data->s.rss_conf = (struct rte_eth_rss_conf){
+ .rss_key = action_rss_data->s.rss_key,
+ .rss_key_len = sizeof(action_rss_data->s.rss_key),
+ .rss_hf = rss_hf,
+ };
+ strncpy((void *)action_rss_data->s.rss_key,
+ "testpmd's default RSS hash key",
+ sizeof(action_rss_data->s.rss_key));
+ for (i = 0; i < action_rss_data->conf.num; ++i)
+ action_rss_data->conf.queue[i] = i;
+ if (!port_id_is_invalid(ctx->port, DISABLED_WARN) &&
+ ctx->port != (portid_t)RTE_PORT_ALL) {
+ struct rte_eth_dev_info info;
+
+ rte_eth_dev_info_get(ctx->port, &info);
+ action_rss_data->s.rss_conf.rss_key_len =
+ RTE_MIN(sizeof(action_rss_data->s.rss_key),
+ info.hash_key_size);
+ }
+ action->conf = &action_rss_data->conf;
+ return ret;
+}
+
/**
* Parse queue field for RSS action.
*
void *buf, unsigned int size)
{
static const enum index next[] = NEXT_ENTRY(ACTION_RSS_QUEUE);
+ union action_rss_data *action_rss_data;
int ret;
int i;
ctx->objdata &= 0xffff;
return len;
}
- if (i >= ACTION_RSS_NUM)
+ if (i >= ACTION_RSS_QUEUE_NUM)
return -1;
- if (push_args(ctx, ARGS_ENTRY(struct rte_flow_action_rss, queue[i])))
+ if (push_args(ctx,
+ ARGS_ENTRY_ARB(offsetof(struct rte_flow_action_rss,
+ queue) +
+ i * sizeof(action_rss_data->s.queue[i]),
+ sizeof(action_rss_data->s.queue[i]))))
return -1;
ret = parse_int(ctx, token, str, len, NULL, 0);
if (ret < 0) {
ctx->next[ctx->next_num++] = next;
if (!ctx->object)
return len;
- ((struct rte_flow_action_rss *)ctx->object)->num = i;
+ action_rss_data = ctx->object;
+ action_rss_data->conf.num = i;
return len;
}
MK_FLOW_ITEM(GENEVE, sizeof(struct rte_flow_item_geneve)),
};
-/** Compute storage space needed by item specification. */
-static void
-flow_item_spec_size(const struct rte_flow_item *item,
- size_t *size, size_t *pad)
+/** Pattern item specification types. */
+enum item_spec_type {
+ ITEM_SPEC,
+ ITEM_LAST,
+ ITEM_MASK,
+};
+
+/** Compute storage space needed by item specification and copy it. */
+static size_t
+flow_item_spec_copy(void *buf, const struct rte_flow_item *item,
+ enum item_spec_type type)
{
- if (!item->spec) {
- *size = 0;
+ size_t size = 0;
+ const void *item_spec =
+ type == ITEM_SPEC ? item->spec :
+ type == ITEM_LAST ? item->last :
+ type == ITEM_MASK ? item->mask :
+ NULL;
+
+ if (!item_spec)
goto empty;
- }
switch (item->type) {
union {
const struct rte_flow_item_raw *raw;
- } spec;
+ } src;
+ union {
+ struct rte_flow_item_raw *raw;
+ } dst;
case RTE_FLOW_ITEM_TYPE_RAW:
- spec.raw = item->spec;
- *size = offsetof(struct rte_flow_item_raw, pattern) +
- spec.raw->length * sizeof(*spec.raw->pattern);
+ src.raw = item_spec;
+ dst.raw = buf;
+ size = offsetof(struct rte_flow_item_raw, pattern) +
+ src.raw->length * sizeof(*src.raw->pattern);
+ if (dst.raw)
+ memcpy(dst.raw, src.raw, size);
break;
default:
- *size = flow_item[item->type].size;
+ size = flow_item[item->type].size;
+ if (buf)
+ memcpy(buf, item_spec, size);
break;
}
empty:
- *pad = RTE_ALIGN_CEIL(*size, sizeof(double)) - *size;
+ return RTE_ALIGN_CEIL(size, sizeof(double));
}
/** Generate flow_action[] entry. */
MK_FLOW_ACTION(METER, sizeof(struct rte_flow_action_meter)),
};
-/** Compute storage space needed by action configuration. */
-static void
-flow_action_conf_size(const struct rte_flow_action *action,
- size_t *size, size_t *pad)
+/** Compute storage space needed by action configuration and copy it. */
+static size_t
+flow_action_conf_copy(void *buf, const struct rte_flow_action *action)
{
- if (!action->conf) {
- *size = 0;
+ size_t size = 0;
+
+ if (!action->conf)
goto empty;
- }
switch (action->type) {
union {
const struct rte_flow_action_rss *rss;
- } conf;
+ } src;
+ union {
+ struct rte_flow_action_rss *rss;
+ } dst;
+ size_t off;
case RTE_FLOW_ACTION_TYPE_RSS:
- conf.rss = action->conf;
- *size = offsetof(struct rte_flow_action_rss, queue) +
- conf.rss->num * sizeof(*conf.rss->queue);
+ src.rss = action->conf;
+ dst.rss = buf;
+ off = 0;
+ if (dst.rss)
+ *dst.rss = (struct rte_flow_action_rss){
+ .num = src.rss->num,
+ };
+ off += offsetof(struct rte_flow_action_rss, queue);
+ if (src.rss->num) {
+ size = sizeof(*src.rss->queue) * src.rss->num;
+ if (dst.rss)
+ memcpy(dst.rss->queue, src.rss->queue, size);
+ off += size;
+ }
+ off = RTE_ALIGN_CEIL(off, sizeof(double));
+ if (dst.rss) {
+ dst.rss->rss_conf = (void *)((uintptr_t)dst.rss + off);
+ *(struct rte_eth_rss_conf *)(uintptr_t)
+ dst.rss->rss_conf = (struct rte_eth_rss_conf){
+ .rss_key_len = src.rss->rss_conf->rss_key_len,
+ .rss_hf = src.rss->rss_conf->rss_hf,
+ };
+ }
+ off += sizeof(*src.rss->rss_conf);
+ if (src.rss->rss_conf->rss_key_len) {
+ off = RTE_ALIGN_CEIL(off, sizeof(double));
+ size = sizeof(*src.rss->rss_conf->rss_key) *
+ src.rss->rss_conf->rss_key_len;
+ if (dst.rss) {
+ ((struct rte_eth_rss_conf *)(uintptr_t)
+ dst.rss->rss_conf)->rss_key =
+ (void *)((uintptr_t)dst.rss + off);
+ memcpy(dst.rss->rss_conf->rss_key,
+ src.rss->rss_conf->rss_key,
+ size);
+ }
+ off += size;
+ }
+ size = off;
break;
default:
- *size = flow_action[action->type].size;
+ size = flow_action[action->type].size;
+ if (buf)
+ memcpy(buf, action->conf, size);
break;
}
empty:
- *pad = RTE_ALIGN_CEIL(*size, sizeof(double)) - *size;
+ return RTE_ALIGN_CEIL(size, sizeof(double));
}
/** Generate a port_flow entry from attributes/pattern/actions. */
const struct rte_flow_action *action;
struct port_flow *pf = NULL;
size_t tmp;
- size_t pad;
size_t off1 = 0;
size_t off2 = 0;
int err = ENOTSUP;
if (pf)
dst = memcpy(pf->data + off1, item, sizeof(*item));
off1 += sizeof(*item);
- flow_item_spec_size(item, &tmp, &pad);
if (item->spec) {
if (pf)
- dst->spec = memcpy(pf->data + off2,
- item->spec, tmp);
- off2 += tmp + pad;
+ dst->spec = pf->data + off2;
+ off2 += flow_item_spec_copy
+ (pf ? pf->data + off2 : NULL, item, ITEM_SPEC);
}
if (item->last) {
if (pf)
- dst->last = memcpy(pf->data + off2,
- item->last, tmp);
- off2 += tmp + pad;
+ dst->last = pf->data + off2;
+ off2 += flow_item_spec_copy
+ (pf ? pf->data + off2 : NULL, item, ITEM_LAST);
}
if (item->mask) {
if (pf)
- dst->mask = memcpy(pf->data + off2,
- item->mask, tmp);
- off2 += tmp + pad;
+ dst->mask = pf->data + off2;
+ off2 += flow_item_spec_copy
+ (pf ? pf->data + off2 : NULL, item, ITEM_MASK);
}
off2 = RTE_ALIGN_CEIL(off2, sizeof(double));
} while ((item++)->type != RTE_FLOW_ITEM_TYPE_END);
if (pf)
dst = memcpy(pf->data + off1, action, sizeof(*action));
off1 += sizeof(*action);
- flow_action_conf_size(action, &tmp, &pad);
if (action->conf) {
if (pf)
- dst->conf = memcpy(pf->data + off2,
- action->conf, tmp);
- off2 += tmp + pad;
+ dst->conf = pf->data + off2;
+ off2 += flow_action_conf_copy
+ (pf ? pf->data + off2 : NULL, action);
}
off2 = RTE_ALIGN_CEIL(off2, sizeof(double));
} while ((action++)->type != RTE_FLOW_ACTION_TYPE_END);