@@ -102,6 +102,7 @@ enum index {
QUEUE,
PUSH,
PULL,
+ HASH,
/* Flex arguments */
FLEX_ITEM_INIT,
@@ -214,6 +215,11 @@ enum index {
GROUP_TRANSFER,
GROUP_SET_MISS_ACTIONS,
+ /* Hash calculation arguments. */
+ HASH_CALC_TABLE,
+ HASH_CALC_PATTERN_INDEX,
+ HASH_CALC_PATTERN,
+
/* Tunnel arguments. */
TUNNEL_CREATE,
TUNNEL_CREATE_TYPE,
@@ -2708,6 +2714,9 @@ static int parse_pull(struct context *, const struct token *,
static int parse_group(struct context *, const struct token *,
const char *, unsigned int,
void *, unsigned int);
+static int parse_hash(struct context *, const struct token *,
+ const char *, unsigned int,
+ void *, unsigned int);
static int parse_tunnel(struct context *, const struct token *,
const char *, unsigned int,
void *, unsigned int);
@@ -3066,7 +3075,8 @@ static const struct token token_list[] = {
FLEX,
QUEUE,
PUSH,
- PULL)),
+ PULL,
+ HASH)),
.call = parse_init,
},
/* Top-level command. */
@@ -3751,6 +3761,33 @@ static const struct token token_list[] = {
.args = ARGS(ARGS_ENTRY(struct buffer, queue)),
},
/* Top-level command. */
+ [HASH] = {
+ .name = "hash",
+ .help = "calculate hash for a given pattern in a given template table",
+ .next = NEXT(NEXT_ENTRY(HASH_CALC_TABLE), NEXT_ENTRY(COMMON_PORT_ID)),
+ .args = ARGS(ARGS_ENTRY(struct buffer, port)),
+ .call = parse_hash,
+ },
+ /* Sub-level commands. */
+ [HASH_CALC_TABLE] = {
+ .name = "template_table",
+ .help = "specify table id",
+ .next = NEXT(NEXT_ENTRY(HASH_CALC_PATTERN_INDEX),
+ NEXT_ENTRY(COMMON_TABLE_ID)),
+ .args = ARGS(ARGS_ENTRY(struct buffer,
+ args.vc.table_id)),
+ .call = parse_hash,
+ },
+ [HASH_CALC_PATTERN_INDEX] = {
+ .name = "pattern_template",
+ .help = "specify pattern template id",
+ .next = NEXT(NEXT_ENTRY(ITEM_PATTERN),
+ NEXT_ENTRY(COMMON_UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY(struct buffer,
+ args.vc.pat_templ_id)),
+ .call = parse_hash,
+ },
+ /* Top-level command. */
[INDIRECT_ACTION] = {
.name = "indirect_action",
.type = "{command} {port_id} [{arg} [...]]",
@@ -10544,6 +10581,48 @@ parse_pull(struct context *ctx, const struct token *token,
return len;
}
+/** Parse tokens for hash calculation commands. */
+static int
+parse_hash(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 != HASH)
+ return -1;
+ if (sizeof(*out) > size)
+ return -1;
+ out->command = ctx->curr;
+ ctx->objdata = 0;
+ ctx->object = out;
+ ctx->objmask = NULL;
+ out->args.vc.data = (uint8_t *)out + size;
+ return len;
+ }
+ switch (ctx->curr) {
+ case HASH_CALC_TABLE:
+ case HASH_CALC_PATTERN_INDEX:
+ return len;
+ case ITEM_PATTERN:
+ out->args.vc.pattern =
+ (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
+ sizeof(double));
+ ctx->object = out->args.vc.pattern;
+ ctx->objmask = NULL;
+ return len;
+ default:
+ return -1;
+ }
+}
+
static int
parse_group(struct context *ctx, const struct token *token,
const char *str, unsigned int len,
@@ -12498,6 +12577,11 @@ cmd_flow_parsed(const struct buffer *in)
case PULL:
port_queue_flow_pull(in->port, in->queue);
break;
+ case HASH:
+ port_flow_hash_calc(in->port, in->args.vc.table_id,
+ in->args.vc.pat_templ_id,
+ in->args.vc.pattern);
+ break;
case QUEUE_AGED:
port_queue_flow_aged(in->port, in->queue,
in->args.aged.destroy);
@@ -6,6 +6,7 @@
#include <ctype.h>
#include <stdarg.h>
#include <errno.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -3301,6 +3302,59 @@ port_queue_flow_push(portid_t port_id, queueid_t queue_id)
return ret;
}
+/** Calculate the hash result for a given pattern in a given table. */
+int
+port_flow_hash_calc(portid_t port_id, uint32_t table_id,
+ uint8_t pattern_template_index, const struct rte_flow_item pattern[])
+{
+ uint32_t hash;
+ bool found;
+ struct port_table *pt;
+ struct rte_port *port;
+ struct rte_flow_error error;
+ int ret = 0;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN) ||
+ port_id == (portid_t)RTE_PORT_ALL)
+ return -EINVAL;
+ port = &ports[port_id];
+
+ found = false;
+ pt = port->table_list;
+ while (pt) {
+ if (table_id == pt->id) {
+ found = true;
+ break;
+ }
+ pt = pt->next;
+ }
+ if (!found) {
+ printf("Table #%u is invalid\n", table_id);
+ return -EINVAL;
+ }
+
+ memset(&error, 0x55, sizeof(error));
+ ret = rte_flow_calc_table_hash(port_id, pt->table, pattern,
+ pattern_template_index, &hash, &error);
+ if (ret < 0) {
+ printf("Failed to calculate hash ");
+ switch (abs(ret)) {
+ case ENODEV:
+ printf("no such device\n");
+ break;
+ case ENOTSUP:
+ printf("device doesn't support this operation\n");
+ break;
+ default:
+ printf("\n");
+ break;
+ }
+ return ret;
+ }
+ printf("Hash results 0x%x\n", hash);
+ return 0;
+}
+
/** Pull queue operation results from the queue. */
static int
port_queue_aged_flow_destroy(portid_t port_id, queueid_t queue_id,
@@ -1014,6 +1014,8 @@ port_queue_action_handle_query_update(portid_t port_id,
const struct rte_flow_action *action);
int port_queue_flow_push(portid_t port_id, queueid_t queue_id);
int port_queue_flow_pull(portid_t port_id, queueid_t queue_id);
+int port_flow_hash_calc(portid_t port_id, uint32_t table_id,
+ uint8_t pattern_template_index, const struct rte_flow_item pattern[]);
void port_queue_flow_aged(portid_t port_id, uint32_t queue_id, uint8_t destroy);
int port_flow_validate(portid_t port_id,
const struct rte_flow_attr *attr,
@@ -4173,6 +4173,23 @@ User data may be provided during a flow creation/destruction in order
to distinguish between multiple operations. User data is returned as part
of the result to provide a method to detect which operation is completed.
+Calculate hash
+~~~~~~~~~~~~~~
+
+Calculating hash of a packet in SW as it would be calculated in HW.
+
+The application can use this function to calculate the hash of a given packet
+as it would be calculated in the HW.
+
+.. code-block:: c
+
+ int
+ rte_flow_calc_table_hash(uint16_t port_id,
+ const struct rte_flow_template_table *table,
+ const struct rte_flow_item pattern[],
+ uint8_t pattern_template_index,
+ uint32_t *hash, struct rte_flow_error *error);
+
.. _flow_isolated_mode:
Flow isolated mode
@@ -3276,6 +3276,28 @@ The usual error message is shown when operations results cannot be pulled::
Caught error type [...] ([...]): [...]
+Calculating hash
+~~~~~~~~~~~~~~~~
+
+``flow hash`` calculates the hash for a given pattern.
+It is bound to ``rte_flow_calc_table_hash()``::
+
+ flow hash {port_id} template_table {table_id}
+ pattern_template {pattern_template_index}
+ actions_template {actions_template_index}
+ pattern {item} [/ {item} [...]] / end
+
+If successful, it will show the calculated hash result as seen below::
+
+ Hash results 0x[...]
+
+Otherwise, it will show an error message of the form::
+
+ Caught error type [...] ([...]): [...]
+
+This command uses the same pattern items as ``flow create``,
+their format is described in `Creating flow rules`_.
+
Creating a tunnel stub for offload
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2454,3 +2454,24 @@ rte_flow_async_action_list_handle_query_update(uint16_t port_id, uint32_t queue_
ret);
return ret;
}
+
+int
+rte_flow_calc_table_hash(uint16_t port_id, const struct rte_flow_template_table *table,
+ const struct rte_flow_item pattern[], uint8_t pattern_template_index,
+ uint32_t *hash, struct rte_flow_error *error)
+{
+ int ret;
+ struct rte_eth_dev *dev;
+ const struct rte_flow_ops *ops;
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+ ops = rte_flow_ops_get(port_id, error);
+ if (!ops || !ops->flow_calc_table_hash)
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+ "action_list async query_update not supported");
+ dev = &rte_eth_devices[port_id];
+ ret = ops->flow_calc_table_hash(dev, table, pattern, pattern_template_index,
+ hash, error);
+ return flow_err(port_id, ret, error);
+}
@@ -6717,6 +6717,38 @@ rte_flow_async_action_list_handle_query_update(uint16_t port_id, uint32_t queue_
void *user_data,
struct rte_flow_error *error);
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Calculate the hash for a given pattern in a given table as
+ * calculated by the HW.
+ *
+ * @param port_id
+ * Port identifier of Ethernet device.
+ * @param table
+ * The table the SW wishes to simulate.
+ * @param pattern
+ * The values to be used in the hash calculation.
+ * @param pattern_template_index
+ * The pattern index in the table to be used for the calculation.
+ * @param hash
+ * Used to return the calculated hash.
+ * @param error
+ * Perform verbose error reporting if not NULL.
+ * PMDs initialize this structure in case of error only.
+ *
+ * @return
+ * - (0) if success.
+ * - (-ENODEV) if *port_id* invalid.
+ * - (-ENOTSUP) if underlying device does not support this functionality.
+ */
+__rte_experimental
+int
+rte_flow_calc_table_hash(uint16_t port_id, const struct rte_flow_template_table *table,
+ const struct rte_flow_item pattern[], uint8_t pattern_template_index,
+ uint32_t *hash, struct rte_flow_error *error);
+
#ifdef __cplusplus
}
#endif
@@ -365,6 +365,11 @@ struct rte_flow_ops {
const void **update, void **query,
enum rte_flow_query_update_mode mode,
void *user_data, struct rte_flow_error *error);
+ /** @see rte_flow_calc_table_hash() */
+ int (*flow_calc_table_hash)
+ (struct rte_eth_dev *dev, const struct rte_flow_template_table *table,
+ const struct rte_flow_item pattern[], uint8_t pattern_template_index,
+ uint32_t *hash, struct rte_flow_error *error);
};
/**
@@ -316,6 +316,7 @@ EXPERIMENTAL {
# added in 23.11
rte_eth_recycle_rx_queue_info_get;
rte_flow_group_set_miss_actions;
+ rte_flow_calc_table_hash;
};
INTERNAL {