An RSS flow rule only selects the hash input set of a packet type, and
the PF keeps a single configuration per packet type for the VF VSI.
When a second rule is created for a packet type already used by another
rule, the PF silently replaces the first configuration, while both flow
handles remain valid.
For example,:

  flow create 0 ingress pattern eth / vlan vid is 1500 / ipv6 / end
    actions rss types ipv6 l3-dst-only end queues end / end
  flow create 0 ingress pattern eth / vlan vid is 2640 / ipv6 / end
    actions rss types ipv6 l3-src-only end queues end / end

Only the second rule is applied, whatever the VLAN ID of the packet, and
destroying it leaves the first rule without any hardware configuration.

Reject the creation of an RSS rule when another RSS rule of the port
already uses the same protocol header stack. The existing rule has to
be destroyed first to change the hash input set of that packet type.
Raw pattern rules are not checked, as their packet type is only known
by the PF parser.

Fixes: 7be10c3004be ("net/iavf: add RSS configuration for VF")
Cc: [email protected]

Signed-off-by: Anurag Mandal <[email protected]>
---
 drivers/net/intel/iavf/iavf_hash.c | 47 ++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/drivers/net/intel/iavf/iavf_hash.c 
b/drivers/net/intel/iavf/iavf_hash.c
index fe5d725064..c079511898 100644
--- a/drivers/net/intel/iavf/iavf_hash.c
+++ b/drivers/net/intel/iavf/iavf_hash.c
@@ -1571,6 +1571,44 @@ iavf_hash_parse_pattern_action(struct iavf_adapter *ad,
        return ret;
 }
 
+/* Check duplicate packet type RSS rule in same VSI */
+static bool
+iavf_hash_ptype_in_use(struct iavf_adapter *ad,
+                      const struct virtchnl_proto_hdrs *hdrs)
+{
+       struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(ad);
+       const struct virtchnl_rss_cfg *cfg;
+       struct rte_flow *flow;
+       bool found = false;
+       int i;
+
+       /* the packet type of a raw pattern is only known by the PF parser */
+       if (hdrs->count == 0)
+               return false;
+
+       rte_spinlock_lock(&vf->flow_ops_lock);
+       TAILQ_FOREACH(flow, &vf->flow_list, node) {
+               cfg = flow->rule;
+               if (flow->engine != &iavf_hash_engine || cfg == NULL ||
+                   cfg->proto_hdrs.tunnel_level != hdrs->tunnel_level ||
+                   cfg->proto_hdrs.count != hdrs->count)
+                       continue;
+
+               for (i = 0; i < hdrs->count; i++) {
+                       if (cfg->proto_hdrs.proto_hdr[i].type != 
hdrs->proto_hdr[i].type)
+                               break;
+               }
+
+               if (i == hdrs->count) {
+                       found = true;
+                       break;
+               }
+       }
+       rte_spinlock_unlock(&vf->flow_ops_lock);
+
+       return found;
+}
+
 static int
 iavf_hash_create(struct iavf_adapter *ad,
                 struct rte_flow *flow, void *meta,
@@ -1579,6 +1617,15 @@ iavf_hash_create(struct iavf_adapter *ad,
        struct virtchnl_rss_cfg *rss_cfg = meta;
        int ret = 0;
 
+       /* Reject duplicate packet type rule in same VSI */
+       if (iavf_hash_ptype_in_use(ad, &rss_cfg->proto_hdrs)) {
+               PMD_DRV_LOG(ERR, "RSS rule for this packet type already 
exists");
+               rte_flow_error_set(error, EEXIST,
+                                  RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+                                  "RSS rule for this packet type already 
exists");
+               return -rte_errno;
+       }
+
        ret = iavf_add_del_rss_cfg(ad, rss_cfg, true);
        if (!ret) {
                flow->rule = rss_cfg;
-- 
2.25.1

Reply via email to