Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 17a73f6b authored by Joseph Gasparakis's avatar Joseph Gasparakis Committed by Jeff Kirsher
Browse files

i40e: Flow Director sideband accounting



This patch completes implementation of the ethtool ntuple
rule management interface.  It adds the get, update and delete
interface reset.

Change-ID: Ida7f481d9ee4e405ed91340b858eabb18a52fdb5
Signed-off-by: default avatarJoseph Gasparakis <joseph.gasparakis@intel.com>
Signed-off-by: default avatarAnjali Singhai Jain <anjali.singhai@intel.com>
Signed-off-by: default avatarJesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: default avatarCatherine Sullivan <catherine.sullivan@intel.com>
Tested-by: default avatarKavindya Deegala <kavindya.s.deegala@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent 3415e8ce
Loading
Loading
Loading
Loading
+18 −5
Original line number Diff line number Diff line
@@ -152,8 +152,18 @@ struct i40e_lump_tracking {
};

#define I40E_DEFAULT_ATR_SAMPLE_RATE	20
#define I40E_FDIR_MAX_RAW_PACKET_LOOKUP 512
struct i40e_fdir_data {
#define I40E_FDIR_MAX_RAW_PACKET_SIZE   512
struct i40e_fdir_filter {
	struct hlist_node fdir_node;
	/* filter ipnut set */
	u8 flow_type;
	u8 ip4_proto;
	__be32 dst_ip[4];
	__be32 src_ip[4];
	__be16 src_port;
	__be16 dst_port;
	__be32 sctp_v_tag;
	/* filter control */
	u16 q_index;
	u8  flex_off;
	u8  pctype;
@@ -162,7 +172,6 @@ struct i40e_fdir_data {
	u8  fd_status;
	u16 cnt_index;
	u32 fd_id;
	u8  *raw_packet;
};

#define I40E_ETH_P_LLDP			0x88cc
@@ -210,6 +219,9 @@ struct i40e_pf {
	u8 atr_sample_rate;
	bool wol_en;

	struct hlist_head fdir_filter_list;
	u16 fdir_pf_active_filters;

#ifdef CONFIG_I40E_VXLAN
	__be16  vxlan_ports[I40E_MAX_PF_UDP_OFFLOAD_PORTS];
	u16 pending_vxlan_bitmap;
@@ -534,9 +546,10 @@ struct rtnl_link_stats64 *i40e_get_vsi_stats_struct(struct i40e_vsi *vsi);
int i40e_fetch_switch_configuration(struct i40e_pf *pf,
				    bool printconfig);

int i40e_program_fdir_filter(struct i40e_fdir_data *fdir_data,
int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, u8 *raw_packet,
			     struct i40e_pf *pf, bool add);

int i40e_add_del_fdir(struct i40e_vsi *vsi,
		      struct i40e_fdir_filter *input, bool add);
void i40e_set_ethtool_ops(struct net_device *netdev);
struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi,
					u8 *macaddr, s16 vlan,
+14 −13
Original line number Diff line number Diff line
@@ -1663,21 +1663,22 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
		desc = NULL;
	} else if ((strncmp(cmd_buf, "add fd_filter", 13) == 0) ||
		   (strncmp(cmd_buf, "rem fd_filter", 13) == 0)) {
		struct i40e_fdir_data fd_data;
		struct i40e_fdir_filter fd_data;
		u16 packet_len, i, j = 0;
		char *asc_packet;
		u8 *raw_packet;
		bool add = false;
		int ret;

		asc_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_LOOKUP,
		asc_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE,
				     GFP_KERNEL);
		if (!asc_packet)
			goto command_write_done;

		fd_data.raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_LOOKUP,
		raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE,
				     GFP_KERNEL);

		if (!fd_data.raw_packet) {
		if (!raw_packet) {
			kfree(asc_packet);
			asc_packet = NULL;
			goto command_write_done;
@@ -1698,36 +1699,36 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
				 cnt);
			kfree(asc_packet);
			asc_packet = NULL;
			kfree(fd_data.raw_packet);
			kfree(raw_packet);
			goto command_write_done;
		}

		/* fix packet length if user entered 0 */
		if (packet_len == 0)
			packet_len = I40E_FDIR_MAX_RAW_PACKET_LOOKUP;
			packet_len = I40E_FDIR_MAX_RAW_PACKET_SIZE;

		/* make sure to check the max as well */
		packet_len = min_t(u16,
				   packet_len, I40E_FDIR_MAX_RAW_PACKET_LOOKUP);
				   packet_len, I40E_FDIR_MAX_RAW_PACKET_SIZE);

		for (i = 0; i < packet_len; i++) {
			sscanf(&asc_packet[j], "%2hhx ",
			       &fd_data.raw_packet[i]);
			       &raw_packet[i]);
			j += 3;
		}
		dev_info(&pf->pdev->dev, "FD raw packet dump\n");
		print_hex_dump(KERN_INFO, "FD raw packet: ",
			       DUMP_PREFIX_OFFSET, 16, 1,
			       fd_data.raw_packet, packet_len, true);
		ret = i40e_program_fdir_filter(&fd_data, pf, add);
			       raw_packet, packet_len, true);
		ret = i40e_program_fdir_filter(&fd_data, raw_packet, pf, add);
		if (!ret) {
			dev_info(&pf->pdev->dev, "Filter command send Status : Success\n");
		} else {
			dev_info(&pf->pdev->dev,
				 "Filter command send failed %d\n", ret);
		}
		kfree(fd_data.raw_packet);
		fd_data.raw_packet = NULL;
		kfree(raw_packet);
		raw_packet = NULL;
		kfree(asc_packet);
		asc_packet = NULL;
	} else if (strncmp(cmd_buf, "fd-atr off", 10) == 0) {
+189 −239
Original line number Diff line number Diff line
@@ -62,6 +62,9 @@ static const struct i40e_stats i40e_gstrings_net_stats[] = {
	I40E_NETDEV_STAT(rx_crc_errors),
};

static int i40e_add_del_fdir_ethtool(struct i40e_vsi *vsi,
				     struct ethtool_rxnfc *cmd, bool add);

/* These PF_STATs might look like duplicates of some NETDEV_STATs,
 * but they are separate.  This device supports Virtualization, and
 * as such might have several netdevs supporting VMDq and FCoE going
@@ -1111,6 +1114,84 @@ static int i40e_get_rss_hash_opts(struct i40e_pf *pf, struct ethtool_rxnfc *cmd)
	return 0;
}

/**
 * i40e_get_ethtool_fdir_all - Populates the rule count of a command
 * @pf: Pointer to the physical function struct
 * @cmd: The command to get or set Rx flow classification rules
 * @rule_locs: Array of used rule locations
 *
 * This function populates both the total and actual rule count of
 * the ethtool flow classification command
 *
 * Returns 0 on success or -EMSGSIZE if entry not found
 **/
static int i40e_get_ethtool_fdir_all(struct i40e_pf *pf,
				     struct ethtool_rxnfc *cmd,
				     u32 *rule_locs)
{
	struct i40e_fdir_filter *rule;
	struct hlist_node *node2;
	int cnt = 0;

	/* report total rule count */
	cmd->data = pf->hw.fdir_shared_filter_count +
		    pf->fdir_pf_filter_count;

	hlist_for_each_entry_safe(rule, node2,
				  &pf->fdir_filter_list, fdir_node) {
		if (cnt == cmd->rule_cnt)
			return -EMSGSIZE;

		rule_locs[cnt] = rule->fd_id;
		cnt++;
	}

	cmd->rule_cnt = cnt;

	return 0;
}

/**
 * i40e_get_ethtool_fdir_entry - Look up a filter based on Rx flow
 * @pf: Pointer to the physical function struct
 * @cmd: The command to get or set Rx flow classification rules
 *
 * This function looks up a filter based on the Rx flow classification
 * command and fills the flow spec info for it if found
 *
 * Returns 0 on success or -EINVAL if filter not found
 **/
static int i40e_get_ethtool_fdir_entry(struct i40e_pf *pf,
				       struct ethtool_rxnfc *cmd)
{
	struct ethtool_rx_flow_spec *fsp =
			(struct ethtool_rx_flow_spec *)&cmd->fs;
	struct i40e_fdir_filter *rule = NULL;
	struct hlist_node *node2;

	/* report total rule count */
	cmd->data = pf->hw.fdir_shared_filter_count +
		    pf->fdir_pf_filter_count;

	hlist_for_each_entry_safe(rule, node2,
				  &pf->fdir_filter_list, fdir_node) {
		if (fsp->location <= rule->fd_id)
			break;
	}

	if (!rule || fsp->location != rule->fd_id)
		return -EINVAL;

	fsp->flow_type = rule->flow_type;
	fsp->h_u.tcp_ip4_spec.psrc = rule->src_port;
	fsp->h_u.tcp_ip4_spec.pdst = rule->dst_port;
	fsp->h_u.tcp_ip4_spec.ip4src = rule->src_ip[0];
	fsp->h_u.tcp_ip4_spec.ip4dst = rule->dst_ip[0];
	fsp->ring_cookie = rule->q_index;

	return 0;
}

/**
 * i40e_get_rxnfc - command to get RX flow classification rules
 * @netdev: network interface device structure
@@ -1135,15 +1216,15 @@ static int i40e_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
		ret = i40e_get_rss_hash_opts(pf, cmd);
		break;
	case ETHTOOL_GRXCLSRLCNT:
		cmd->rule_cnt = 10;
		cmd->rule_cnt = pf->fdir_pf_active_filters;
		ret = 0;
		break;
	case ETHTOOL_GRXCLSRULE:
		ret = 0;
		ret = i40e_get_ethtool_fdir_entry(pf, cmd);
		break;
	case ETHTOOL_GRXCLSRLALL:
		cmd->data = 500;
		ret = 0;
		ret = i40e_get_ethtool_fdir_all(pf, cmd, rule_locs);
		break;
	default:
		break;
	}
@@ -1274,289 +1355,158 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc)
	return 0;
}

#define IP_HEADER_OFFSET 14
#define I40E_UDPIP_DUMMY_PACKET_LEN 42
/**
 * i40e_add_del_fdir_udpv4 - Add/Remove UDPv4 Flow Director filters for
 * a specific flow spec
 * @vsi: pointer to the targeted VSI
 * @fd_data: the flow director data required from the FDir descriptor
 * @ethtool_rx_flow_spec: the flow spec
 * @add: true adds a filter, false removes it
 * i40e_update_ethtool_fdir_entry - Updates the fdir filter entry
 * @vsi: Pointer to the targeted VSI
 * @input: The filter to update or NULL to indicate deletion
 * @sw_idx: Software index to the filter
 * @cmd: The command to get or set Rx flow classification rules
 *
 * This function updates (or deletes) a Flow Director entry from
 * the hlist of the corresponding PF
 *
 * Returns 0 if the filters were successfully added or removed
 * Returns 0 on success
 **/
static int i40e_add_del_fdir_udpv4(struct i40e_vsi *vsi,
				   struct i40e_fdir_data *fd_data,
				   struct ethtool_rx_flow_spec *fsp, bool add)
static int i40e_update_ethtool_fdir_entry(struct i40e_vsi *vsi,
					  struct i40e_fdir_filter *input,
					  u16 sw_idx,
					  struct ethtool_rxnfc *cmd)
{
	struct i40e_fdir_filter *rule, *parent;
	struct i40e_pf *pf = vsi->back;
	struct udphdr *udp;
	struct iphdr *ip;
	bool err = false;
	int ret;
	int i;
	char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0,
			 0x45, 0, 0, 0x1c, 0, 0, 0x40, 0, 0x40, 0x11,
			 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
			 0, 0, 0, 0, 0, 0, 0, 0};

	memcpy(fd_data->raw_packet, packet, I40E_UDPIP_DUMMY_PACKET_LEN);

	ip = (struct iphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET);
	udp = (struct udphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET
	      + sizeof(struct iphdr));

	ip->saddr = fsp->h_u.tcp_ip4_spec.ip4src;
	ip->daddr = fsp->h_u.tcp_ip4_spec.ip4dst;
	udp->source = fsp->h_u.tcp_ip4_spec.psrc;
	udp->dest = fsp->h_u.tcp_ip4_spec.pdst;
	struct hlist_node *node2;
	int err = -EINVAL;

	for (i = I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP;
	     i <= I40E_FILTER_PCTYPE_NONF_IPV4_UDP; i++) {
		fd_data->pctype = i;
		ret = i40e_program_fdir_filter(fd_data, pf, add);
	parent = NULL;
	rule = NULL;

		if (ret) {
			dev_info(&pf->pdev->dev,
				 "Filter command send failed for PCTYPE %d (ret = %d)\n",
				 fd_data->pctype, ret);
			err = true;
		} else {
			dev_info(&pf->pdev->dev,
				 "Filter OK for PCTYPE %d (ret = %d)\n",
				 fd_data->pctype, ret);
		}
	hlist_for_each_entry_safe(rule, node2,
				  &pf->fdir_filter_list, fdir_node) {
		/* hash found, or no matching entry */
		if (rule->fd_id >= sw_idx)
			break;
		parent = rule;
	}

	return err ? -EOPNOTSUPP : 0;
	/* if there is an old rule occupying our place remove it */
	if (rule && (rule->fd_id == sw_idx)) {
		if (!input || (rule->fd_id != input->fd_id)) {
			cmd->fs.flow_type = rule->flow_type;
			err = i40e_add_del_fdir_ethtool(vsi, cmd, false);
		}

#define I40E_TCPIP_DUMMY_PACKET_LEN 54
/**
 * i40e_add_del_fdir_tcpv4 - Add/Remove TCPv4 Flow Director filters for
 * a specific flow spec
 * @vsi: pointer to the targeted VSI
 * @fd_data: the flow director data required from the FDir descriptor
 * @ethtool_rx_flow_spec: the flow spec
 * @add: true adds a filter, false removes it
 *
 * Returns 0 if the filters were successfully added or removed
 **/
static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi,
				   struct i40e_fdir_data *fd_data,
				   struct ethtool_rx_flow_spec *fsp, bool add)
{
	struct i40e_pf *pf = vsi->back;
	struct tcphdr *tcp;
	struct iphdr *ip;
	bool err = false;
	int ret;
	/* Dummy packet */
	char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0,
			 0x45, 0, 0, 0x28, 0, 0, 0x40, 0, 0x40, 0x6,
			 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
			 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
			 0x80, 0x11, 0x0, 0x72, 0, 0, 0, 0};

	memcpy(fd_data->raw_packet, packet, I40E_TCPIP_DUMMY_PACKET_LEN);

	ip = (struct iphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET);
	tcp = (struct tcphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET
	      + sizeof(struct iphdr));

	ip->daddr = fsp->h_u.tcp_ip4_spec.ip4dst;
	tcp->dest = fsp->h_u.tcp_ip4_spec.pdst;
	ip->saddr = fsp->h_u.tcp_ip4_spec.ip4src;
	tcp->source = fsp->h_u.tcp_ip4_spec.psrc;

	if (add) {
		if (pf->flags & I40E_FLAG_FD_ATR_ENABLED) {
			dev_info(&pf->pdev->dev, "Forcing ATR off, sideband rules for TCP/IPv4 flow being applied\n");
			pf->flags &= ~I40E_FLAG_FD_ATR_ENABLED;
		}
		hlist_del(&rule->fdir_node);
		kfree(rule);
		pf->fdir_pf_active_filters--;
	}

	fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN;
	ret = i40e_program_fdir_filter(fd_data, pf, add);
	/* If no input this was a delete, err should be 0 if a rule was
	 * successfully found and removed from the list else -EINVAL
	 */
	if (!input)
		return err;

	if (ret) {
		dev_info(&pf->pdev->dev,
			 "Filter command send failed for PCTYPE %d (ret = %d)\n",
			 fd_data->pctype, ret);
		err = true;
	} else {
		dev_info(&pf->pdev->dev, "Filter OK for PCTYPE %d (ret = %d)\n",
			 fd_data->pctype, ret);
	}
	/* initialize node and set software index */
	INIT_HLIST_NODE(&input->fdir_node);

	fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP;
	/* add filter to the list */
	if (parent)
		hlist_add_after(&parent->fdir_node, &input->fdir_node);
	else
		hlist_add_head(&input->fdir_node,
			       &pf->fdir_filter_list);

	ret = i40e_program_fdir_filter(fd_data, pf, add);
	if (ret) {
		dev_info(&pf->pdev->dev,
			 "Filter command send failed for PCTYPE %d (ret = %d)\n",
			 fd_data->pctype, ret);
		err = true;
	} else {
		dev_info(&pf->pdev->dev, "Filter OK for PCTYPE %d (ret = %d)\n",
			  fd_data->pctype, ret);
	}
	/* update counts */
	pf->fdir_pf_active_filters++;

	return err ? -EOPNOTSUPP : 0;
	return 0;
}

/**
 * i40e_add_del_fdir_sctpv4 - Add/Remove SCTPv4 Flow Director filters for
 * a specific flow spec
 * @vsi: pointer to the targeted VSI
 * @fd_data: the flow director data required from the FDir descriptor
 * @ethtool_rx_flow_spec: the flow spec
 * @add: true adds a filter, false removes it
 * i40e_del_fdir_entry - Deletes a Flow Director filter entry
 * @vsi: Pointer to the targeted VSI
 * @cmd: The command to get or set Rx flow classification rules
 *
 * Returns 0 if the filters were successfully added or removed
 **/
static int i40e_add_del_fdir_sctpv4(struct i40e_vsi *vsi,
				    struct i40e_fdir_data *fd_data,
				    struct ethtool_rx_flow_spec *fsp, bool add)
{
	return -EOPNOTSUPP;
}

#define I40E_IP_DUMMY_PACKET_LEN 34
/**
 * i40e_add_del_fdir_ipv4 - Add/Remove IPv4 Flow Director filters for
 * a specific flow spec
 * @vsi: pointer to the targeted VSI
 * @fd_data: the flow director data required for the FDir descriptor
 * @fsp: the ethtool flow spec
 * @add: true adds a filter, false removes it
 * The function removes a Flow Director filter entry from the
 * hlist of the corresponding PF
 *
 * Returns 0 if the filters were successfully added or removed
 **/
static int i40e_add_del_fdir_ipv4(struct i40e_vsi *vsi,
				  struct i40e_fdir_data *fd_data,
				  struct ethtool_rx_flow_spec *fsp, bool add)
 * Returns 0 on success
 */
static int i40e_del_fdir_entry(struct i40e_vsi *vsi,
			       struct ethtool_rxnfc *cmd)
{
	struct ethtool_rx_flow_spec *fsp =
		(struct ethtool_rx_flow_spec *)&cmd->fs;
	struct i40e_pf *pf = vsi->back;
	struct iphdr *ip;
	bool err = false;
	int ret;
	int i;
	char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0,
			 0x45, 0, 0, 0x14, 0, 0, 0x40, 0, 0x40, 0x10,
			 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

	memcpy(fd_data->raw_packet, packet, I40E_IP_DUMMY_PACKET_LEN);
	ip = (struct iphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET);

	ip->saddr = fsp->h_u.usr_ip4_spec.ip4src;
	ip->daddr = fsp->h_u.usr_ip4_spec.ip4dst;
	ip->protocol = fsp->h_u.usr_ip4_spec.proto;

	for (i = I40E_FILTER_PCTYPE_NONF_IPV4_OTHER;
	     i <= I40E_FILTER_PCTYPE_FRAG_IPV4;	i++) {
		fd_data->pctype = i;
		ret = i40e_program_fdir_filter(fd_data, pf, add);
	int ret = 0;

		if (ret) {
			dev_info(&pf->pdev->dev,
				 "Filter command send failed for PCTYPE %d (ret = %d)\n",
				 fd_data->pctype, ret);
			err = true;
		} else {
			dev_info(&pf->pdev->dev,
				 "Filter OK for PCTYPE %d (ret = %d)\n",
				 fd_data->pctype, ret);
		}
	}
	ret = i40e_update_ethtool_fdir_entry(vsi, NULL, fsp->location, cmd);

	return err ? -EOPNOTSUPP : 0;
	return ret;
}

/**
 * i40e_add_del_fdir_ethtool - Add/Remove Flow Director filters for
 * a specific flow spec based on their protocol
 * i40e_add_del_fdir_ethtool - Add/Remove Flow Director filters
 * @vsi: pointer to the targeted VSI
 * @cmd: command to get or set RX flow classification rules
 * @add: true adds a filter, false removes it
 *
 * Returns 0 if the filters were successfully added or removed
 * Add/Remove Flow Director filters for a specific flow spec based on their
 * protocol.  Returns 0 if the filters were successfully added or removed.
 **/
static int i40e_add_del_fdir_ethtool(struct i40e_vsi *vsi,
				     struct ethtool_rxnfc *cmd, bool add)
{
	struct i40e_fdir_data fd_data;
	int ret = -EINVAL;
	struct ethtool_rx_flow_spec *fsp;
	struct i40e_fdir_filter *input;
	struct i40e_pf *pf;
	struct ethtool_rx_flow_spec *fsp =
		(struct ethtool_rx_flow_spec *)&cmd->fs;
	int ret = -EINVAL;

	if (!vsi)
		return -EINVAL;

	fsp = (struct ethtool_rx_flow_spec *)&cmd->fs;
	pf = vsi->back;

	if ((fsp->ring_cookie != RX_CLS_FLOW_DISC) &&
	    (fsp->ring_cookie >= vsi->num_queue_pairs))
	if (fsp->location >= (pf->hw.func_caps.fd_filters_best_effort +
			      pf->hw.func_caps.fd_filters_guaranteed)) {
		return -EINVAL;
	}

	if ((fsp->ring_cookie >= vsi->num_queue_pairs) && add)
		return -EINVAL;

	/* Populate the Flow Director that we have at the moment
	 * and allocate the raw packet buffer for the calling functions
	 */
	fd_data.raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_LOOKUP,
				     GFP_KERNEL);
	input = kzalloc(sizeof(*input), GFP_KERNEL);

	if (!fd_data.raw_packet) {
		dev_info(&pf->pdev->dev, "Could not allocate memory\n");
	if (!input)
		return -ENOMEM;
	}

	fd_data.q_index = fsp->ring_cookie;
	fd_data.flex_off = 0;
	fd_data.pctype = 0;
	fd_data.dest_vsi = vsi->id;
	fd_data.dest_ctl = I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX;
	fd_data.fd_status = I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID;
	fd_data.cnt_index = 0;
	fd_data.fd_id = 0;

	switch (fsp->flow_type & ~FLOW_EXT) {
	case TCP_V4_FLOW:
		ret = i40e_add_del_fdir_tcpv4(vsi, &fd_data, fsp, add);
		break;
	case UDP_V4_FLOW:
		ret = i40e_add_del_fdir_udpv4(vsi, &fd_data, fsp, add);
		break;
	case SCTP_V4_FLOW:
		ret = i40e_add_del_fdir_sctpv4(vsi, &fd_data, fsp, add);
		break;
	case IPV4_FLOW:
		ret = i40e_add_del_fdir_ipv4(vsi, &fd_data, fsp, add);
		break;
	case IP_USER_FLOW:
		switch (fsp->h_u.usr_ip4_spec.proto) {
		case IPPROTO_TCP:
			ret = i40e_add_del_fdir_tcpv4(vsi, &fd_data, fsp, add);
			break;
		case IPPROTO_UDP:
			ret = i40e_add_del_fdir_udpv4(vsi, &fd_data, fsp, add);
			break;
		case IPPROTO_SCTP:
			ret = i40e_add_del_fdir_sctpv4(vsi, &fd_data, fsp, add);
			break;
		default:
			ret = i40e_add_del_fdir_ipv4(vsi, &fd_data, fsp, add);
			break;
		}
		break;
	default:
		dev_info(&pf->pdev->dev, "Could not specify spec type\n");
		ret = -EINVAL;
	input->fd_id = fsp->location;

	input->q_index = fsp->ring_cookie;
	input->flex_off = 0;
	input->pctype = 0;
	input->dest_vsi = vsi->id;
	input->dest_ctl = I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX;
	input->fd_status = I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID;
	input->cnt_index = 0;
	input->flow_type = fsp->flow_type;
	input->ip4_proto = fsp->h_u.usr_ip4_spec.proto;
	input->src_port = fsp->h_u.tcp_ip4_spec.psrc;
	input->dst_port = fsp->h_u.tcp_ip4_spec.pdst;
	input->src_ip[0] = fsp->h_u.tcp_ip4_spec.ip4src;
	input->dst_ip[0] = fsp->h_u.tcp_ip4_spec.ip4dst;

	ret = i40e_add_del_fdir(vsi, input, add);
	if (ret) {
		kfree(input);
		return ret;
	}

	kfree(fd_data.raw_packet);
	fd_data.raw_packet = NULL;
	if (!ret && add)
		i40e_update_ethtool_fdir_entry(vsi, input, fsp->location, NULL);
	else
		kfree(input);

	return ret;
}
@@ -1583,7 +1533,7 @@ static int i40e_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
		ret = i40e_add_del_fdir_ethtool(vsi, cmd, true);
		break;
	case ETHTOOL_SRXCLSRLDEL:
		ret = i40e_add_del_fdir_ethtool(vsi, cmd, false);
		ret = i40e_del_fdir_entry(vsi, cmd);
		break;
	default:
		break;
+43 −1
Original line number Diff line number Diff line
@@ -2420,6 +2420,25 @@ static void i40e_set_vsi_rx_mode(struct i40e_vsi *vsi)
		i40e_set_rx_mode(vsi->netdev);
}

/**
 * i40e_fdir_filter_restore - Restore the Sideband Flow Director filters
 * @vsi: Pointer to the targeted VSI
 *
 * This function replays the hlist on the hw where all the SB Flow Director
 * filters were saved.
 **/
static void i40e_fdir_filter_restore(struct i40e_vsi *vsi)
{
	struct i40e_fdir_filter *filter;
	struct i40e_pf *pf = vsi->back;
	struct hlist_node *node;

	hlist_for_each_entry_safe(filter, node,
				  &pf->fdir_filter_list, fdir_node) {
		i40e_add_del_fdir(vsi, filter, true);
	}
}

/**
 * i40e_vsi_configure - Set up the VSI for action
 * @vsi: the VSI being configured
@@ -2431,6 +2450,8 @@ static int i40e_vsi_configure(struct i40e_vsi *vsi)
	i40e_set_vsi_rx_mode(vsi);
	i40e_restore_vlan(vsi);
	i40e_vsi_config_dcb_rings(vsi);
	if (vsi->type == I40E_VSI_FDIR)
		i40e_fdir_filter_restore(vsi);
	err = i40e_vsi_configure_tx(vsi);
	if (!err)
		err = i40e_vsi_configure_rx(vsi);
@@ -4267,6 +4288,26 @@ static int i40e_open(struct net_device *netdev)
	return err;
}

/**
 * i40e_fdir_filter_exit - Cleans up the Flow Director accounting
 * @pf: Pointer to pf
 *
 * This function destroys the hlist where all the Flow Director
 * filters were saved.
 **/
static void i40e_fdir_filter_exit(struct i40e_pf *pf)
{
	struct i40e_fdir_filter *filter;
	struct hlist_node *node2;

	hlist_for_each_entry_safe(filter, node2,
				  &pf->fdir_filter_list, fdir_node) {
		hlist_del(&filter->fdir_node);
		kfree(filter);
	}
	pf->fdir_pf_active_filters = 0;
}

/**
 * i40e_close - Disables a network interface
 * @netdev: network interface device structure
@@ -5131,9 +5172,9 @@ static void i40e_fdir_sb_setup(struct i40e_pf *pf)
		err = i40e_up_complete(vsi);
		if (err)
			goto err_up_complete;
		clear_bit(__I40E_NEEDS_RESTART, &vsi->state);
	}

	clear_bit(__I40E_NEEDS_RESTART, &vsi->state);
	return;

err_up_complete:
@@ -5156,6 +5197,7 @@ static void i40e_fdir_teardown(struct i40e_pf *pf)
{
	int i;

	i40e_fdir_filter_exit(pf);
	for (i = 0; i < pf->hw.func_caps.num_vsis; i++) {
		if (pf->vsi[i] && pf->vsi[i]->type == I40E_VSI_FDIR) {
			i40e_vsi_release(pf->vsi[i]);
+271 −6

File changed.

Preview size limit exceeded, changes collapsed.