@@ -193,6 +193,15 @@ Runtime Configuration
``+outvlan-sctptag``: means disable sctp tag tuple, and enable outer vlan tuple.
``+outvlan-tunvni``: means disable tunnel vni tuple, and enable outer vlan tuple.
+- ``fdir_index_config`` (default ``hash``)
+
+ Used to select flow director index strategy, the flow director index is the index
+ position in the hardware flow director table. Lower index denotes higher priority
+ (it means when a packet matches multiple indexes, the smaller index wins).
+ Current supported options are as follows:
+ ``hash``: The driver generates a flow index based on the hash of the rte_flow key.
+ ``priority``: the driver uses the rte_flow priority field as the flow director index.
+
Driver compilation and testing
------------------------------
@@ -322,6 +331,9 @@ Generic flow API
configuration for hardware which will affect other rules.
The rule just setting input tuple is completely independent.
+ In addition, if the rule priority level is set, no error is reported,
+ but the rule priority level does not take effect.
+
Run ``testpmd``:
.. code-block:: console
@@ -290,6 +290,27 @@ hns3_parse_fdir_tuple_config(const char *key, const char *value, void *args)
return 0;
}
+static int
+hns3_parse_fdir_index_config(const char *key, const char *value, void *args)
+{
+ enum hns3_fdir_index_config cfg;
+
+ if (strcmp(value, "hash") == 0) {
+ cfg = HNS3_FDIR_INDEX_CONFIG_HASH;
+ } else if (strcmp(value, "priority") == 0) {
+ cfg = HNS3_FDIR_INDEX_CONFIG_PRIORITY;
+ } else {
+ PMD_INIT_LOG(WARNING, "invalid value:\"%s\" for key:\"%s\", "
+ "value must be 'hash' or 'priority'",
+ value, key);
+ return -1;
+ }
+
+ *(enum hns3_fdir_index_config *)args = cfg;
+
+ return 0;
+}
+
void
hns3_parse_devargs(struct rte_eth_dev *dev)
{
@@ -333,6 +354,10 @@ hns3_parse_devargs(struct rte_eth_dev *dev)
HNS3_DEVARG_FDIR_TUPLE_CONFIG,
&hns3_parse_fdir_tuple_config,
&hns->pf.fdir.tuple_cfg);
+ (void)rte_kvargs_process(kvlist,
+ HNS3_DEVARG_FDIR_INDEX_CONFIG,
+ &hns3_parse_fdir_index_config,
+ &hns->pf.fdir.index_cfg);
}
rte_kvargs_free(kvlist);
@@ -29,6 +29,7 @@ enum {
#define HNS3_DEVARG_FDIR_VLAN_MATCH_MODE "fdir_vlan_match_mode"
#define HNS3_DEVARG_FDIR_TUPLE_CONFIG "fdir_tuple_config"
+#define HNS3_DEVARG_FDIR_INDEX_CONFIG "fdir_index_config"
#define MSEC_PER_SEC 1000L
#define USEC_PER_MSEC 1000L
@@ -169,6 +169,7 @@ hns3_get_fdir_basic_info(FILE *file, struct hns3_pf *pf)
"\t -- mode=%u max_key_len=%u rule_num:%u cnt_num:%u\n"
"\t -- key_sel=%u tuple_active=0x%x meta_data_active=0x%x\n"
"\t -- ipv6_word_en: in_s=%u in_d=%u out_s=%u out_d=%u\n"
+ "\t -- index_cfg: %s\n"
"\t -- tuple_config: %s\n"
"\t -- active_tuples:\n",
fdcfg->fd_mode, fdcfg->max_key_length,
@@ -181,6 +182,7 @@ hns3_get_fdir_basic_info(FILE *file, struct hns3_pf *pf)
fdcfg->key_cfg[HNS3_FD_STAGE_1].inner_dipv6_word_en,
fdcfg->key_cfg[HNS3_FD_STAGE_1].outer_sipv6_word_en,
fdcfg->key_cfg[HNS3_FD_STAGE_1].outer_dipv6_word_en,
+ hns3_fdir_index_config_name(pf->fdir.index_cfg),
hns3_tuple_config_name(pf->fdir.tuple_cfg));
for (i = 0; i < MAX_TUPLE; i++) {
@@ -6674,7 +6674,8 @@ RTE_PMD_REGISTER_PARAM_STRING(net_hns3,
HNS3_DEVARG_FDIR_VLAN_MATCH_MODE "=strict|nostrict "
HNS3_DEVARG_FDIR_TUPLE_CONFIG "=+outvlan-insmac|+outvlan-indmac|"
"+outvlan-insip|+outvlan-indip"
- "+outvlan-sctptag|+outvlan-tunvni ");
+ "+outvlan-sctptag|+outvlan-tunvni "
+ HNS3_DEVARG_FDIR_INDEX_CONFIG "=hash|priority ");
RTE_LOG_REGISTER_SUFFIX(hns3_logtype_init, init, NOTICE);
RTE_LOG_REGISTER_SUFFIX(hns3_logtype_driver, driver, NOTICE);
#ifdef RTE_ETHDEV_DEBUG_RX
@@ -981,39 +981,44 @@ static int hns3_insert_fdir_filter(struct hns3_hw *hw,
{
struct hns3_fdir_key_conf *key;
hash_sig_t sig;
- int ret;
+ int index;
key = &fdir_filter->fdir_conf.key_conf;
sig = rte_hash_crc(key, sizeof(*key), 0);
- ret = rte_hash_add_key_with_hash(fdir_info->hash_handle, key, sig);
- if (ret < 0) {
- hns3_err(hw, "Hash table full? err:%d!", ret);
- return ret;
+ index = rte_hash_add_key_with_hash(fdir_info->hash_handle, key, sig);
+ if (index < 0) {
+ hns3_err(hw, "Hash table full? err:%d!", index);
+ return index;
}
- fdir_info->hash_map[ret] = fdir_filter;
+ if (fdir_info->index_cfg == HNS3_FDIR_INDEX_CONFIG_PRIORITY)
+ index = fdir_filter->fdir_conf.location;
+
+ fdir_info->hash_map[index] = fdir_filter;
TAILQ_INSERT_TAIL(&fdir_info->fdir_list, fdir_filter, entries);
- return ret;
+ return index;
}
static int hns3_remove_fdir_filter(struct hns3_hw *hw,
struct hns3_fdir_info *fdir_info,
- struct hns3_fdir_key_conf *key)
+ struct hns3_fdir_rule *rule)
{
struct hns3_fdir_rule_ele *fdir_filter;
hash_sig_t sig;
- int ret;
+ int index;
- sig = rte_hash_crc(key, sizeof(*key), 0);
- ret = rte_hash_del_key_with_hash(fdir_info->hash_handle, key, sig);
- if (ret < 0) {
- hns3_err(hw, "Delete hash key fail ret=%d", ret);
- return ret;
+ sig = rte_hash_crc(&rule->key_conf, sizeof(rule->key_conf), 0);
+ index = rte_hash_del_key_with_hash(fdir_info->hash_handle, &rule->key_conf, sig);
+ if (index < 0) {
+ hns3_err(hw, "Delete hash key fail ret=%d", index);
+ return index;
}
- fdir_filter = fdir_info->hash_map[ret];
- fdir_info->hash_map[ret] = NULL;
+ if (fdir_info->index_cfg == HNS3_FDIR_INDEX_CONFIG_PRIORITY)
+ index = rule->location;
+ fdir_filter = fdir_info->hash_map[index];
+ fdir_info->hash_map[index] = NULL;
TAILQ_REMOVE(&fdir_info->fdir_list, fdir_filter, entries);
rte_free(fdir_filter);
@@ -1042,7 +1047,7 @@ int hns3_fdir_filter_program(struct hns3_adapter *hns,
rule->key_conf.spec.src_port,
rule->key_conf.spec.dst_port, ret);
else
- ret = hns3_remove_fdir_filter(hw, fdir_info, &rule->key_conf);
+ ret = hns3_remove_fdir_filter(hw, fdir_info, rule);
return ret;
}
@@ -1080,7 +1085,7 @@ int hns3_fdir_filter_program(struct hns3_adapter *hns,
rule->key_conf.spec.dst_ip[IP_ADDR_KEY_ID],
rule->key_conf.spec.src_port,
rule->key_conf.spec.dst_port, ret);
- (void)hns3_remove_fdir_filter(hw, fdir_info, &rule->key_conf);
+ (void)hns3_remove_fdir_filter(hw, fdir_info, rule);
}
return ret;
@@ -1231,3 +1236,24 @@ hns3_tuple_config_name(enum hns3_fdir_tuple_config tuple_cfg)
return "unknown";
}
+
+static struct {
+ enum hns3_fdir_index_config cfg;
+ const char *name;
+} index_cfg_map[] = {
+ { HNS3_FDIR_INDEX_CONFIG_HASH, "hash"},
+ { HNS3_FDIR_INDEX_CONFIG_PRIORITY, "priority"},
+};
+
+const char *
+hns3_fdir_index_config_name(enum hns3_fdir_index_config cfg)
+{
+ uint32_t i;
+
+ for (i = 0; i < RTE_DIM(index_cfg_map); i++) {
+ if (cfg == index_cfg_map[i].cfg)
+ return index_cfg_map[i].name;
+ }
+
+ return "unknown";
+}
@@ -228,6 +228,14 @@ enum hns3_fdir_tuple_config {
HNS3_FDIR_TUPLE_CONFIG_BUTT
};
+enum hns3_fdir_index_config {
+ /* Generate the hardware flow director index based on rte_hash (Default) */
+ HNS3_FDIR_INDEX_CONFIG_HASH,
+
+ /* Use the rte_flow priority field as the hardware flow director index. */
+ HNS3_FDIR_INDEX_CONFIG_PRIORITY
+};
+
/*
* A structure used to define fields of a FDIR related info.
*/
@@ -238,6 +246,7 @@ struct hns3_fdir_info {
struct hns3_fd_cfg fd_cfg;
uint8_t vlan_match_mode;
enum hns3_fdir_tuple_config tuple_cfg;
+ enum hns3_fdir_index_config index_cfg;
};
struct hns3_adapter;
@@ -254,5 +263,6 @@ int hns3_restore_all_fdir_filter(struct hns3_adapter *hns);
enum hns3_fdir_tuple_config hns3_parse_tuple_config(const char *name);
const char *hns3_tuple_config_name(enum hns3_fdir_tuple_config tuple_cfg);
+const char *hns3_fdir_index_config_name(enum hns3_fdir_index_config cfg);
#endif /* HNS3_FDIR_H */
@@ -597,10 +597,6 @@ hns3_check_attr(const struct rte_flow_attr *attr, struct rte_flow_error *error)
return rte_flow_error_set(error, ENOTSUP,
RTE_FLOW_ERROR_TYPE_ATTR_TRANSFER,
attr, "No support for transfer");
- if (attr->priority)
- return rte_flow_error_set(error, ENOTSUP,
- RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
- attr, "Not support priority");
if (attr->group)
return rte_flow_error_set(error, ENOTSUP,
RTE_FLOW_ERROR_TYPE_ATTR_GROUP,
@@ -1441,6 +1437,40 @@ is_tunnel_packet(enum rte_flow_item_type type)
return false;
}
+static int
+hns3_handle_attributes(struct rte_eth_dev *dev,
+ const struct rte_flow_attr *attr,
+ struct hns3_fdir_rule *rule,
+ struct rte_flow_error *error)
+{
+ struct hns3_pf *pf = HNS3_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+ struct hns3_fdir_info fdir = pf->fdir;
+ uint32_t rule_num;
+
+ if (fdir.index_cfg != HNS3_FDIR_INDEX_CONFIG_PRIORITY) {
+ if (attr->priority == 0)
+ return 0;
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
+ attr, "Not support priority");
+ }
+
+ rule_num = fdir.fd_cfg.rule_num[HNS3_FD_STAGE_1];
+ if (attr->priority >= rule_num)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
+ attr, "Priority out of range");
+
+ if (fdir.hash_map[attr->priority] != NULL)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
+ attr, "Priority already exists");
+
+ rule->location = attr->priority;
+
+ return 0;
+}
+
/*
* Parse the flow director rule.
* The supported PATTERN:
@@ -1468,6 +1498,7 @@ is_tunnel_packet(enum rte_flow_item_type type)
*/
static int
hns3_parse_fdir_filter(struct rte_eth_dev *dev,
+ const struct rte_flow_attr *attr,
const struct rte_flow_item pattern[],
const struct rte_flow_action actions[],
struct hns3_fdir_rule *rule,
@@ -1484,6 +1515,10 @@ hns3_parse_fdir_filter(struct rte_eth_dev *dev,
RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
"Fdir not supported in VF");
+ ret = hns3_handle_attributes(dev, attr, rule, error);
+ if (ret)
+ return ret;
+
step_mngr.items = first_items;
step_mngr.count = RTE_DIM(first_items);
for (item = pattern; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
@@ -2248,7 +2283,7 @@ hns3_flow_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
return hns3_parse_rss_filter(dev, pattern, actions,
&conf->rss_conf, error);
- return hns3_parse_fdir_filter(dev, pattern, actions,
+ return hns3_parse_fdir_filter(dev, attr, pattern, actions,
&conf->fdir_conf, error);
}