net/i40e: finish integration FDIR with generic flow API

rte_eth_fdir_* structures are still used in FDIR functions.
This patch adds i40e private FDIR related structures and
functions to finish integration FDIR with generic flow API.

Signed-off-by: Beilei Xing <beilei.xing@intel.com>
This commit is contained in:
Beilei Xing 2017-10-05 16:14:54 +08:00 committed by Ferruh Yigit
parent 576f459eb2
commit 4149825bbd
3 changed files with 584 additions and 63 deletions

View File

@ -460,6 +460,80 @@ struct i40e_vmdq_info {
#define I40E_FLEX_WORD_MASK(off) (0x80 >> (off))
#define I40E_FDIR_IPv6_TC_OFFSET 20
/*
* A union contains the inputs for all types of flow
* items in flows need to be in big endian
*/
union i40e_fdir_flow {
struct rte_eth_l2_flow l2_flow;
struct rte_eth_udpv4_flow udp4_flow;
struct rte_eth_tcpv4_flow tcp4_flow;
struct rte_eth_sctpv4_flow sctp4_flow;
struct rte_eth_ipv4_flow ip4_flow;
struct rte_eth_udpv6_flow udp6_flow;
struct rte_eth_tcpv6_flow tcp6_flow;
struct rte_eth_sctpv6_flow sctp6_flow;
struct rte_eth_ipv6_flow ipv6_flow;
};
/* A structure used to contain extend input of flow */
struct i40e_fdir_flow_ext {
uint16_t vlan_tci;
uint8_t flexbytes[RTE_ETH_FDIR_MAX_FLEXLEN];
/* It is filled by the flexible payload to match. */
uint8_t is_vf; /* 1 for VF, 0 for port dev */
uint16_t dst_id; /* VF ID, available when is_vf is 1*/
};
/* A structure used to define the input for a flow director filter entry */
struct i40e_fdir_input {
enum i40e_filter_pctype pctype;
union i40e_fdir_flow flow;
/* Flow fields to match, dependent on flow_type */
struct i40e_fdir_flow_ext flow_ext;
/* Additional fields to match */
};
/* Behavior will be taken if FDIR match */
enum i40e_fdir_behavior {
I40E_FDIR_ACCEPT = 0,
I40E_FDIR_REJECT,
I40E_FDIR_PASSTHRU,
};
/* Flow director report status
* It defines what will be reported if FDIR entry is matched.
*/
enum i40e_fdir_status {
I40E_FDIR_NO_REPORT_STATUS = 0, /* Report nothing. */
I40E_FDIR_REPORT_ID, /* Only report FD ID. */
I40E_FDIR_REPORT_ID_FLEX_4, /* Report FD ID and 4 flex bytes. */
I40E_FDIR_REPORT_FLEX_8, /* Report 8 flex bytes. */
};
/* A structure used to define an action when match FDIR packet filter. */
struct i40e_fdir_action {
uint16_t rx_queue; /* Queue assigned to if FDIR match. */
enum i40e_fdir_behavior behavior; /* Behavior will be taken */
enum i40e_fdir_status report_status; /* Status report option */
/* If report_status is I40E_FDIR_REPORT_ID_FLEX_4 or
* I40E_FDIR_REPORT_FLEX_8, flex_off specifies where the reported
* flex bytes start from in flexible payload.
*/
uint8_t flex_off;
};
/* A structure used to define the flow director filter entry by filter_ctrl API
* It supports RTE_ETH_FILTER_FDIR with RTE_ETH_FILTER_ADD and
* RTE_ETH_FILTER_DELETE operations.
*/
struct i40e_fdir_filter_conf {
uint32_t soft_id;
/* ID, an unique value is required when deal with FDIR entry */
struct i40e_fdir_input input; /* Input set */
struct i40e_fdir_action action; /* Action taken when match */
};
/*
* Structure to store flex pit for flow diretor.
*/
@ -484,7 +558,7 @@ struct i40e_fdir_flex_mask {
struct i40e_fdir_filter {
TAILQ_ENTRY(i40e_fdir_filter) rules;
struct rte_eth_fdir_filter fdir;
struct i40e_fdir_filter_conf fdir;
};
TAILQ_HEAD(i40e_fdir_filter_list, i40e_fdir_filter);
@ -913,7 +987,7 @@ extern const struct rte_flow_ops i40e_flow_ops;
union i40e_filter_t {
struct rte_eth_ethertype_filter ethertype_filter;
struct rte_eth_fdir_filter fdir_filter;
struct i40e_fdir_filter_conf fdir_filter;
struct rte_eth_tunnel_filter_conf tunnel_filter;
struct i40e_tunnel_filter_conf consistent_tunnel_filter;
};
@ -990,7 +1064,7 @@ i40e_sw_ethertype_filter_lookup(struct i40e_ethertype_rule *ethertype_rule,
int i40e_sw_ethertype_filter_del(struct i40e_pf *pf,
struct i40e_ethertype_filter_input *input);
int i40e_sw_fdir_filter_del(struct i40e_pf *pf,
struct rte_eth_fdir_input *input);
struct i40e_fdir_input *input);
struct i40e_tunnel_filter *
i40e_sw_tunnel_filter_lookup(struct i40e_tunnel_rule *tunnel_rule,
const struct i40e_tunnel_filter_input *input);
@ -1003,6 +1077,9 @@ int i40e_ethertype_filter_set(struct i40e_pf *pf,
int i40e_add_del_fdir_filter(struct rte_eth_dev *dev,
const struct rte_eth_fdir_filter *filter,
bool add);
int i40e_flow_add_del_fdir_filter(struct rte_eth_dev *dev,
const struct i40e_fdir_filter_conf *filter,
bool add);
int i40e_dev_tunnel_filter_set(struct i40e_pf *pf,
struct rte_eth_tunnel_filter_conf *tunnel_filter,
uint8_t add);

View File

@ -100,13 +100,18 @@ static int i40e_fdir_filter_programming(struct i40e_pf *pf,
enum i40e_filter_pctype pctype,
const struct rte_eth_fdir_filter *filter,
bool add);
static int i40e_fdir_filter_convert(const struct rte_eth_fdir_filter *input,
static int i40e_fdir_filter_convert(const struct i40e_fdir_filter_conf *input,
struct i40e_fdir_filter *filter);
static struct i40e_fdir_filter *
i40e_sw_fdir_filter_lookup(struct i40e_fdir_info *fdir_info,
const struct rte_eth_fdir_input *input);
const struct i40e_fdir_input *input);
static int i40e_sw_fdir_filter_insert(struct i40e_pf *pf,
struct i40e_fdir_filter *filter);
static int
i40e_flow_fdir_filter_programming(struct i40e_pf *pf,
enum i40e_filter_pctype pctype,
const struct i40e_fdir_filter_conf *filter,
bool add);
static int
i40e_fdir_rx_queue_init(struct i40e_rx_queue *rxq)
@ -933,6 +938,263 @@ i40e_fdir_construct_pkt(struct i40e_pf *pf,
return 0;
}
static inline int
i40e_flow_fdir_fill_eth_ip_head(const struct i40e_fdir_input *fdir_input,
unsigned char *raw_pkt,
bool vlan)
{
static uint8_t vlan_frame[] = {0x81, 0, 0, 0};
uint16_t *ether_type;
uint8_t len = 2 * sizeof(struct ether_addr);
struct ipv4_hdr *ip;
struct ipv6_hdr *ip6;
static const uint8_t next_proto[] = {
[I40E_FILTER_PCTYPE_FRAG_IPV4] = IPPROTO_IP,
[I40E_FILTER_PCTYPE_NONF_IPV4_TCP] = IPPROTO_TCP,
[I40E_FILTER_PCTYPE_NONF_IPV4_UDP] = IPPROTO_UDP,
[I40E_FILTER_PCTYPE_NONF_IPV4_SCTP] = IPPROTO_SCTP,
[I40E_FILTER_PCTYPE_NONF_IPV4_OTHER] = IPPROTO_IP,
[I40E_FILTER_PCTYPE_FRAG_IPV6] = IPPROTO_NONE,
[I40E_FILTER_PCTYPE_NONF_IPV6_TCP] = IPPROTO_TCP,
[I40E_FILTER_PCTYPE_NONF_IPV6_UDP] = IPPROTO_UDP,
[I40E_FILTER_PCTYPE_NONF_IPV6_SCTP] = IPPROTO_SCTP,
[I40E_FILTER_PCTYPE_NONF_IPV6_OTHER] = IPPROTO_NONE,
};
raw_pkt += 2 * sizeof(struct ether_addr);
if (vlan && fdir_input->flow_ext.vlan_tci) {
rte_memcpy(raw_pkt, vlan_frame, sizeof(vlan_frame));
rte_memcpy(raw_pkt + sizeof(uint16_t),
&fdir_input->flow_ext.vlan_tci,
sizeof(uint16_t));
raw_pkt += sizeof(vlan_frame);
len += sizeof(vlan_frame);
}
ether_type = (uint16_t *)raw_pkt;
raw_pkt += sizeof(uint16_t);
len += sizeof(uint16_t);
switch (fdir_input->pctype) {
case I40E_FILTER_PCTYPE_L2_PAYLOAD:
*ether_type = fdir_input->flow.l2_flow.ether_type;
break;
case I40E_FILTER_PCTYPE_NONF_IPV4_TCP:
case I40E_FILTER_PCTYPE_NONF_IPV4_UDP:
case I40E_FILTER_PCTYPE_NONF_IPV4_SCTP:
case I40E_FILTER_PCTYPE_NONF_IPV4_OTHER:
case I40E_FILTER_PCTYPE_FRAG_IPV4:
ip = (struct ipv4_hdr *)raw_pkt;
*ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
ip->version_ihl = I40E_FDIR_IP_DEFAULT_VERSION_IHL;
/* set len to by default */
ip->total_length = rte_cpu_to_be_16(I40E_FDIR_IP_DEFAULT_LEN);
ip->next_proto_id = fdir_input->flow.ip4_flow.proto ?
fdir_input->flow.ip4_flow.proto :
next_proto[fdir_input->pctype];
ip->time_to_live = fdir_input->flow.ip4_flow.ttl ?
fdir_input->flow.ip4_flow.ttl :
I40E_FDIR_IP_DEFAULT_TTL;
ip->type_of_service = fdir_input->flow.ip4_flow.tos;
/**
* The source and destination fields in the transmitted packet
* need to be presented in a reversed order with respect
* to the expected received packets.
*/
ip->src_addr = fdir_input->flow.ip4_flow.dst_ip;
ip->dst_addr = fdir_input->flow.ip4_flow.src_ip;
len += sizeof(struct ipv4_hdr);
break;
case I40E_FILTER_PCTYPE_NONF_IPV6_TCP:
case I40E_FILTER_PCTYPE_NONF_IPV6_UDP:
case I40E_FILTER_PCTYPE_NONF_IPV6_SCTP:
case I40E_FILTER_PCTYPE_NONF_IPV6_OTHER:
case I40E_FILTER_PCTYPE_FRAG_IPV6:
ip6 = (struct ipv6_hdr *)raw_pkt;
*ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
ip6->vtc_flow =
rte_cpu_to_be_32(I40E_FDIR_IPv6_DEFAULT_VTC_FLOW |
(fdir_input->flow.ipv6_flow.tc <<
I40E_FDIR_IPv6_TC_OFFSET));
ip6->payload_len =
rte_cpu_to_be_16(I40E_FDIR_IPv6_PAYLOAD_LEN);
ip6->proto = fdir_input->flow.ipv6_flow.proto ?
fdir_input->flow.ipv6_flow.proto :
next_proto[fdir_input->pctype];
ip6->hop_limits = fdir_input->flow.ipv6_flow.hop_limits ?
fdir_input->flow.ipv6_flow.hop_limits :
I40E_FDIR_IPv6_DEFAULT_HOP_LIMITS;
/**
* The source and destination fields in the transmitted packet
* need to be presented in a reversed order with respect
* to the expected received packets.
*/
rte_memcpy(&ip6->src_addr,
&fdir_input->flow.ipv6_flow.dst_ip,
IPV6_ADDR_LEN);
rte_memcpy(&ip6->dst_addr,
&fdir_input->flow.ipv6_flow.src_ip,
IPV6_ADDR_LEN);
len += sizeof(struct ipv6_hdr);
break;
default:
PMD_DRV_LOG(ERR, "unknown pctype %u.",
fdir_input->pctype);
return -1;
}
return len;
}
/**
* i40e_flow_fdir_construct_pkt - construct packet based on fields in input
* @pf: board private structure
* @fdir_input: input set of the flow director entry
* @raw_pkt: a packet to be constructed
*/
static int
i40e_flow_fdir_construct_pkt(struct i40e_pf *pf,
const struct i40e_fdir_input *fdir_input,
unsigned char *raw_pkt)
{
unsigned char *payload, *ptr;
struct udp_hdr *udp;
struct tcp_hdr *tcp;
struct sctp_hdr *sctp;
uint8_t size, dst = 0;
uint8_t i, pit_idx, set_idx = I40E_FLXPLD_L4_IDX; /* use l4 by default*/
int len;
/* fill the ethernet and IP head */
len = i40e_flow_fdir_fill_eth_ip_head(fdir_input, raw_pkt,
!!fdir_input->flow_ext.vlan_tci);
if (len < 0)
return -EINVAL;
/* fill the L4 head */
switch (fdir_input->pctype) {
case I40E_FILTER_PCTYPE_NONF_IPV4_UDP:
udp = (struct udp_hdr *)(raw_pkt + len);
payload = (unsigned char *)udp + sizeof(struct udp_hdr);
/**
* The source and destination fields in the transmitted packet
* need to be presented in a reversed order with respect
* to the expected received packets.
*/
udp->src_port = fdir_input->flow.udp4_flow.dst_port;
udp->dst_port = fdir_input->flow.udp4_flow.src_port;
udp->dgram_len = rte_cpu_to_be_16(I40E_FDIR_UDP_DEFAULT_LEN);
break;
case I40E_FILTER_PCTYPE_NONF_IPV4_TCP:
tcp = (struct tcp_hdr *)(raw_pkt + len);
payload = (unsigned char *)tcp + sizeof(struct tcp_hdr);
/**
* The source and destination fields in the transmitted packet
* need to be presented in a reversed order with respect
* to the expected received packets.
*/
tcp->src_port = fdir_input->flow.tcp4_flow.dst_port;
tcp->dst_port = fdir_input->flow.tcp4_flow.src_port;
tcp->data_off = I40E_FDIR_TCP_DEFAULT_DATAOFF;
break;
case I40E_FILTER_PCTYPE_NONF_IPV4_SCTP:
sctp = (struct sctp_hdr *)(raw_pkt + len);
payload = (unsigned char *)sctp + sizeof(struct sctp_hdr);
/**
* The source and destination fields in the transmitted packet
* need to be presented in a reversed order with respect
* to the expected received packets.
*/
sctp->src_port = fdir_input->flow.sctp4_flow.dst_port;
sctp->dst_port = fdir_input->flow.sctp4_flow.src_port;
sctp->tag = fdir_input->flow.sctp4_flow.verify_tag;
break;
case I40E_FILTER_PCTYPE_NONF_IPV4_OTHER:
case I40E_FILTER_PCTYPE_FRAG_IPV4:
payload = raw_pkt + len;
set_idx = I40E_FLXPLD_L3_IDX;
break;
case I40E_FILTER_PCTYPE_NONF_IPV6_UDP:
udp = (struct udp_hdr *)(raw_pkt + len);
payload = (unsigned char *)udp + sizeof(struct udp_hdr);
/**
* The source and destination fields in the transmitted packet
* need to be presented in a reversed order with respect
* to the expected received packets.
*/
udp->src_port = fdir_input->flow.udp6_flow.dst_port;
udp->dst_port = fdir_input->flow.udp6_flow.src_port;
udp->dgram_len = rte_cpu_to_be_16(I40E_FDIR_IPv6_PAYLOAD_LEN);
break;
case I40E_FILTER_PCTYPE_NONF_IPV6_TCP:
tcp = (struct tcp_hdr *)(raw_pkt + len);
payload = (unsigned char *)tcp + sizeof(struct tcp_hdr);
/**
* The source and destination fields in the transmitted packet
* need to be presented in a reversed order with respect
* to the expected received packets.
*/
tcp->data_off = I40E_FDIR_TCP_DEFAULT_DATAOFF;
tcp->src_port = fdir_input->flow.udp6_flow.dst_port;
tcp->dst_port = fdir_input->flow.udp6_flow.src_port;
break;
case I40E_FILTER_PCTYPE_NONF_IPV6_SCTP:
sctp = (struct sctp_hdr *)(raw_pkt + len);
payload = (unsigned char *)sctp + sizeof(struct sctp_hdr);
/**
* The source and destination fields in the transmitted packet
* need to be presented in a reversed order with respect
* to the expected received packets.
*/
sctp->src_port = fdir_input->flow.sctp6_flow.dst_port;
sctp->dst_port = fdir_input->flow.sctp6_flow.src_port;
sctp->tag = fdir_input->flow.sctp6_flow.verify_tag;
break;
case I40E_FILTER_PCTYPE_NONF_IPV6_OTHER:
case I40E_FILTER_PCTYPE_FRAG_IPV6:
payload = raw_pkt + len;
set_idx = I40E_FLXPLD_L3_IDX;
break;
case I40E_FILTER_PCTYPE_L2_PAYLOAD:
payload = raw_pkt + len;
/**
* ARP packet is a special case on which the payload
* starts after the whole ARP header
*/
if (fdir_input->flow.l2_flow.ether_type ==
rte_cpu_to_be_16(ETHER_TYPE_ARP))
payload += sizeof(struct arp_hdr);
set_idx = I40E_FLXPLD_L2_IDX;
break;
default:
PMD_DRV_LOG(ERR, "unknown pctype %u.", fdir_input->pctype);
return -EINVAL;
}
/* fill the flexbytes to payload */
for (i = 0; i < I40E_MAX_FLXPLD_FIED; i++) {
pit_idx = set_idx * I40E_MAX_FLXPLD_FIED + i;
size = pf->fdir.flex_set[pit_idx].size;
if (size == 0)
continue;
dst = pf->fdir.flex_set[pit_idx].dst_offset * sizeof(uint16_t);
ptr = payload +
pf->fdir.flex_set[pit_idx].src_offset * sizeof(uint16_t);
(void)rte_memcpy(ptr,
&fdir_input->flow_ext.flexbytes[dst],
size * sizeof(uint16_t));
}
return 0;
}
/* Construct the tx flags */
static inline uint64_t
i40e_build_ctob(uint32_t td_cmd,
@ -1006,17 +1268,17 @@ i40e_check_fdir_programming_status(struct i40e_rx_queue *rxq)
}
static int
i40e_fdir_filter_convert(const struct rte_eth_fdir_filter *input,
i40e_fdir_filter_convert(const struct i40e_fdir_filter_conf *input,
struct i40e_fdir_filter *filter)
{
rte_memcpy(&filter->fdir, input, sizeof(struct rte_eth_fdir_filter));
rte_memcpy(&filter->fdir, input, sizeof(struct i40e_fdir_filter_conf));
return 0;
}
/* Check if there exists the flow director filter */
static struct i40e_fdir_filter *
i40e_sw_fdir_filter_lookup(struct i40e_fdir_info *fdir_info,
const struct rte_eth_fdir_input *input)
const struct i40e_fdir_input *input)
{
int ret;
@ -1051,7 +1313,7 @@ i40e_sw_fdir_filter_insert(struct i40e_pf *pf, struct i40e_fdir_filter *filter)
/* Delete a flow director filter from the SW list */
int
i40e_sw_fdir_filter_del(struct i40e_pf *pf, struct rte_eth_fdir_input *input)
i40e_sw_fdir_filter_del(struct i40e_pf *pf, struct i40e_fdir_input *input)
{
struct i40e_fdir_info *fdir_info = &pf->fdir;
struct i40e_fdir_filter *filter;
@ -1081,16 +1343,13 @@ i40e_sw_fdir_filter_del(struct i40e_pf *pf, struct rte_eth_fdir_input *input)
*/
int
i40e_add_del_fdir_filter(struct rte_eth_dev *dev,
const struct rte_eth_fdir_filter *filter,
bool add)
const struct rte_eth_fdir_filter *filter,
bool add)
{
struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
unsigned char *pkt = (unsigned char *)pf->fdir.prg_pkt;
enum i40e_filter_pctype pctype;
struct i40e_fdir_info *fdir_info = &pf->fdir;
struct i40e_fdir_filter *fdir_filter, *node;
struct i40e_fdir_filter check_filter; /* Check if the filter exists */
int ret = 0;
if (dev->data->dev_conf.fdir_conf.mode != RTE_FDIR_MODE_PERFECT) {
@ -1114,6 +1373,65 @@ i40e_add_del_fdir_filter(struct rte_eth_dev *dev,
return -EINVAL;
}
memset(pkt, 0, I40E_FDIR_PKT_LEN);
ret = i40e_fdir_construct_pkt(pf, &filter->input, pkt);
if (ret < 0) {
PMD_DRV_LOG(ERR, "construct packet for fdir fails.");
return ret;
}
if (hw->mac.type == I40E_MAC_X722) {
/* get translated pctype value in fd pctype register */
pctype = (enum i40e_filter_pctype)i40e_read_rx_ctl(
hw, I40E_GLQF_FD_PCTYPES((int)pctype));
}
ret = i40e_fdir_filter_programming(pf, pctype, filter, add);
if (ret < 0) {
PMD_DRV_LOG(ERR, "fdir programming fails for PCTYPE(%u).",
pctype);
return ret;
}
return ret;
}
/**
* i40e_flow_add_del_fdir_filter - add or remove a flow director filter.
* @pf: board private structure
* @filter: fdir filter entry
* @add: 0 - delete, 1 - add
*/
int
i40e_flow_add_del_fdir_filter(struct rte_eth_dev *dev,
const struct i40e_fdir_filter_conf *filter,
bool add)
{
struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
unsigned char *pkt = (unsigned char *)pf->fdir.prg_pkt;
enum i40e_filter_pctype pctype;
struct i40e_fdir_info *fdir_info = &pf->fdir;
struct i40e_fdir_filter *fdir_filter, *node;
struct i40e_fdir_filter check_filter; /* Check if the filter exists */
int ret = 0;
if (dev->data->dev_conf.fdir_conf.mode != RTE_FDIR_MODE_PERFECT) {
PMD_DRV_LOG(ERR, "FDIR is not enabled, please check the mode in fdir_conf.");
return -ENOTSUP;
}
if (filter->action.rx_queue >= pf->dev_data->nb_rx_queues) {
PMD_DRV_LOG(ERR, "Invalid queue ID");
return -EINVAL;
}
if (filter->input.flow_ext.is_vf &&
filter->input.flow_ext.dst_id >= pf->vf_num) {
PMD_DRV_LOG(ERR, "Invalid VF ID");
return -EINVAL;
}
/* Check if there is the filter in SW list */
memset(&check_filter, 0, sizeof(check_filter));
i40e_fdir_filter_convert(filter, &check_filter);
@ -1132,7 +1450,7 @@ i40e_add_del_fdir_filter(struct rte_eth_dev *dev,
memset(pkt, 0, I40E_FDIR_PKT_LEN);
ret = i40e_fdir_construct_pkt(pf, &filter->input, pkt);
ret = i40e_flow_fdir_construct_pkt(pf, &filter->input, pkt);
if (ret < 0) {
PMD_DRV_LOG(ERR, "construct packet for fdir fails.");
return ret;
@ -1141,9 +1459,12 @@ i40e_add_del_fdir_filter(struct rte_eth_dev *dev,
if (hw->mac.type == I40E_MAC_X722) {
/* get translated pctype value in fd pctype register */
pctype = (enum i40e_filter_pctype)i40e_read_rx_ctl(
hw, I40E_GLQF_FD_PCTYPES((int)pctype));
}
ret = i40e_fdir_filter_programming(pf, pctype, filter, add);
hw, I40E_GLQF_FD_PCTYPES(
(int)filter->input.pctype));
} else
pctype = filter->input.pctype;
ret = i40e_flow_fdir_filter_programming(pf, pctype, filter, add);
if (ret < 0) {
PMD_DRV_LOG(ERR, "fdir programming fails for PCTYPE(%u).",
pctype);
@ -1297,6 +1618,140 @@ i40e_fdir_filter_programming(struct i40e_pf *pf,
return -ETIMEDOUT;
}
/*
* i40e_flow_fdir_filter_programming - Program a flow director filter rule.
* Is done by Flow Director Programming Descriptor followed by packet
* structure that contains the filter fields need to match.
* @pf: board private structure
* @pctype: pctype
* @filter: fdir filter entry
* @add: 0 - delete, 1 - add
*/
static int
i40e_flow_fdir_filter_programming(struct i40e_pf *pf,
enum i40e_filter_pctype pctype,
const struct i40e_fdir_filter_conf *filter,
bool add)
{
struct i40e_tx_queue *txq = pf->fdir.txq;
struct i40e_rx_queue *rxq = pf->fdir.rxq;
const struct i40e_fdir_action *fdir_action = &filter->action;
volatile struct i40e_tx_desc *txdp;
volatile struct i40e_filter_program_desc *fdirdp;
uint32_t td_cmd;
uint16_t vsi_id, i;
uint8_t dest;
PMD_DRV_LOG(INFO, "filling filter programming descriptor.");
fdirdp = (volatile struct i40e_filter_program_desc *)
(&txq->tx_ring[txq->tx_tail]);
fdirdp->qindex_flex_ptype_vsi =
rte_cpu_to_le_32((fdir_action->rx_queue <<
I40E_TXD_FLTR_QW0_QINDEX_SHIFT) &
I40E_TXD_FLTR_QW0_QINDEX_MASK);
fdirdp->qindex_flex_ptype_vsi |=
rte_cpu_to_le_32((fdir_action->flex_off <<
I40E_TXD_FLTR_QW0_FLEXOFF_SHIFT) &
I40E_TXD_FLTR_QW0_FLEXOFF_MASK);
fdirdp->qindex_flex_ptype_vsi |=
rte_cpu_to_le_32((pctype <<
I40E_TXD_FLTR_QW0_PCTYPE_SHIFT) &
I40E_TXD_FLTR_QW0_PCTYPE_MASK);
if (filter->input.flow_ext.is_vf)
vsi_id = pf->vfs[filter->input.flow_ext.dst_id].vsi->vsi_id;
else
/* Use LAN VSI Id by default */
vsi_id = pf->main_vsi->vsi_id;
fdirdp->qindex_flex_ptype_vsi |=
rte_cpu_to_le_32(((uint32_t)vsi_id <<
I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT) &
I40E_TXD_FLTR_QW0_DEST_VSI_MASK);
fdirdp->dtype_cmd_cntindex =
rte_cpu_to_le_32(I40E_TX_DESC_DTYPE_FILTER_PROG);
if (add)
fdirdp->dtype_cmd_cntindex |= rte_cpu_to_le_32(
I40E_FILTER_PROGRAM_DESC_PCMD_ADD_UPDATE <<
I40E_TXD_FLTR_QW1_PCMD_SHIFT);
else
fdirdp->dtype_cmd_cntindex |= rte_cpu_to_le_32(
I40E_FILTER_PROGRAM_DESC_PCMD_REMOVE <<
I40E_TXD_FLTR_QW1_PCMD_SHIFT);
if (fdir_action->behavior == I40E_FDIR_REJECT)
dest = I40E_FILTER_PROGRAM_DESC_DEST_DROP_PACKET;
else if (fdir_action->behavior == I40E_FDIR_ACCEPT)
dest = I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX;
else if (fdir_action->behavior == I40E_FDIR_PASSTHRU)
dest = I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_OTHER;
else {
PMD_DRV_LOG(ERR, "Failed to program FDIR filter: unsupported fdir behavior.");
return -EINVAL;
}
fdirdp->dtype_cmd_cntindex |= rte_cpu_to_le_32((dest <<
I40E_TXD_FLTR_QW1_DEST_SHIFT) &
I40E_TXD_FLTR_QW1_DEST_MASK);
fdirdp->dtype_cmd_cntindex |=
rte_cpu_to_le_32((fdir_action->report_status <<
I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT) &
I40E_TXD_FLTR_QW1_FD_STATUS_MASK);
fdirdp->dtype_cmd_cntindex |=
rte_cpu_to_le_32(I40E_TXD_FLTR_QW1_CNT_ENA_MASK);
fdirdp->dtype_cmd_cntindex |=
rte_cpu_to_le_32(
((uint32_t)pf->fdir.match_counter_index <<
I40E_TXD_FLTR_QW1_CNTINDEX_SHIFT) &
I40E_TXD_FLTR_QW1_CNTINDEX_MASK);
fdirdp->fd_id = rte_cpu_to_le_32(filter->soft_id);
PMD_DRV_LOG(INFO, "filling transmit descriptor.");
txdp = &txq->tx_ring[txq->tx_tail + 1];
txdp->buffer_addr = rte_cpu_to_le_64(pf->fdir.dma_addr);
td_cmd = I40E_TX_DESC_CMD_EOP |
I40E_TX_DESC_CMD_RS |
I40E_TX_DESC_CMD_DUMMY;
txdp->cmd_type_offset_bsz =
i40e_build_ctob(td_cmd, 0, I40E_FDIR_PKT_LEN, 0);
txq->tx_tail += 2; /* set 2 descriptors above, fdirdp and txdp */
if (txq->tx_tail >= txq->nb_tx_desc)
txq->tx_tail = 0;
/* Update the tx tail register */
rte_wmb();
I40E_PCI_REG_WRITE(txq->qtx_tail, txq->tx_tail);
for (i = 0; i < I40E_FDIR_MAX_WAIT_US; i++) {
if ((txdp->cmd_type_offset_bsz &
rte_cpu_to_le_64(I40E_TXD_QW1_DTYPE_MASK)) ==
rte_cpu_to_le_64(I40E_TX_DESC_DTYPE_DESC_DONE))
break;
rte_delay_us(1);
}
if (i >= I40E_FDIR_MAX_WAIT_US) {
PMD_DRV_LOG(ERR,
"Failed to program FDIR filter: time out to get DD on tx queue.");
return -ETIMEDOUT;
}
/* totally delay 10 ms to check programming status*/
rte_delay_us(I40E_FDIR_MAX_WAIT_US);
if (i40e_check_fdir_programming_status(rxq) < 0) {
PMD_DRV_LOG(ERR,
"Failed to program FDIR filter: programming status reported.");
return -ETIMEDOUT;
}
return 0;
}
/*
* i40e_fdir_flush - clear all filters of Flow Director table
* @pf: board private structure
@ -1572,7 +2027,7 @@ i40e_fdir_filter_restore(struct i40e_pf *pf)
uint32_t best_cnt; /**< Number of filters in best effort spaces. */
TAILQ_FOREACH(f, fdir_list, rules)
i40e_add_del_fdir_filter(dev, &f->fdir, TRUE);
i40e_flow_add_del_fdir_filter(dev, &f->fdir, TRUE);
fdstat = I40E_READ_REG(hw, I40E_PFQF_FDSTAT);
guarant_cnt =

View File

@ -84,11 +84,11 @@ static int i40e_flow_parse_ethertype_action(struct rte_eth_dev *dev,
static int i40e_flow_parse_fdir_pattern(struct rte_eth_dev *dev,
const struct rte_flow_item *pattern,
struct rte_flow_error *error,
struct rte_eth_fdir_filter *filter);
struct i40e_fdir_filter_conf *filter);
static int i40e_flow_parse_fdir_action(struct rte_eth_dev *dev,
const struct rte_flow_action *actions,
struct rte_flow_error *error,
struct rte_eth_fdir_filter *filter);
struct i40e_fdir_filter_conf *filter);
static int i40e_flow_parse_tunnel_action(struct rte_eth_dev *dev,
const struct rte_flow_action *actions,
struct rte_flow_error *error,
@ -2315,7 +2315,7 @@ static int
i40e_flow_parse_fdir_pattern(struct rte_eth_dev *dev,
const struct rte_flow_item *pattern,
struct rte_flow_error *error,
struct rte_eth_fdir_filter *filter)
struct i40e_fdir_filter_conf *filter)
{
struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
const struct rte_flow_item *item = pattern;
@ -2329,8 +2329,7 @@ i40e_flow_parse_fdir_pattern(struct rte_eth_dev *dev,
const struct rte_flow_item_raw *raw_spec, *raw_mask;
const struct rte_flow_item_vf *vf_spec;
uint32_t flow_type = RTE_ETH_FLOW_UNKNOWN;
enum i40e_filter_pctype pctype;
enum i40e_filter_pctype pctype = 0;
uint64_t input_set = I40E_INSET_NONE;
uint16_t frag_off;
enum rte_flow_item_type item_type;
@ -2402,7 +2401,7 @@ i40e_flow_parse_fdir_pattern(struct rte_eth_dev *dev,
}
}
flow_type = RTE_ETH_FLOW_L2_PAYLOAD;
pctype = I40E_FILTER_PCTYPE_L2_PAYLOAD;
layer_idx = I40E_FLXPLD_L2_IDX;
break;
@ -2420,7 +2419,7 @@ i40e_flow_parse_fdir_pattern(struct rte_eth_dev *dev,
}
}
flow_type = RTE_ETH_FLOW_L2_PAYLOAD;
pctype = I40E_FILTER_PCTYPE_L2_PAYLOAD;
layer_idx = I40E_FLXPLD_L2_IDX;
break;
@ -2457,13 +2456,13 @@ i40e_flow_parse_fdir_pattern(struct rte_eth_dev *dev,
input_set |= I40E_INSET_IPV4_PROTO;
/* Get filter info */
flow_type = RTE_ETH_FLOW_NONFRAG_IPV4_OTHER;
pctype = I40E_FILTER_PCTYPE_NONF_IPV4_OTHER;
/* Check if it is fragment. */
frag_off = ipv4_spec->hdr.fragment_offset;
frag_off = rte_be_to_cpu_16(frag_off);
if (frag_off & IPV4_HDR_OFFSET_MASK ||
frag_off & IPV4_HDR_MF_FLAG)
flow_type = RTE_ETH_FLOW_FRAG_IPV4;
pctype = I40E_FILTER_PCTYPE_FRAG_IPV4;
/* Get the filter info */
filter->input.flow.ip4_flow.proto =
@ -2535,11 +2534,10 @@ i40e_flow_parse_fdir_pattern(struct rte_eth_dev *dev,
/* Check if it is fragment. */
if (ipv6_spec->hdr.proto ==
I40E_IPV6_FRAG_HEADER)
flow_type =
RTE_ETH_FLOW_FRAG_IPV6;
pctype = I40E_FILTER_PCTYPE_FRAG_IPV6;
else
flow_type =
RTE_ETH_FLOW_NONFRAG_IPV6_OTHER;
pctype =
I40E_FILTER_PCTYPE_NONF_IPV6_OTHER;
}
layer_idx = I40E_FLXPLD_L3_IDX;
@ -2572,11 +2570,11 @@ i40e_flow_parse_fdir_pattern(struct rte_eth_dev *dev,
/* Get filter info */
if (l3 == RTE_FLOW_ITEM_TYPE_IPV4)
flow_type =
RTE_ETH_FLOW_NONFRAG_IPV4_TCP;
pctype =
I40E_FILTER_PCTYPE_NONF_IPV4_TCP;
else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6)
flow_type =
RTE_ETH_FLOW_NONFRAG_IPV6_TCP;
pctype =
I40E_FILTER_PCTYPE_NONF_IPV6_TCP;
if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) {
filter->input.flow.tcp4_flow.src_port =
@ -2616,11 +2614,11 @@ i40e_flow_parse_fdir_pattern(struct rte_eth_dev *dev,
/* Get filter info */
if (l3 == RTE_FLOW_ITEM_TYPE_IPV4)
flow_type =
RTE_ETH_FLOW_NONFRAG_IPV4_UDP;
pctype =
I40E_FILTER_PCTYPE_NONF_IPV4_UDP;
else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6)
flow_type =
RTE_ETH_FLOW_NONFRAG_IPV6_UDP;
pctype =
I40E_FILTER_PCTYPE_NONF_IPV6_UDP;
if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) {
filter->input.flow.udp4_flow.src_port =
@ -2663,11 +2661,11 @@ i40e_flow_parse_fdir_pattern(struct rte_eth_dev *dev,
/* Get filter info */
if (l3 == RTE_FLOW_ITEM_TYPE_IPV4)
flow_type =
RTE_ETH_FLOW_NONFRAG_IPV4_SCTP;
pctype =
I40E_FILTER_PCTYPE_NONF_IPV4_SCTP;
else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6)
flow_type =
RTE_ETH_FLOW_NONFRAG_IPV6_SCTP;
pctype =
I40E_FILTER_PCTYPE_NONF_IPV6_SCTP;
if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) {
filter->input.flow.sctp4_flow.src_port =
@ -2776,15 +2774,6 @@ i40e_flow_parse_fdir_pattern(struct rte_eth_dev *dev,
}
}
pctype = i40e_flowtype_to_pctype(pf->adapter, flow_type);
if (pctype == I40E_FILTER_PCTYPE_INVALID ||
pctype > I40E_FILTER_PCTYPE_L2_PAYLOAD) {
rte_flow_error_set(error, EINVAL,
RTE_FLOW_ERROR_TYPE_ITEM, item,
"Unsupported flow type");
return -rte_errno;
}
ret = i40e_flow_set_fdir_inset(pf, pctype, input_set);
if (ret == -1) {
rte_flow_error_set(error, EINVAL,
@ -2798,7 +2787,7 @@ i40e_flow_parse_fdir_pattern(struct rte_eth_dev *dev,
return -rte_errno;
}
filter->input.flow_type = flow_type;
filter->input.pctype = pctype;
/* Store flex mask to SW */
ret = i40e_flow_store_flex_mask(pf, pctype, flex_mask);
@ -2833,7 +2822,7 @@ static int
i40e_flow_parse_fdir_action(struct rte_eth_dev *dev,
const struct rte_flow_action *actions,
struct rte_flow_error *error,
struct rte_eth_fdir_filter *filter)
struct i40e_fdir_filter_conf *filter)
{
struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
const struct rte_flow_action *act;
@ -2856,13 +2845,13 @@ i40e_flow_parse_fdir_action(struct rte_eth_dev *dev,
"Invalid queue ID for FDIR.");
return -rte_errno;
}
filter->action.behavior = RTE_ETH_FDIR_ACCEPT;
filter->action.behavior = I40E_FDIR_ACCEPT;
break;
case RTE_FLOW_ACTION_TYPE_DROP:
filter->action.behavior = RTE_ETH_FDIR_REJECT;
filter->action.behavior = I40E_FDIR_REJECT;
break;
case RTE_FLOW_ACTION_TYPE_PASSTHRU:
filter->action.behavior = RTE_ETH_FDIR_PASSTHRU;
filter->action.behavior = I40E_FDIR_PASSTHRU;
break;
default:
rte_flow_error_set(error, EINVAL,
@ -2877,11 +2866,11 @@ i40e_flow_parse_fdir_action(struct rte_eth_dev *dev,
switch (act->type) {
case RTE_FLOW_ACTION_TYPE_MARK:
mark_spec = (const struct rte_flow_action_mark *)act->conf;
filter->action.report_status = RTE_ETH_FDIR_REPORT_ID;
filter->action.report_status = I40E_FDIR_REPORT_ID;
filter->soft_id = mark_spec->id;
break;
case RTE_FLOW_ACTION_TYPE_FLAG:
filter->action.report_status = RTE_ETH_FDIR_NO_REPORT_STATUS;
filter->action.report_status = I40E_FDIR_NO_REPORT_STATUS;
break;
case RTE_FLOW_ACTION_TYPE_END:
return 0;
@ -2912,7 +2901,7 @@ i40e_flow_parse_fdir_filter(struct rte_eth_dev *dev,
struct rte_flow_error *error,
union i40e_filter_t *filter)
{
struct rte_eth_fdir_filter *fdir_filter =
struct i40e_fdir_filter_conf *fdir_filter =
&filter->fdir_filter;
int ret;
@ -3878,7 +3867,7 @@ i40e_flow_create(struct rte_eth_dev *dev,
i40e_ethertype_filter_list);
break;
case RTE_ETH_FILTER_FDIR:
ret = i40e_add_del_fdir_filter(dev,
ret = i40e_flow_add_del_fdir_filter(dev,
&cons_filter.fdir_filter, 1);
if (ret)
goto free_flow;
@ -3928,7 +3917,7 @@ i40e_flow_destroy(struct rte_eth_dev *dev,
(struct i40e_tunnel_filter *)flow->rule);
break;
case RTE_ETH_FILTER_FDIR:
ret = i40e_add_del_fdir_filter(dev,
ret = i40e_flow_add_del_fdir_filter(dev,
&((struct i40e_fdir_filter *)flow->rule)->fdir, 0);
break;
default: