ice: add profile conflict check for AVF FDIR
authorJunfeng Guo <junfeng.guo@intel.com>
Tue, 14 Mar 2023 02:03:15 +0000 (10:03 +0800)
committerTony Nguyen <anthony.l.nguyen@intel.com>
Tue, 28 Mar 2023 16:48:41 +0000 (09:48 -0700)
Add profile conflict check while adding some FDIR rules to avoid
unexpected flow behavior, rules may have conflict including:
        IPv4 <---> {IPv4_UDP, IPv4_TCP, IPv4_SCTP}
        IPv6 <---> {IPv6_UDP, IPv6_TCP, IPv6_SCTP}

For example, when we create an FDIR rule for IPv4, this rule will work
on packets including IPv4, IPv4_UDP, IPv4_TCP and IPv4_SCTP. But if we
then create an FDIR rule for IPv4_UDP and then destroy it, the first
FDIR rule for IPv4 cannot work on pkt IPv4_UDP then.

To prevent this unexpected behavior, we add restriction in software
when creating FDIR rules by adding necessary profile conflict check.

Fixes: 1f7ea1cd6a37 ("ice: Enable FDIR Configure for AVF")
Signed-off-by: Junfeng Guo <junfeng.guo@intel.com>
Tested-by: Rafal Romanowski <rafal.romanowski@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c

index e6ef6b3..5fd75e7 100644 (file)
@@ -542,6 +542,72 @@ static void ice_vc_fdir_rem_prof_all(struct ice_vf *vf)
 }
 
 /**
+ * ice_vc_fdir_has_prof_conflict
+ * @vf: pointer to the VF structure
+ * @conf: FDIR configuration for each filter
+ *
+ * Check if @conf has conflicting profile with existing profiles
+ *
+ * Return: true on success, and false on error.
+ */
+static bool
+ice_vc_fdir_has_prof_conflict(struct ice_vf *vf,
+                             struct virtchnl_fdir_fltr_conf *conf)
+{
+       struct ice_fdir_fltr *desc;
+
+       list_for_each_entry(desc, &vf->fdir.fdir_rule_list, fltr_node) {
+               struct virtchnl_fdir_fltr_conf *existing_conf;
+               enum ice_fltr_ptype flow_type_a, flow_type_b;
+               struct ice_fdir_fltr *a, *b;
+
+               existing_conf = to_fltr_conf_from_desc(desc);
+               a = &existing_conf->input;
+               b = &conf->input;
+               flow_type_a = a->flow_type;
+               flow_type_b = b->flow_type;
+
+               /* No need to compare two rules with different tunnel types or
+                * with the same protocol type.
+                */
+               if (existing_conf->ttype != conf->ttype ||
+                   flow_type_a == flow_type_b)
+                       continue;
+
+               switch (flow_type_a) {
+               case ICE_FLTR_PTYPE_NONF_IPV4_UDP:
+               case ICE_FLTR_PTYPE_NONF_IPV4_TCP:
+               case ICE_FLTR_PTYPE_NONF_IPV4_SCTP:
+                       if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_OTHER)
+                               return true;
+                       break;
+               case ICE_FLTR_PTYPE_NONF_IPV4_OTHER:
+                       if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_UDP ||
+                           flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_TCP ||
+                           flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_SCTP)
+                               return true;
+                       break;
+               case ICE_FLTR_PTYPE_NONF_IPV6_UDP:
+               case ICE_FLTR_PTYPE_NONF_IPV6_TCP:
+               case ICE_FLTR_PTYPE_NONF_IPV6_SCTP:
+                       if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_OTHER)
+                               return true;
+                       break;
+               case ICE_FLTR_PTYPE_NONF_IPV6_OTHER:
+                       if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_UDP ||
+                           flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_TCP ||
+                           flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_SCTP)
+                               return true;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return false;
+}
+
+/**
  * ice_vc_fdir_write_flow_prof
  * @vf: pointer to the VF structure
  * @flow: filter flow type
@@ -677,6 +743,13 @@ ice_vc_fdir_config_input_set(struct ice_vf *vf, struct virtchnl_fdir_add *fltr,
        enum ice_fltr_ptype flow;
        int ret;
 
+       ret = ice_vc_fdir_has_prof_conflict(vf, conf);
+       if (ret) {
+               dev_dbg(dev, "Found flow profile conflict for VF %d\n",
+                       vf->vf_id);
+               return ret;
+       }
+
        flow = input->flow_type;
        ret = ice_vc_fdir_alloc_prof(vf, flow);
        if (ret) {