Commit 29486b6d authored by Junfeng Guo's avatar Junfeng Guo Committed by Tony Nguyen
Browse files

ice: add profile conflict check for AVF FDIR



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: 1f7ea1cd ("ice: Enable FDIR Configure for AVF")
Signed-off-by: default avatarJunfeng Guo <junfeng.guo@intel.com>
Tested-by: default avatarRafal Romanowski <rafal.romanowski@intel.com>
Signed-off-by: default avatarTony Nguyen <anthony.l.nguyen@intel.com>
parent d94dbdc4
Loading
Loading
Loading
Loading
+73 −0
Original line number Diff line number Diff line
@@ -541,6 +541,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
@@ -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) {