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: Joseph Gasparakis <joseph.gasparakis@intel.com> Signed-off-by: Anjali Singhai Jain <anjali.singhai@intel.com> Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com> Signed-off-by: Catherine Sullivan <catherine.sullivan@intel.com> Tested-by: Kavindya Deegala <kavindya.s.deegala@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
This commit is contained in:
parent
3415e8ce0d
commit
17a73f6b14
5 changed files with 544 additions and 273 deletions
|
@ -152,8 +152,18 @@ struct i40e_lump_tracking {
|
||||||
};
|
};
|
||||||
|
|
||||||
#define I40E_DEFAULT_ATR_SAMPLE_RATE 20
|
#define I40E_DEFAULT_ATR_SAMPLE_RATE 20
|
||||||
#define I40E_FDIR_MAX_RAW_PACKET_LOOKUP 512
|
#define I40E_FDIR_MAX_RAW_PACKET_SIZE 512
|
||||||
struct i40e_fdir_data {
|
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;
|
u16 q_index;
|
||||||
u8 flex_off;
|
u8 flex_off;
|
||||||
u8 pctype;
|
u8 pctype;
|
||||||
|
@ -162,7 +172,6 @@ struct i40e_fdir_data {
|
||||||
u8 fd_status;
|
u8 fd_status;
|
||||||
u16 cnt_index;
|
u16 cnt_index;
|
||||||
u32 fd_id;
|
u32 fd_id;
|
||||||
u8 *raw_packet;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define I40E_ETH_P_LLDP 0x88cc
|
#define I40E_ETH_P_LLDP 0x88cc
|
||||||
|
@ -210,6 +219,9 @@ struct i40e_pf {
|
||||||
u8 atr_sample_rate;
|
u8 atr_sample_rate;
|
||||||
bool wol_en;
|
bool wol_en;
|
||||||
|
|
||||||
|
struct hlist_head fdir_filter_list;
|
||||||
|
u16 fdir_pf_active_filters;
|
||||||
|
|
||||||
#ifdef CONFIG_I40E_VXLAN
|
#ifdef CONFIG_I40E_VXLAN
|
||||||
__be16 vxlan_ports[I40E_MAX_PF_UDP_OFFLOAD_PORTS];
|
__be16 vxlan_ports[I40E_MAX_PF_UDP_OFFLOAD_PORTS];
|
||||||
u16 pending_vxlan_bitmap;
|
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,
|
int i40e_fetch_switch_configuration(struct i40e_pf *pf,
|
||||||
bool printconfig);
|
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);
|
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);
|
void i40e_set_ethtool_ops(struct net_device *netdev);
|
||||||
struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi,
|
struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi,
|
||||||
u8 *macaddr, s16 vlan,
|
u8 *macaddr, s16 vlan,
|
||||||
|
|
|
@ -1663,21 +1663,22 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
|
||||||
desc = NULL;
|
desc = NULL;
|
||||||
} else if ((strncmp(cmd_buf, "add fd_filter", 13) == 0) ||
|
} else if ((strncmp(cmd_buf, "add fd_filter", 13) == 0) ||
|
||||||
(strncmp(cmd_buf, "rem 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;
|
u16 packet_len, i, j = 0;
|
||||||
char *asc_packet;
|
char *asc_packet;
|
||||||
|
u8 *raw_packet;
|
||||||
bool add = false;
|
bool add = false;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
asc_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_LOOKUP,
|
asc_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE,
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!asc_packet)
|
if (!asc_packet)
|
||||||
goto command_write_done;
|
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);
|
GFP_KERNEL);
|
||||||
|
|
||||||
if (!fd_data.raw_packet) {
|
if (!raw_packet) {
|
||||||
kfree(asc_packet);
|
kfree(asc_packet);
|
||||||
asc_packet = NULL;
|
asc_packet = NULL;
|
||||||
goto command_write_done;
|
goto command_write_done;
|
||||||
|
@ -1698,36 +1699,36 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
|
||||||
cnt);
|
cnt);
|
||||||
kfree(asc_packet);
|
kfree(asc_packet);
|
||||||
asc_packet = NULL;
|
asc_packet = NULL;
|
||||||
kfree(fd_data.raw_packet);
|
kfree(raw_packet);
|
||||||
goto command_write_done;
|
goto command_write_done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fix packet length if user entered 0 */
|
/* fix packet length if user entered 0 */
|
||||||
if (packet_len == 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 */
|
/* make sure to check the max as well */
|
||||||
packet_len = min_t(u16,
|
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++) {
|
for (i = 0; i < packet_len; i++) {
|
||||||
sscanf(&asc_packet[j], "%2hhx ",
|
sscanf(&asc_packet[j], "%2hhx ",
|
||||||
&fd_data.raw_packet[i]);
|
&raw_packet[i]);
|
||||||
j += 3;
|
j += 3;
|
||||||
}
|
}
|
||||||
dev_info(&pf->pdev->dev, "FD raw packet dump\n");
|
dev_info(&pf->pdev->dev, "FD raw packet dump\n");
|
||||||
print_hex_dump(KERN_INFO, "FD raw packet: ",
|
print_hex_dump(KERN_INFO, "FD raw packet: ",
|
||||||
DUMP_PREFIX_OFFSET, 16, 1,
|
DUMP_PREFIX_OFFSET, 16, 1,
|
||||||
fd_data.raw_packet, packet_len, true);
|
raw_packet, packet_len, true);
|
||||||
ret = i40e_program_fdir_filter(&fd_data, pf, add);
|
ret = i40e_program_fdir_filter(&fd_data, raw_packet, pf, add);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
dev_info(&pf->pdev->dev, "Filter command send Status : Success\n");
|
dev_info(&pf->pdev->dev, "Filter command send Status : Success\n");
|
||||||
} else {
|
} else {
|
||||||
dev_info(&pf->pdev->dev,
|
dev_info(&pf->pdev->dev,
|
||||||
"Filter command send failed %d\n", ret);
|
"Filter command send failed %d\n", ret);
|
||||||
}
|
}
|
||||||
kfree(fd_data.raw_packet);
|
kfree(raw_packet);
|
||||||
fd_data.raw_packet = NULL;
|
raw_packet = NULL;
|
||||||
kfree(asc_packet);
|
kfree(asc_packet);
|
||||||
asc_packet = NULL;
|
asc_packet = NULL;
|
||||||
} else if (strncmp(cmd_buf, "fd-atr off", 10) == 0) {
|
} else if (strncmp(cmd_buf, "fd-atr off", 10) == 0) {
|
||||||
|
|
|
@ -62,6 +62,9 @@ static const struct i40e_stats i40e_gstrings_net_stats[] = {
|
||||||
I40E_NETDEV_STAT(rx_crc_errors),
|
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,
|
/* These PF_STATs might look like duplicates of some NETDEV_STATs,
|
||||||
* but they are separate. This device supports Virtualization, and
|
* but they are separate. This device supports Virtualization, and
|
||||||
* as such might have several netdevs supporting VMDq and FCoE going
|
* 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;
|
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
|
* i40e_get_rxnfc - command to get RX flow classification rules
|
||||||
* @netdev: network interface device structure
|
* @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);
|
ret = i40e_get_rss_hash_opts(pf, cmd);
|
||||||
break;
|
break;
|
||||||
case ETHTOOL_GRXCLSRLCNT:
|
case ETHTOOL_GRXCLSRLCNT:
|
||||||
cmd->rule_cnt = 10;
|
cmd->rule_cnt = pf->fdir_pf_active_filters;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
break;
|
break;
|
||||||
case ETHTOOL_GRXCLSRULE:
|
case ETHTOOL_GRXCLSRULE:
|
||||||
ret = 0;
|
ret = i40e_get_ethtool_fdir_entry(pf, cmd);
|
||||||
break;
|
break;
|
||||||
case ETHTOOL_GRXCLSRLALL:
|
case ETHTOOL_GRXCLSRLALL:
|
||||||
cmd->data = 500;
|
ret = i40e_get_ethtool_fdir_all(pf, cmd, rule_locs);
|
||||||
ret = 0;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1274,289 +1355,158 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc)
|
||||||
return 0;
|
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
|
* i40e_update_ethtool_fdir_entry - Updates the fdir filter entry
|
||||||
* a specific flow spec
|
* @vsi: Pointer to the targeted VSI
|
||||||
* @vsi: pointer to the targeted VSI
|
* @input: The filter to update or NULL to indicate deletion
|
||||||
* @fd_data: the flow director data required from the FDir descriptor
|
* @sw_idx: Software index to the filter
|
||||||
* @ethtool_rx_flow_spec: the flow spec
|
* @cmd: The 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
|
* This function updates (or deletes) a Flow Director entry from
|
||||||
|
* the hlist of the corresponding PF
|
||||||
|
*
|
||||||
|
* Returns 0 on success
|
||||||
**/
|
**/
|
||||||
static int i40e_add_del_fdir_udpv4(struct i40e_vsi *vsi,
|
static int i40e_update_ethtool_fdir_entry(struct i40e_vsi *vsi,
|
||||||
struct i40e_fdir_data *fd_data,
|
struct i40e_fdir_filter *input,
|
||||||
struct ethtool_rx_flow_spec *fsp, bool add)
|
u16 sw_idx,
|
||||||
|
struct ethtool_rxnfc *cmd)
|
||||||
{
|
{
|
||||||
|
struct i40e_fdir_filter *rule, *parent;
|
||||||
struct i40e_pf *pf = vsi->back;
|
struct i40e_pf *pf = vsi->back;
|
||||||
struct udphdr *udp;
|
struct hlist_node *node2;
|
||||||
struct iphdr *ip;
|
int err = -EINVAL;
|
||||||
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);
|
parent = NULL;
|
||||||
|
rule = NULL;
|
||||||
|
|
||||||
ip = (struct iphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET);
|
hlist_for_each_entry_safe(rule, node2,
|
||||||
udp = (struct udphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET
|
&pf->fdir_filter_list, fdir_node) {
|
||||||
+ sizeof(struct iphdr));
|
/* hash found, or no matching entry */
|
||||||
|
if (rule->fd_id >= sw_idx)
|
||||||
ip->saddr = fsp->h_u.tcp_ip4_spec.ip4src;
|
break;
|
||||||
ip->daddr = fsp->h_u.tcp_ip4_spec.ip4dst;
|
parent = rule;
|
||||||
udp->source = fsp->h_u.tcp_ip4_spec.psrc;
|
|
||||||
udp->dest = fsp->h_u.tcp_ip4_spec.pdst;
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
hlist_del(&rule->fdir_node);
|
||||||
|
kfree(rule);
|
||||||
|
pf->fdir_pf_active_filters--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
/* initialize node and set software index */
|
||||||
|
INIT_HLIST_NODE(&input->fdir_node);
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
/* update counts */
|
||||||
|
pf->fdir_pf_active_filters++;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define I40E_TCPIP_DUMMY_PACKET_LEN 54
|
|
||||||
/**
|
/**
|
||||||
* i40e_add_del_fdir_tcpv4 - Add/Remove TCPv4 Flow Director filters for
|
* i40e_del_fdir_entry - Deletes a Flow Director filter entry
|
||||||
* a specific flow spec
|
* @vsi: Pointer to the targeted VSI
|
||||||
* @vsi: pointer to the targeted VSI
|
* @cmd: The command to get or set Rx flow classification rules
|
||||||
* @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
|
* The function removes a Flow Director filter entry from the
|
||||||
**/
|
* hlist of the corresponding PF
|
||||||
static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi,
|
*
|
||||||
struct i40e_fdir_data *fd_data,
|
* Returns 0 on success
|
||||||
struct ethtool_rx_flow_spec *fsp, bool add)
|
*/
|
||||||
|
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 i40e_pf *pf = vsi->back;
|
||||||
struct tcphdr *tcp;
|
int ret = 0;
|
||||||
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);
|
ret = i40e_update_ethtool_fdir_entry(vsi, NULL, fsp->location, cmd);
|
||||||
|
|
||||||
ip = (struct iphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET);
|
return ret;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN;
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP;
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return err ? -EOPNOTSUPP : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* i40e_add_del_fdir_sctpv4 - Add/Remove SCTPv4 Flow Director filters for
|
* i40e_add_del_fdir_ethtool - Add/Remove Flow Director filters
|
||||||
* 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_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
|
|
||||||
*
|
|
||||||
* 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)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return err ? -EOPNOTSUPP : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* i40e_add_del_fdir_ethtool - Add/Remove Flow Director filters for
|
|
||||||
* a specific flow spec based on their protocol
|
|
||||||
* @vsi: pointer to the targeted VSI
|
* @vsi: pointer to the targeted VSI
|
||||||
* @cmd: command to get or set RX flow classification rules
|
* @cmd: command to get or set RX flow classification rules
|
||||||
* @add: true adds a filter, false removes it
|
* @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,
|
static int i40e_add_del_fdir_ethtool(struct i40e_vsi *vsi,
|
||||||
struct ethtool_rxnfc *cmd, bool add)
|
struct ethtool_rxnfc *cmd, bool add)
|
||||||
{
|
{
|
||||||
struct i40e_fdir_data fd_data;
|
struct ethtool_rx_flow_spec *fsp;
|
||||||
int ret = -EINVAL;
|
struct i40e_fdir_filter *input;
|
||||||
struct i40e_pf *pf;
|
struct i40e_pf *pf;
|
||||||
struct ethtool_rx_flow_spec *fsp =
|
int ret = -EINVAL;
|
||||||
(struct ethtool_rx_flow_spec *)&cmd->fs;
|
|
||||||
|
|
||||||
if (!vsi)
|
if (!vsi)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
fsp = (struct ethtool_rx_flow_spec *)&cmd->fs;
|
||||||
pf = vsi->back;
|
pf = vsi->back;
|
||||||
|
|
||||||
if ((fsp->ring_cookie != RX_CLS_FLOW_DISC) &&
|
if (fsp->location >= (pf->hw.func_caps.fd_filters_best_effort +
|
||||||
(fsp->ring_cookie >= vsi->num_queue_pairs))
|
pf->hw.func_caps.fd_filters_guaranteed)) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((fsp->ring_cookie >= vsi->num_queue_pairs) && add)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* Populate the Flow Director that we have at the moment
|
input = kzalloc(sizeof(*input), GFP_KERNEL);
|
||||||
* and allocate the raw packet buffer for the calling functions
|
|
||||||
*/
|
|
||||||
fd_data.raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_LOOKUP,
|
|
||||||
GFP_KERNEL);
|
|
||||||
|
|
||||||
if (!fd_data.raw_packet) {
|
if (!input)
|
||||||
dev_info(&pf->pdev->dev, "Could not allocate memory\n");
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
fd_data.q_index = fsp->ring_cookie;
|
if (!ret && add)
|
||||||
fd_data.flex_off = 0;
|
i40e_update_ethtool_fdir_entry(vsi, input, fsp->location, NULL);
|
||||||
fd_data.pctype = 0;
|
else
|
||||||
fd_data.dest_vsi = vsi->id;
|
kfree(input);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
kfree(fd_data.raw_packet);
|
|
||||||
fd_data.raw_packet = NULL;
|
|
||||||
|
|
||||||
return ret;
|
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);
|
ret = i40e_add_del_fdir_ethtool(vsi, cmd, true);
|
||||||
break;
|
break;
|
||||||
case ETHTOOL_SRXCLSRLDEL:
|
case ETHTOOL_SRXCLSRLDEL:
|
||||||
ret = i40e_add_del_fdir_ethtool(vsi, cmd, false);
|
ret = i40e_del_fdir_entry(vsi, cmd);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -2420,6 +2420,25 @@ static void i40e_set_vsi_rx_mode(struct i40e_vsi *vsi)
|
||||||
i40e_set_rx_mode(vsi->netdev);
|
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
|
* i40e_vsi_configure - Set up the VSI for action
|
||||||
* @vsi: the VSI being configured
|
* @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_set_vsi_rx_mode(vsi);
|
||||||
i40e_restore_vlan(vsi);
|
i40e_restore_vlan(vsi);
|
||||||
i40e_vsi_config_dcb_rings(vsi);
|
i40e_vsi_config_dcb_rings(vsi);
|
||||||
|
if (vsi->type == I40E_VSI_FDIR)
|
||||||
|
i40e_fdir_filter_restore(vsi);
|
||||||
err = i40e_vsi_configure_tx(vsi);
|
err = i40e_vsi_configure_tx(vsi);
|
||||||
if (!err)
|
if (!err)
|
||||||
err = i40e_vsi_configure_rx(vsi);
|
err = i40e_vsi_configure_rx(vsi);
|
||||||
|
@ -4267,6 +4288,26 @@ err_setup_tx:
|
||||||
return err;
|
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
|
* i40e_close - Disables a network interface
|
||||||
* @netdev: network interface device structure
|
* @netdev: network interface device structure
|
||||||
|
@ -5131,9 +5172,9 @@ static void i40e_fdir_sb_setup(struct i40e_pf *pf)
|
||||||
err = i40e_up_complete(vsi);
|
err = i40e_up_complete(vsi);
|
||||||
if (err)
|
if (err)
|
||||||
goto err_up_complete;
|
goto err_up_complete;
|
||||||
|
clear_bit(__I40E_NEEDS_RESTART, &vsi->state);
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_bit(__I40E_NEEDS_RESTART, &vsi->state);
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
err_up_complete:
|
err_up_complete:
|
||||||
|
@ -5156,6 +5197,7 @@ static void i40e_fdir_teardown(struct i40e_pf *pf)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
i40e_fdir_filter_exit(pf);
|
||||||
for (i = 0; i < pf->hw.func_caps.num_vsis; i++) {
|
for (i = 0; i < pf->hw.func_caps.num_vsis; i++) {
|
||||||
if (pf->vsi[i] && pf->vsi[i]->type == I40E_VSI_FDIR) {
|
if (pf->vsi[i] && pf->vsi[i]->type == I40E_VSI_FDIR) {
|
||||||
i40e_vsi_release(pf->vsi[i]);
|
i40e_vsi_release(pf->vsi[i]);
|
||||||
|
|
|
@ -39,11 +39,12 @@ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
|
||||||
#define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS)
|
#define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS)
|
||||||
/**
|
/**
|
||||||
* i40e_program_fdir_filter - Program a Flow Director filter
|
* i40e_program_fdir_filter - Program a Flow Director filter
|
||||||
* @fdir_input: Packet data that will be filter parameters
|
* @fdir_data: Packet data that will be filter parameters
|
||||||
|
* @raw_packet: the pre-allocated packet buffer for FDir
|
||||||
* @pf: The pf pointer
|
* @pf: The pf pointer
|
||||||
* @add: True for add/update, False for remove
|
* @add: True for add/update, False for remove
|
||||||
**/
|
**/
|
||||||
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)
|
struct i40e_pf *pf, bool add)
|
||||||
{
|
{
|
||||||
struct i40e_filter_program_desc *fdir_desc;
|
struct i40e_filter_program_desc *fdir_desc;
|
||||||
|
@ -68,8 +69,8 @@ int i40e_program_fdir_filter(struct i40e_fdir_data *fdir_data,
|
||||||
tx_ring = vsi->tx_rings[0];
|
tx_ring = vsi->tx_rings[0];
|
||||||
dev = tx_ring->dev;
|
dev = tx_ring->dev;
|
||||||
|
|
||||||
dma = dma_map_single(dev, fdir_data->raw_packet,
|
dma = dma_map_single(dev, raw_packet,
|
||||||
I40E_FDIR_MAX_RAW_PACKET_LOOKUP, DMA_TO_DEVICE);
|
I40E_FDIR_MAX_RAW_PACKET_SIZE, DMA_TO_DEVICE);
|
||||||
if (dma_mapping_error(dev, dma))
|
if (dma_mapping_error(dev, dma))
|
||||||
goto dma_fail;
|
goto dma_fail;
|
||||||
|
|
||||||
|
@ -132,14 +133,14 @@ int i40e_program_fdir_filter(struct i40e_fdir_data *fdir_data,
|
||||||
tx_ring->next_to_use = (i + 1 < tx_ring->count) ? i + 1 : 0;
|
tx_ring->next_to_use = (i + 1 < tx_ring->count) ? i + 1 : 0;
|
||||||
|
|
||||||
/* record length, and DMA address */
|
/* record length, and DMA address */
|
||||||
dma_unmap_len_set(tx_buf, len, I40E_FDIR_MAX_RAW_PACKET_LOOKUP);
|
dma_unmap_len_set(tx_buf, len, I40E_FDIR_MAX_RAW_PACKET_SIZE);
|
||||||
dma_unmap_addr_set(tx_buf, dma, dma);
|
dma_unmap_addr_set(tx_buf, dma, dma);
|
||||||
|
|
||||||
tx_desc->buffer_addr = cpu_to_le64(dma);
|
tx_desc->buffer_addr = cpu_to_le64(dma);
|
||||||
td_cmd = I40E_TXD_CMD | I40E_TX_DESC_CMD_DUMMY;
|
td_cmd = I40E_TXD_CMD | I40E_TX_DESC_CMD_DUMMY;
|
||||||
|
|
||||||
tx_desc->cmd_type_offset_bsz =
|
tx_desc->cmd_type_offset_bsz =
|
||||||
build_ctob(td_cmd, 0, I40E_FDIR_MAX_RAW_PACKET_LOOKUP, 0);
|
build_ctob(td_cmd, 0, I40E_FDIR_MAX_RAW_PACKET_SIZE, 0);
|
||||||
|
|
||||||
/* set the timestamp */
|
/* set the timestamp */
|
||||||
tx_buf->time_stamp = jiffies;
|
tx_buf->time_stamp = jiffies;
|
||||||
|
@ -161,6 +162,270 @@ dma_fail:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define IP_HEADER_OFFSET 14
|
||||||
|
#define I40E_UDPIP_DUMMY_PACKET_LEN 42
|
||||||
|
/**
|
||||||
|
* i40e_add_del_fdir_udpv4 - Add/Remove UDPv4 filters
|
||||||
|
* @vsi: pointer to the targeted VSI
|
||||||
|
* @fd_data: the flow director data required for the FDir descriptor
|
||||||
|
* @raw_packet: the pre-allocated packet buffer for FDir
|
||||||
|
* @add: true adds a filter, false removes it
|
||||||
|
*
|
||||||
|
* Returns 0 if the filters were successfully added or removed
|
||||||
|
**/
|
||||||
|
static int i40e_add_del_fdir_udpv4(struct i40e_vsi *vsi,
|
||||||
|
struct i40e_fdir_filter *fd_data,
|
||||||
|
u8 *raw_packet, bool add)
|
||||||
|
{
|
||||||
|
struct i40e_pf *pf = vsi->back;
|
||||||
|
struct udphdr *udp;
|
||||||
|
struct iphdr *ip;
|
||||||
|
bool err = false;
|
||||||
|
int ret;
|
||||||
|
int i;
|
||||||
|
static 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(raw_packet, packet, I40E_UDPIP_DUMMY_PACKET_LEN);
|
||||||
|
|
||||||
|
ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET);
|
||||||
|
udp = (struct udphdr *)(raw_packet + IP_HEADER_OFFSET
|
||||||
|
+ sizeof(struct iphdr));
|
||||||
|
|
||||||
|
ip->daddr = fd_data->dst_ip[0];
|
||||||
|
udp->dest = fd_data->dst_port;
|
||||||
|
ip->saddr = fd_data->src_ip[0];
|
||||||
|
udp->source = fd_data->src_port;
|
||||||
|
|
||||||
|
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, raw_packet, 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return err ? -EOPNOTSUPP : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define I40E_TCPIP_DUMMY_PACKET_LEN 54
|
||||||
|
/**
|
||||||
|
* i40e_add_del_fdir_tcpv4 - Add/Remove TCPv4 filters
|
||||||
|
* @vsi: pointer to the targeted VSI
|
||||||
|
* @fd_data: the flow director data required for the FDir descriptor
|
||||||
|
* @raw_packet: the pre-allocated packet buffer for FDir
|
||||||
|
* @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_filter *fd_data,
|
||||||
|
u8 *raw_packet, bool add)
|
||||||
|
{
|
||||||
|
struct i40e_pf *pf = vsi->back;
|
||||||
|
struct tcphdr *tcp;
|
||||||
|
struct iphdr *ip;
|
||||||
|
bool err = false;
|
||||||
|
int ret;
|
||||||
|
/* Dummy packet */
|
||||||
|
static 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(raw_packet, packet, I40E_TCPIP_DUMMY_PACKET_LEN);
|
||||||
|
|
||||||
|
ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET);
|
||||||
|
tcp = (struct tcphdr *)(raw_packet + IP_HEADER_OFFSET
|
||||||
|
+ sizeof(struct iphdr));
|
||||||
|
|
||||||
|
ip->daddr = fd_data->dst_ip[0];
|
||||||
|
tcp->dest = fd_data->dst_port;
|
||||||
|
ip->saddr = fd_data->src_ip[0];
|
||||||
|
tcp->source = fd_data->src_port;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN;
|
||||||
|
ret = i40e_program_fdir_filter(fd_data, raw_packet, 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP;
|
||||||
|
|
||||||
|
ret = i40e_program_fdir_filter(fd_data, raw_packet, 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
return err ? -EOPNOTSUPP : 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 for the FDir descriptor
|
||||||
|
* @raw_packet: the pre-allocated packet buffer for FDir
|
||||||
|
* @add: true adds a filter, false removes it
|
||||||
|
*
|
||||||
|
* Returns 0 if the filters were successfully added or removed
|
||||||
|
**/
|
||||||
|
static int i40e_add_del_fdir_sctpv4(struct i40e_vsi *vsi,
|
||||||
|
struct i40e_fdir_filter *fd_data,
|
||||||
|
u8 *raw_packet, 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
|
||||||
|
* @raw_packet: the pre-allocated packet buffer for FDir
|
||||||
|
* @add: true adds a filter, false removes it
|
||||||
|
*
|
||||||
|
* Returns 0 if the filters were successfully added or removed
|
||||||
|
**/
|
||||||
|
static int i40e_add_del_fdir_ipv4(struct i40e_vsi *vsi,
|
||||||
|
struct i40e_fdir_filter *fd_data,
|
||||||
|
u8 *raw_packet, bool add)
|
||||||
|
{
|
||||||
|
struct i40e_pf *pf = vsi->back;
|
||||||
|
struct iphdr *ip;
|
||||||
|
bool err = false;
|
||||||
|
int ret;
|
||||||
|
int i;
|
||||||
|
static 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(raw_packet, packet, I40E_IP_DUMMY_PACKET_LEN);
|
||||||
|
ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET);
|
||||||
|
|
||||||
|
ip->saddr = fd_data->src_ip[0];
|
||||||
|
ip->daddr = fd_data->dst_ip[0];
|
||||||
|
ip->protocol = 0;
|
||||||
|
|
||||||
|
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, raw_packet, 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return err ? -EOPNOTSUPP : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* i40e_add_del_fdir - Build raw packets to add/del fdir filter
|
||||||
|
* @vsi: pointer to the targeted VSI
|
||||||
|
* @cmd: command to get or set RX flow classification rules
|
||||||
|
* @add: true adds a filter, false removes it
|
||||||
|
*
|
||||||
|
**/
|
||||||
|
int i40e_add_del_fdir(struct i40e_vsi *vsi,
|
||||||
|
struct i40e_fdir_filter *input, bool add)
|
||||||
|
{
|
||||||
|
struct i40e_pf *pf = vsi->back;
|
||||||
|
u8 *raw_packet;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Populate the Flow Director that we have at the moment
|
||||||
|
* and allocate the raw packet buffer for the calling functions
|
||||||
|
*/
|
||||||
|
raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE, GFP_KERNEL);
|
||||||
|
if (!raw_packet)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
switch (input->flow_type & ~FLOW_EXT) {
|
||||||
|
case TCP_V4_FLOW:
|
||||||
|
ret = i40e_add_del_fdir_tcpv4(vsi, input, raw_packet,
|
||||||
|
add);
|
||||||
|
break;
|
||||||
|
case UDP_V4_FLOW:
|
||||||
|
ret = i40e_add_del_fdir_udpv4(vsi, input, raw_packet,
|
||||||
|
add);
|
||||||
|
break;
|
||||||
|
case SCTP_V4_FLOW:
|
||||||
|
ret = i40e_add_del_fdir_sctpv4(vsi, input, raw_packet,
|
||||||
|
add);
|
||||||
|
break;
|
||||||
|
case IPV4_FLOW:
|
||||||
|
ret = i40e_add_del_fdir_ipv4(vsi, input, raw_packet,
|
||||||
|
add);
|
||||||
|
break;
|
||||||
|
case IP_USER_FLOW:
|
||||||
|
switch (input->ip4_proto) {
|
||||||
|
case IPPROTO_TCP:
|
||||||
|
ret = i40e_add_del_fdir_tcpv4(vsi, input,
|
||||||
|
raw_packet, add);
|
||||||
|
break;
|
||||||
|
case IPPROTO_UDP:
|
||||||
|
ret = i40e_add_del_fdir_udpv4(vsi, input,
|
||||||
|
raw_packet, add);
|
||||||
|
break;
|
||||||
|
case IPPROTO_SCTP:
|
||||||
|
ret = i40e_add_del_fdir_sctpv4(vsi, input,
|
||||||
|
raw_packet, add);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = i40e_add_del_fdir_ipv4(vsi, input,
|
||||||
|
raw_packet, add);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dev_info(&pf->pdev->dev, "Could not specify spec type %d",
|
||||||
|
input->flow_type);
|
||||||
|
ret = -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
kfree(raw_packet);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* i40e_fd_handle_status - check the Programming Status for FD
|
* i40e_fd_handle_status - check the Programming Status for FD
|
||||||
* @rx_ring: the Rx ring for this descriptor
|
* @rx_ring: the Rx ring for this descriptor
|
||||||
|
|
Loading…
Reference in a new issue