diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c | 140 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/ice/ice_fdir.c | 26 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/ice/ice_fdir.h | 5 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/ice/ice_type.h | 1 | 
4 files changed, 171 insertions, 1 deletions
| diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c b/drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c index 9a1a04f5f146..e3cab8e98f52 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c @@ -41,6 +41,8 @@ static struct in6_addr zero_ipv6_addr_mask = {  static int ice_fltr_to_ethtool_flow(enum ice_fltr_ptype flow)  {  	switch (flow) { +	case ICE_FLTR_PTYPE_NONF_ETH: +		return ETHER_FLOW;  	case ICE_FLTR_PTYPE_NONF_IPV4_TCP:  		return TCP_V4_FLOW;  	case ICE_FLTR_PTYPE_NONF_IPV4_UDP: @@ -72,6 +74,8 @@ static int ice_fltr_to_ethtool_flow(enum ice_fltr_ptype flow)  static enum ice_fltr_ptype ice_ethtool_flow_to_fltr(int eth)  {  	switch (eth) { +	case ETHER_FLOW: +		return ICE_FLTR_PTYPE_NONF_ETH;  	case TCP_V4_FLOW:  		return ICE_FLTR_PTYPE_NONF_IPV4_TCP;  	case UDP_V4_FLOW: @@ -137,6 +141,10 @@ int ice_get_ethtool_fdir_entry(struct ice_hw *hw, struct ethtool_rxnfc *cmd)  	memset(&fsp->m_ext, 0, sizeof(fsp->m_ext));  	switch (fsp->flow_type) { +	case ETHER_FLOW: +		fsp->h_u.ether_spec = rule->eth; +		fsp->m_u.ether_spec = rule->eth_mask; +		break;  	case IPV4_USER_FLOW:  		fsp->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4;  		fsp->h_u.usr_ip4_spec.proto = 0; @@ -1194,6 +1202,122 @@ ice_set_fdir_ip6_usr_seg(struct ice_flow_seg_info *seg,  }  /** + * ice_fdir_vlan_valid - validate VLAN data for Flow Director rule + * @dev: network interface device structure + * @fsp: pointer to ethtool Rx flow specification + * + * Return: true if vlan data is valid, false otherwise + */ +static bool ice_fdir_vlan_valid(struct device *dev, +				struct ethtool_rx_flow_spec *fsp) +{ +	if (fsp->m_ext.vlan_etype && !eth_type_vlan(fsp->h_ext.vlan_etype)) +		return false; + +	if (fsp->m_ext.vlan_tci && ntohs(fsp->h_ext.vlan_tci) >= VLAN_N_VID) +		return false; + +	/* proto and vlan must have vlan-etype defined */ +	if (fsp->m_u.ether_spec.h_proto && fsp->m_ext.vlan_tci && +	    !fsp->m_ext.vlan_etype) { +		dev_warn(dev, "Filter with proto and vlan require also vlan-etype"); +		return false; +	} + +	return true; +} + +/** + * ice_set_ether_flow_seg - set address and protocol segments for ether flow + * @dev: network interface device structure + * @seg: flow segment for programming + * @eth_spec: mask data from ethtool + * + * Return: 0 on success and errno in case of error. + */ +static int ice_set_ether_flow_seg(struct device *dev, +				  struct ice_flow_seg_info *seg, +				  struct ethhdr *eth_spec) +{ +	ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_ETH); + +	/* empty rules are not valid */ +	if (is_zero_ether_addr(eth_spec->h_source) && +	    is_zero_ether_addr(eth_spec->h_dest) && +	    !eth_spec->h_proto) +		return -EINVAL; + +	/* Ethertype */ +	if (eth_spec->h_proto == htons(0xFFFF)) { +		ice_flow_set_fld(seg, ICE_FLOW_FIELD_IDX_ETH_TYPE, +				 ICE_FLOW_FLD_OFF_INVAL, +				 ICE_FLOW_FLD_OFF_INVAL, +				 ICE_FLOW_FLD_OFF_INVAL, false); +	} else if (eth_spec->h_proto) { +		dev_warn(dev, "Only 0x0000 or 0xffff proto mask is allowed for flow-type ether"); +		return -EOPNOTSUPP; +	} + +	/* Source MAC address */ +	if (is_broadcast_ether_addr(eth_spec->h_source)) +		ice_flow_set_fld(seg, ICE_FLOW_FIELD_IDX_ETH_SA, +				 ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL, +				 ICE_FLOW_FLD_OFF_INVAL, false); +	else if (!is_zero_ether_addr(eth_spec->h_source)) +		goto err_mask; + +	/* Destination MAC address */ +	if (is_broadcast_ether_addr(eth_spec->h_dest)) +		ice_flow_set_fld(seg, ICE_FLOW_FIELD_IDX_ETH_DA, +				 ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL, +				 ICE_FLOW_FLD_OFF_INVAL, false); +	else if (!is_zero_ether_addr(eth_spec->h_dest)) +		goto err_mask; + +	return 0; + +err_mask: +	dev_warn(dev, "Only 00:00:00:00:00:00 or ff:ff:ff:ff:ff:ff MAC address mask is allowed for flow-type ether"); +	return -EOPNOTSUPP; +} + +/** + * ice_set_fdir_vlan_seg - set vlan segments for ether flow + * @seg: flow segment for programming + * @ext_masks: masks for additional RX flow fields + * + * Return: 0 on success and errno in case of error. + */ +static int +ice_set_fdir_vlan_seg(struct ice_flow_seg_info *seg, +		      struct ethtool_flow_ext *ext_masks) +{ +	ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_VLAN); + +	if (ext_masks->vlan_etype) { +		if (ext_masks->vlan_etype != htons(0xFFFF)) +			return -EOPNOTSUPP; + +		ice_flow_set_fld(seg, ICE_FLOW_FIELD_IDX_S_VLAN, +				 ICE_FLOW_FLD_OFF_INVAL, +				 ICE_FLOW_FLD_OFF_INVAL, +				 ICE_FLOW_FLD_OFF_INVAL, false); +	} + +	if (ext_masks->vlan_tci) { +		if (ext_masks->vlan_tci != htons(0xFFFF)) +			return -EOPNOTSUPP; + +		ice_flow_set_fld(seg, ICE_FLOW_FIELD_IDX_C_VLAN, +				 ICE_FLOW_FLD_OFF_INVAL, +				 ICE_FLOW_FLD_OFF_INVAL, +				 ICE_FLOW_FLD_OFF_INVAL, false); +	} + +	return 0; +} + +/**   * ice_cfg_fdir_xtrct_seq - Configure extraction sequence for the given filter   * @pf: PF structure   * @fsp: pointer to ethtool Rx flow specification @@ -1209,7 +1333,7 @@ ice_cfg_fdir_xtrct_seq(struct ice_pf *pf, struct ethtool_rx_flow_spec *fsp,  	struct device *dev = ice_pf_to_dev(pf);  	enum ice_fltr_ptype fltr_idx;  	struct ice_hw *hw = &pf->hw; -	bool perfect_filter; +	bool perfect_filter = false;  	int ret;  	seg = devm_kzalloc(dev, sizeof(*seg), GFP_KERNEL); @@ -1262,6 +1386,16 @@ ice_cfg_fdir_xtrct_seq(struct ice_pf *pf, struct ethtool_rx_flow_spec *fsp,  		ret = ice_set_fdir_ip6_usr_seg(seg, &fsp->m_u.usr_ip6_spec,  					       &perfect_filter);  		break; +	case ETHER_FLOW: +		ret = ice_set_ether_flow_seg(dev, seg, &fsp->m_u.ether_spec); +		if (!ret && (fsp->m_ext.vlan_etype || fsp->m_ext.vlan_tci)) { +			if (!ice_fdir_vlan_valid(dev, fsp)) { +				ret = -EINVAL; +				break; +			} +			ret = ice_set_fdir_vlan_seg(seg, &fsp->m_ext); +		} +		break;  	default:  		ret = -EINVAL;  	} @@ -1823,6 +1957,10 @@ ice_set_fdir_input_set(struct ice_vsi *vsi, struct ethtool_rx_flow_spec *fsp,  		input->mask.v6.tc = fsp->m_u.usr_ip6_spec.tclass;  		input->mask.v6.proto = fsp->m_u.usr_ip6_spec.l4_proto;  		break; +	case ETHER_FLOW: +		input->eth = fsp->h_u.ether_spec; +		input->eth_mask = fsp->m_u.ether_spec; +		break;  	default:  		/* not doing un-parsed flow types */  		return -EINVAL; diff --git a/drivers/net/ethernet/intel/ice/ice_fdir.c b/drivers/net/ethernet/intel/ice/ice_fdir.c index 1f7b26f38818..26b357c0ae15 100644 --- a/drivers/net/ethernet/intel/ice/ice_fdir.c +++ b/drivers/net/ethernet/intel/ice/ice_fdir.c @@ -4,6 +4,8 @@  #include "ice_common.h"  /* These are training packet headers used to program flow director filters. */ +static const u8 ice_fdir_eth_pkt[22]; +  static const u8 ice_fdir_tcpv4_pkt[] = {  	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  	0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x45, 0x00, @@ -417,6 +419,11 @@ static const u8 ice_fdir_ip6_tun_pkt[] = {  /* Flow Director no-op training packet table */  static const struct ice_fdir_base_pkt ice_fdir_pkt[] = {  	{ +		ICE_FLTR_PTYPE_NONF_ETH, +		sizeof(ice_fdir_eth_pkt), ice_fdir_eth_pkt, +		sizeof(ice_fdir_eth_pkt), ice_fdir_eth_pkt, +	}, +	{  		ICE_FLTR_PTYPE_NONF_IPV4_TCP,  		sizeof(ice_fdir_tcpv4_pkt), ice_fdir_tcpv4_pkt,  		sizeof(ice_fdir_tcp4_tun_pkt), ice_fdir_tcp4_tun_pkt, @@ -914,6 +921,21 @@ ice_fdir_get_gen_prgm_pkt(struct ice_hw *hw, struct ice_fdir_fltr *input,  	 * perspective. The input from user is from Rx filter perspective.  	 */  	switch (flow) { +	case ICE_FLTR_PTYPE_NONF_ETH: +		ice_pkt_insert_mac_addr(loc, input->eth.h_dest); +		ice_pkt_insert_mac_addr(loc + ETH_ALEN, input->eth.h_source); +		if (input->ext_data.vlan_tag || input->ext_data.vlan_type) { +			ice_pkt_insert_u16(loc, ICE_ETH_TYPE_F_OFFSET, +					   input->ext_data.vlan_type); +			ice_pkt_insert_u16(loc, ICE_ETH_VLAN_TCI_OFFSET, +					   input->ext_data.vlan_tag); +			ice_pkt_insert_u16(loc, ICE_ETH_TYPE_VLAN_OFFSET, +					   input->eth.h_proto); +		} else { +			ice_pkt_insert_u16(loc, ICE_ETH_TYPE_F_OFFSET, +					   input->eth.h_proto); +		} +		break;  	case ICE_FLTR_PTYPE_NONF_IPV4_TCP:  		ice_pkt_insert_u32(loc, ICE_IPV4_DST_ADDR_OFFSET,  				   input->ip.v4.src_ip); @@ -1201,6 +1223,10 @@ ice_fdir_comp_rules(struct ice_fdir_fltr *a,  struct ice_fdir_fltr *b)  	 * same flow_type.  	 */  	switch (flow_type) { +	case ICE_FLTR_PTYPE_NONF_ETH: +		if (!memcmp(&a->eth, &b->eth, sizeof(a->eth))) +			return true; +		break;  	case ICE_FLTR_PTYPE_NONF_IPV4_TCP:  	case ICE_FLTR_PTYPE_NONF_IPV4_UDP:  	case ICE_FLTR_PTYPE_NONF_IPV4_SCTP: diff --git a/drivers/net/ethernet/intel/ice/ice_fdir.h b/drivers/net/ethernet/intel/ice/ice_fdir.h index 1b9b84490689..021ecbac7848 100644 --- a/drivers/net/ethernet/intel/ice/ice_fdir.h +++ b/drivers/net/ethernet/intel/ice/ice_fdir.h @@ -8,6 +8,9 @@  #define ICE_FDIR_MAX_RAW_PKT_SIZE	(512 + ICE_FDIR_TUN_PKT_OFF)  /* macros for offsets into packets for flow director programming */ +#define ICE_ETH_TYPE_F_OFFSET		12 +#define ICE_ETH_VLAN_TCI_OFFSET		14 +#define ICE_ETH_TYPE_VLAN_OFFSET	16  #define ICE_IPV4_SRC_ADDR_OFFSET	26  #define ICE_IPV4_DST_ADDR_OFFSET	30  #define ICE_IPV4_TCP_SRC_PORT_OFFSET	34 @@ -159,6 +162,8 @@ struct ice_fdir_fltr {  	struct list_head fltr_node;  	enum ice_fltr_ptype flow_type; +	struct ethhdr eth, eth_mask; +  	union {  		struct ice_fdir_v4 v4;  		struct ice_fdir_v6 v6; diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h index 08ec5efdafe6..4049ae40c4fb 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h @@ -203,6 +203,7 @@ struct ice_phy_info {  enum ice_fltr_ptype {  	/* NONE - used for undef/error */  	ICE_FLTR_PTYPE_NONF_NONE = 0, +	ICE_FLTR_PTYPE_NONF_ETH,  	ICE_FLTR_PTYPE_NONF_IPV4_UDP,  	ICE_FLTR_PTYPE_NONF_IPV4_TCP,  	ICE_FLTR_PTYPE_NONF_IPV4_SCTP, |