From: Jingjing Wu <jingjing.wu@intel.com> To: dev@dpdk.org Subject: [dpdk-dev] [PATCH v3 06/20] i40e: implement operations to add/delete flow director Date: Fri, 26 Sep 2014 14:03:24 +0800 Message-ID: <1411711418-12881-7-git-send-email-jingjing.wu@intel.com> (raw) In-Reply-To: <1411711418-12881-1-git-send-email-jingjing.wu@intel.com> deal with two operations for flow director - RTE_ETH_FILTER_OP_ADD - RTE_ETH_FILTER_OP_DELETE encode the flow inputs to programming packet sent the packet to filter programming queue and check status on the status report queue Signed-off-by: Jingjing Wu <jingjing.wu@intel.com> Acked-by: Chen Jing D(Mark) <jing.d.chen@intel.com> Acked-by: Helin Zhang <helin.zhang@intel.com> --- lib/librte_pmd_i40e/i40e_ethdev.c | 29 ++ lib/librte_pmd_i40e/i40e_ethdev.h | 3 + lib/librte_pmd_i40e/i40e_fdir.c | 617 +++++++++++++++++++++++++++++++++++++- 3 files changed, 648 insertions(+), 1 deletion(-) diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c b/lib/librte_pmd_i40e/i40e_ethdev.c index a3f25e6..9791519 100644 --- a/lib/librte_pmd_i40e/i40e_ethdev.c +++ b/lib/librte_pmd_i40e/i40e_ethdev.c @@ -205,6 +205,9 @@ static int i40e_dev_rss_hash_update(struct rte_eth_dev *dev, struct rte_eth_rss_conf *rss_conf); static int i40e_dev_rss_hash_conf_get(struct rte_eth_dev *dev, struct rte_eth_rss_conf *rss_conf); +static int i40e_dev_filter_ctrl(struct rte_eth_dev *dev, + enum rte_filter_type filter_type, + enum rte_filter_op filter_op, void *arg); /* Default hash key buffer for RSS */ static uint32_t rss_key_default[I40E_PFQF_HKEY_MAX_INDEX + 1]; @@ -256,6 +259,7 @@ static struct eth_dev_ops i40e_eth_dev_ops = { .reta_query = i40e_dev_rss_reta_query, .rss_hash_update = i40e_dev_rss_hash_update, .rss_hash_conf_get = i40e_dev_rss_hash_conf_get, + .filter_ctrl = i40e_dev_filter_ctrl, }; static struct eth_driver rte_i40e_pmd = { @@ -4221,3 +4225,28 @@ i40e_pf_config_mq_rx(struct i40e_pf *pf) return 0; } + +/* + * Take operations to assigned filter type on NIC. + */ +static int +i40e_dev_filter_ctrl(struct rte_eth_dev *dev, enum rte_filter_type filter_type, + enum rte_filter_op filter_op, void *arg) +{ + struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); + int ret = I40E_SUCCESS; + + if (dev == NULL) + return -EINVAL; + + switch (filter_type) { + case RTE_ETH_FILTER_FDIR: + ret = i40e_fdir_ctrl_func(pf, filter_op, arg); + break; + default: + PMD_DRV_LOG(ERR, "unsupported filter type %u.", filter_type); + ret = -EINVAL; + break; + } + return ret; +} diff --git a/lib/librte_pmd_i40e/i40e_ethdev.h b/lib/librte_pmd_i40e/i40e_ethdev.h index 2460635..af149df 100644 --- a/lib/librte_pmd_i40e/i40e_ethdev.h +++ b/lib/librte_pmd_i40e/i40e_ethdev.h @@ -341,6 +341,9 @@ enum i40e_status_code i40e_fdir_setup_rx_resources(struct i40e_pf *pf, unsigned int socket_id); int i40e_fdir_setup(struct i40e_pf *pf); void i40e_fdir_teardown(struct i40e_pf *pf); +int i40e_fdir_ctrl_func(struct i40e_pf *pf, + enum rte_filter_op filter_op, + void *arg); /* I40E_DEV_PRIVATE_TO */ #define I40E_DEV_PRIVATE_TO_PF(adapter) \ diff --git a/lib/librte_pmd_i40e/i40e_fdir.c b/lib/librte_pmd_i40e/i40e_fdir.c index a3e6bd7..82645df 100644 --- a/lib/librte_pmd_i40e/i40e_fdir.c +++ b/lib/librte_pmd_i40e/i40e_fdir.c @@ -44,6 +44,10 @@ #include <rte_log.h> #include <rte_memzone.h> #include <rte_malloc.h> +#include <rte_ip.h> +#include <rte_udp.h> +#include <rte_tcp.h> +#include <rte_sctp.h> #include "i40e_logs.h" #include "i40e/i40e_type.h" @@ -51,12 +55,43 @@ #include "i40e_rxtx.h" #define I40E_FDIR_MZ_NAME "FDIR_MEMZONE" +#ifndef IPV6_ADDR_LEN +#define IPV6_ADDR_LEN 16 +#endif + #define I40E_FDIR_PKT_LEN 512 +#define I40E_FDIR_IP_DEFAULT_LEN 420 +#define I40E_FDIR_IP_DEFAULT_TTL 0x40 +#define I40E_FDIR_IP_DEFAULT_VERSION_IHL 0x45 +#define I40E_FDIR_TCP_DEFAULT_DATAOFF 0x50 +#define I40E_FDIR_IPv6_DEFAULT_VTC_FLOW 0x60300000 +#define I40E_FDIR_IPv6_DEFAULT_HOP_LIMITS 0xFF +#define I40E_FDIR_IPv6_PAYLOAD_LEN 380 +#define I40E_FDIR_UDP_DEFAULT_LEN 400 + +/* Wait count and inteval for fdir filter programming */ +#define I40E_FDIR_WAIT_COUNT 10 +#define I40E_FDIR_WAIT_INTERVAL_US 1000 + +/* Wait count and inteval for fdir filter flush */ +#define I40E_FDIR_FLUSH_RETRY 50 +#define I40E_FDIR_FLUSH_INTERVAL_MS 5 + #define I40E_COUNTER_PF 2 /* Statistic counter index for one pf */ #define I40E_COUNTER_INDEX_FDIR(pf_id) (0 + (pf_id) * I40E_COUNTER_PF) static int i40e_fdir_rx_queue_init(struct i40e_rx_queue *rxq); +static int i40e_fdir_construct_pkt(struct i40e_pf *pf, + struct rte_eth_fdir_input *fdir_input, + unsigned char *raw_pkt); +static int i40e_add_del_fdir_filter(struct i40e_pf *pf, + struct rte_eth_fdir_filter *filter, + bool add); +static int i40e_fdir_filter_programming(struct i40e_pf *pf, + enum i40e_filter_pctype pctype, + struct rte_eth_fdir_filter *filter, + bool add); static int i40e_fdir_rx_queue_init(struct i40e_rx_queue *rxq) @@ -285,4 +320,584 @@ i40e_fdir_teardown(struct i40e_pf *pf) i40e_vsi_release(vsi); pf->fdir.fdir_vsi = NULL; return; -} \ No newline at end of file +} + +static int +i40e_fdir_construct_pkt(struct i40e_pf *pf, + struct rte_eth_fdir_input *fdir_input, + unsigned char *raw_pkt) +{ + struct ether_hdr *ether; + unsigned char *payload; + struct ipv4_hdr *ip; + struct ipv6_hdr *ip6; + struct udp_hdr *udp; + struct tcp_hdr *tcp; + struct sctp_hdr *sctp; + uint8_t size = 0; + int i, set_idx = 2; /* set_idx = 2 means using l4 pyload by default*/ + + switch (fdir_input->flow_type) { + case RTE_ETH_FLOW_TYPE_UDPV4: + ether = (struct ether_hdr *)raw_pkt; + ip = (struct ipv4_hdr *)(raw_pkt + sizeof(struct ether_hdr)); + udp = (struct udp_hdr *)(raw_pkt + sizeof(struct ether_hdr) + + sizeof(struct ipv4_hdr)); + payload = raw_pkt + sizeof(struct ether_hdr) + + sizeof(struct ipv4_hdr) + sizeof(struct udp_hdr); + + ether->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->time_to_live = I40E_FDIR_IP_DEFAULT_TTL; + + /* + * 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.udp4_flow.dst_ip; + ip->dst_addr = fdir_input->flow.udp4_flow.src_ip; + ip->next_proto_id = IPPROTO_UDP; + 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 RTE_ETH_FLOW_TYPE_TCPV4: + ether = (struct ether_hdr *)raw_pkt; + ip = (struct ipv4_hdr *)(raw_pkt + sizeof(struct ether_hdr)); + tcp = (struct tcp_hdr *)(raw_pkt + sizeof(struct ether_hdr) + + sizeof(struct ipv4_hdr)); + payload = raw_pkt + sizeof(struct ether_hdr) + + sizeof(struct ipv4_hdr) + sizeof(struct tcp_hdr); + + ether->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4); + ip->version_ihl = I40E_FDIR_IP_DEFAULT_VERSION_IHL; + ip->total_length = rte_cpu_to_be_16(I40E_FDIR_IP_DEFAULT_LEN); + ip->time_to_live = I40E_FDIR_IP_DEFAULT_TTL; + + /* + * 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.tcp4_flow.dst_ip; + ip->dst_addr = fdir_input->flow.tcp4_flow.src_ip; + ip->next_proto_id = IPPROTO_TCP; + 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 RTE_ETH_FLOW_TYPE_SCTPV4: + ether = (struct ether_hdr *)raw_pkt; + ip = (struct ipv4_hdr *)(raw_pkt + sizeof(struct ether_hdr)); + sctp = (struct sctp_hdr *)(raw_pkt + sizeof(struct ether_hdr) + + sizeof(struct ipv4_hdr)); + payload = raw_pkt + sizeof(struct ether_hdr) + + sizeof(struct ipv4_hdr) + sizeof(struct sctp_hdr); + + ether->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4); + ip->version_ihl = I40E_FDIR_IP_DEFAULT_VERSION_IHL; + ip->total_length = rte_cpu_to_be_16(I40E_FDIR_IP_DEFAULT_LEN); + ip->time_to_live = I40E_FDIR_IP_DEFAULT_TTL; + + /* + * 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.sctp4_flow.dst_ip; + ip->dst_addr = fdir_input->flow.sctp4_flow.src_ip; + ip->next_proto_id = IPPROTO_SCTP; + sctp->tag = fdir_input->flow.sctp4_flow.verify_tag; + break; + + case RTE_ETH_FLOW_TYPE_IPV4_OTHER: + ether = (struct ether_hdr *)raw_pkt; + ip = (struct ipv4_hdr *)(raw_pkt + sizeof(struct ether_hdr)); + payload = raw_pkt + sizeof(struct ether_hdr) + + sizeof(struct ipv4_hdr); + + ether->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4); + ip->version_ihl = I40E_FDIR_IP_DEFAULT_VERSION_IHL; + ip->total_length = rte_cpu_to_be_16(I40E_FDIR_IP_DEFAULT_LEN); + ip->time_to_live = I40E_FDIR_IP_DEFAULT_TTL; + ip->next_proto_id = IPPROTO_IP; + + /* + * 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; + set_idx = 1; /* l3 pyload */ + break; + + case RTE_ETH_FLOW_TYPE_UDPV6: + ether = (struct ether_hdr *)raw_pkt; + ip6 = (struct ipv6_hdr *)(raw_pkt + sizeof(struct ether_hdr)); + udp = (struct udp_hdr *)(raw_pkt + sizeof(struct ether_hdr) + + sizeof(struct ipv6_hdr)); + payload = raw_pkt + sizeof(struct ether_hdr) + + sizeof(struct ipv6_hdr) + sizeof(struct udp_hdr); + + ether->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6); + ip6->vtc_flow = rte_cpu_to_be_32(I40E_FDIR_IPv6_DEFAULT_VTC_FLOW); + ip6->payload_len = rte_cpu_to_be_16(I40E_FDIR_IPv6_PAYLOAD_LEN); + ip6->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.udp6_flow.dst_ip), + IPV6_ADDR_LEN); + rte_memcpy(&(ip6->dst_addr), &(fdir_input->flow.udp6_flow.src_ip), + IPV6_ADDR_LEN); + ip6->proto = IPPROTO_UDP; + 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 RTE_ETH_FLOW_TYPE_TCPV6: + ether = (struct ether_hdr *)raw_pkt; + ip6 = (struct ipv6_hdr *)(raw_pkt + sizeof(struct ether_hdr)); + tcp = (struct tcp_hdr *)(raw_pkt + sizeof(struct ether_hdr) + + sizeof(struct ipv6_hdr)); + payload = raw_pkt + sizeof(struct ether_hdr) + + sizeof(struct ipv6_hdr) + sizeof(struct tcp_hdr); + + ether->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6); + ip6->vtc_flow = rte_cpu_to_be_32(I40E_FDIR_IPv6_DEFAULT_VTC_FLOW); + ip6->payload_len = rte_cpu_to_be_16(I40E_FDIR_IPv6_PAYLOAD_LEN); + ip6->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.tcp6_flow.dst_ip), + IPV6_ADDR_LEN); + rte_memcpy(&(ip6->dst_addr), &(fdir_input->flow.tcp6_flow.src_ip), + IPV6_ADDR_LEN); + ip6->proto = IPPROTO_TCP; + 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 RTE_ETH_FLOW_TYPE_SCTPV6: + ether = (struct ether_hdr *)raw_pkt; + ip6 = (struct ipv6_hdr *)(raw_pkt + sizeof(struct ether_hdr)); + sctp = (struct sctp_hdr *)(raw_pkt + sizeof(struct ether_hdr) + + sizeof(struct ipv6_hdr)); + payload = raw_pkt + sizeof(struct ether_hdr) + + sizeof(struct ipv6_hdr) + sizeof(struct sctp_hdr); + + ether->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6); + ip6->vtc_flow = rte_cpu_to_be_32(I40E_FDIR_IPv6_DEFAULT_VTC_FLOW); + ip6->payload_len = rte_cpu_to_be_16(I40E_FDIR_IPv6_PAYLOAD_LEN); + ip6->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.sctp6_flow.dst_ip), + IPV6_ADDR_LEN); + rte_memcpy(&(ip6->dst_addr), &(fdir_input->flow.sctp6_flow.src_ip), + IPV6_ADDR_LEN); + ip6->proto = IPPROTO_SCTP; + sctp->tag = fdir_input->flow.sctp6_flow.verify_tag; + break; + + case RTE_ETH_FLOW_TYPE_IPV6_OTHER: + ether = (struct ether_hdr *)raw_pkt; + ip6 = (struct ipv6_hdr *)(raw_pkt + sizeof(struct ether_hdr)); + payload = raw_pkt + sizeof(struct ether_hdr) + sizeof(struct ipv6_hdr); + + ether->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6); + ip6->vtc_flow = rte_cpu_to_be_32(I40E_FDIR_IPv6_DEFAULT_VTC_FLOW); + ip6->proto = IPPROTO_NONE; + ip6->payload_len = rte_cpu_to_be_16(I40E_FDIR_IPv6_PAYLOAD_LEN); + ip6->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.ip6_flow.dst_ip), + IPV6_ADDR_LEN); + rte_memcpy(&(ip6->dst_addr), &(fdir_input->flow.ip6_flow.src_ip), + IPV6_ADDR_LEN); + set_idx = 1; /* l3 pyload */ + break; + default: + PMD_DRV_LOG(ERR, "unknown flow type %u\n", fdir_input->flow_type); + return -EINVAL; + } + + for (i = 0; i < 3; i++) { + if (pf->fdir.flex_set[set_idx][i].size == 0) + break; + (void)rte_memcpy(payload + 2 * pf->fdir.flex_set[set_idx][i].offset, + fdir_input->flow_ext.flexwords + size, + 2 * pf->fdir.flex_set[set_idx][i].size); + size = pf->fdir.flex_set[set_idx][i].size; + } + return 0; +} + +/* Construct the tx flags */ +static inline uint64_t +i40e_build_ctob(uint32_t td_cmd, + uint32_t td_offset, + unsigned int size, + uint32_t td_tag) +{ + return rte_cpu_to_le_64(I40E_TX_DESC_DTYPE_DATA | + ((uint64_t)td_cmd << I40E_TXD_QW1_CMD_SHIFT) | + ((uint64_t)td_offset << I40E_TXD_QW1_OFFSET_SHIFT) | + ((uint64_t)size << I40E_TXD_QW1_TX_BUF_SZ_SHIFT) | + ((uint64_t)td_tag << I40E_TXD_QW1_L2TAG1_SHIFT)); +} + +/* + * check the programming status descriptor in rx queue. + * done after Programming Flow Director is programmed on + * tx queue + */ +static inline int +i40e_check_fdir_programming_status(struct i40e_rx_queue *rxq) +{ + volatile union i40e_rx_desc *rxdp; + uint64_t qword1; + uint32_t rx_status; + uint32_t len, id; + uint32_t error; + int ret = 0; + + rxdp = &rxq->rx_ring[rxq->rx_tail]; + qword1 = rte_le_to_cpu_64(rxdp->wb.qword1.status_error_len); + rx_status = (qword1 & I40E_RXD_QW1_STATUS_MASK) + >> I40E_RXD_QW1_STATUS_SHIFT; + + if (rx_status & (1 << I40E_RX_DESC_STATUS_DD_SHIFT)) { + len = qword1 >> I40E_RX_PROG_STATUS_DESC_LENGTH_SHIFT; + id = (qword1 & I40E_RX_PROG_STATUS_DESC_QW1_PROGID_MASK) >> + I40E_RX_PROG_STATUS_DESC_QW1_PROGID_SHIFT; + + if (len == I40E_RX_PROG_STATUS_DESC_LENGTH && + id == I40E_RX_PROG_STATUS_DESC_FD_FILTER_STATUS) { + error = (qword1 & + I40E_RX_PROG_STATUS_DESC_QW1_ERROR_MASK) >> + I40E_RX_PROG_STATUS_DESC_QW1_ERROR_SHIFT; + if (error == (0x1 << + I40E_RX_PROG_STATUS_DESC_FD_TBL_FULL_SHIFT)) { + PMD_DRV_LOG(ERR, "Failed to add FDIR filter" + " (FD_ID %u): programming status" + " reported.", + rxdp->wb.qword0.hi_dword.fd_id); + ret = -1; + } else if (error == (0x1 << + I40E_RX_PROG_STATUS_DESC_NO_FD_ENTRY_SHIFT)) { + PMD_DRV_LOG(ERR, "Failed to delete FDIR filter" + " (FD_ID %u): programming status" + " reported.", + rxdp->wb.qword0.hi_dword.fd_id); + ret = -1; + } else + PMD_DRV_LOG(ERR, "invalid programming status" + " reported, error = %u.", error); + } else + PMD_DRV_LOG(ERR, "unknown programming status" + " reported,len = %d, id = %u.", len, id); + rxdp->wb.qword1.status_error_len = 0; + rxq->rx_tail++; + if (unlikely(rxq->rx_tail == rxq->nb_rx_desc)) + rxq->rx_tail = 0; + } + return ret; +} + +/* + * add or remove flow diretor filter. + */ +static int +i40e_add_del_fdir_filter(struct i40e_pf *pf, + struct rte_eth_fdir_filter *filter, + bool add) +{ + int ret = I40E_SUCCESS; + unsigned char *pkt = (unsigned char *)pf->fdir.prg_pkt; + + if (!(pf->flags & I40E_FLAG_FDIR)) { + PMD_DRV_LOG(ERR, "FDIR is not enabled."); + return -ENOTSUP; + } + + 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; + } + + switch (filter->input.flow_type) { + case RTE_ETH_FLOW_TYPE_UDPV4: + ret = i40e_fdir_filter_programming(pf, + I40E_FILTER_PCTYPE_NONF_IPV4_UDP, + filter, add); + if (ret < 0) + PMD_DRV_LOG(ERR, "NONF_IPV4_UDP fdir program fails."); + break; + case RTE_ETH_FLOW_TYPE_TCPV4: + ret = i40e_fdir_filter_programming(pf, + I40E_FILTER_PCTYPE_NONF_IPV4_TCP, + filter, add); + if (ret < 0) + PMD_DRV_LOG(ERR, "NONF_IPV4_TCP fdir program fails."); + break; + case RTE_ETH_FLOW_TYPE_SCTPV4: + ret = i40e_fdir_filter_programming(pf, + I40E_FILTER_PCTYPE_NONF_IPV4_SCTP, + filter, add); + if (ret < 0) { + PMD_DRV_LOG(ERR, "NONF_IPV4_SCTP fdir program fails."); + } + break; + case RTE_ETH_FLOW_TYPE_IPV4_OTHER: + /* program on both NONF_IPV4 and FRAG_IPV4 PCTYPE*/ + ret = i40e_fdir_filter_programming(pf, + I40E_FILTER_PCTYPE_NONF_IPV4_OTHER, + filter, add); + if (ret < 0) + PMD_DRV_LOG(ERR, "NONF_IPV4_OTHER fdir program fails."); + ret = i40e_fdir_filter_programming(pf, + I40E_FILTER_PCTYPE_FRAG_IPV4, + filter, add); + if (ret < 0) + PMD_DRV_LOG(ERR, "NONF_FRAG_IPV4 fdir program fails."); + break; + case RTE_ETH_FLOW_TYPE_UDPV6: + ret = i40e_fdir_filter_programming(pf, + I40E_FILTER_PCTYPE_NONF_IPV6_UDP, + filter, add); + if (ret < 0) + PMD_DRV_LOG(ERR, "NONF_IPV6_UDP fdir program fails."); + break; + case RTE_ETH_FLOW_TYPE_TCPV6: + ret = i40e_fdir_filter_programming(pf, + I40E_FILTER_PCTYPE_NONF_IPV6_TCP, + filter, add); + if (ret < 0) + PMD_DRV_LOG(ERR, "NONF_IPV6_TCP fdir program fails."); + break; + case RTE_ETH_FLOW_TYPE_SCTPV6: + ret = i40e_fdir_filter_programming(pf, + I40E_FILTER_PCTYPE_NONF_IPV6_SCTP, + filter, add); + if (ret < 0) + PMD_DRV_LOG(ERR, "NONF_IPV6_SCTP fdir program fails."); + break; + case RTE_ETH_FLOW_TYPE_IPV6_OTHER: + /* program on both NONF_IPV6 and FRAG_IPV6 PCTYPE*/ + ret = i40e_fdir_filter_programming(pf, + I40E_FILTER_PCTYPE_NONF_IPV6_OTHER, + filter, add); + if (ret < 0) + PMD_DRV_LOG(ERR, "NONF_IPV6_OTHER fdir program fails."); + ret = i40e_fdir_filter_programming(pf, + I40E_FILTER_PCTYPE_FRAG_IPV6, + filter, add); + if (ret < 0) + PMD_DRV_LOG(ERR, "NONF_FRAG_IPV6 fdir program fails."); + break; + default: + PMD_DRV_LOG(ERR, " invalid flow_type input."); + ret = -EINVAL; + } + return ret; +} + +/* + * Program a flow diretor filter rule. + * Is done by Flow Director Programming Descriptor followed by packet + * structure that contains the filter fieldsneed to match. + */ +static int +i40e_fdir_filter_programming(struct i40e_pf *pf, + enum i40e_filter_pctype pctype, + struct rte_eth_fdir_filter *filter, + bool add) +{ + struct i40e_tx_queue *txq = pf->fdir.txq; + struct i40e_rx_queue *rxq = pf->fdir.rxq; + struct rte_eth_fdir_input *fdir_input = &filter->input; + struct rte_eth_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 i; + uint8_t dest; + + PMD_DRV_LOG(INFO, "filling filter prgramming 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); + + /* Use LAN VSI Id if not programmed by user */ + if (fdir_input->flow_ext.dest_id == 0) + fdirdp->qindex_flex_ptype_vsi |= + rte_cpu_to_le_32((pf->main_vsi->vsi_id << + I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT) & + I40E_TXD_FLTR_QW0_DEST_VSI_MASK); + else + fdirdp->qindex_flex_ptype_vsi |= + rte_cpu_to_le_32((fdir_input->flow_ext.dest_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->drop) + dest = I40E_FILTER_PROGRAM_DESC_DEST_DROP_PACKET; + else + dest = I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX; + 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); + if (fdir_action->cnt_idx != 0) + fdirdp->dtype_cmd_cntindex |= + rte_cpu_to_le_32((fdir_action->cnt_idx << + I40E_TXD_FLTR_QW1_CNTINDEX_SHIFT) & + I40E_TXD_FLTR_QW1_CNTINDEX_MASK); + else + fdirdp->dtype_cmd_cntindex |= + rte_cpu_to_le_32((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); + txq->tx_tail++; + if (txq->tx_tail >= txq->nb_tx_desc) + txq->tx_tail = 0; + + PMD_DRV_LOG(INFO, "filling transmit descriptor."); + txdp = &(txq->tx_ring[txq->tx_tail]); + 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++; + 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_WAIT_COUNT; i++) { + rte_delay_us(I40E_FDIR_WAIT_INTERVAL_US); + if (txdp->cmd_type_offset_bsz & + rte_cpu_to_le_64(I40E_TX_DESC_DTYPE_DESC_DONE)) + break; + } + if (i >= I40E_FDIR_WAIT_COUNT) { + PMD_DRV_LOG(ERR, "Failed to program FDIR filter:" + " timeout to get DD on tx queue."); + return -ETIMEDOUT; + } + /* totally delay 10 ms to check programming status*/ + rte_delay_us((I40E_FDIR_WAIT_COUNT - i) * I40E_FDIR_WAIT_INTERVAL_US); + if (i40e_check_fdir_programming_status(rxq) < 0) { + PMD_DRV_LOG(ERR, "Failed to program FDIR filter:" + " programming status reported."); + return -ENOSYS; + } + + return 0; +} + +/* + * i40e_fdir_ctrl_func - deal with all operations on flow director. + * @pf: board private structure + * @filter_op:operation will be taken. + * @arg: a pointer to specific structure corresponding to the filter_op + */ +int +i40e_fdir_ctrl_func(struct i40e_pf *pf, enum rte_filter_op filter_op, void *arg) +{ + int ret = I40E_SUCCESS; + + if (arg == NULL && filter_op != RTE_ETH_FILTER_OP_NONE && + filter_op != RTE_ETH_FILTER_OP_FLUSH) + return -EINVAL; + + switch (filter_op) { + case RTE_ETH_FILTER_OP_NONE: + if (!(pf->flags & I40E_FLAG_FDIR)) + ret = -ENOTSUP; + break; + case RTE_ETH_FILTER_OP_ADD: + ret = i40e_add_del_fdir_filter(pf, + (struct rte_eth_fdir_filter *)arg, + TRUE); + break; + case RTE_ETH_FILTER_OP_DELETE: + ret = i40e_add_del_fdir_filter(pf, + (struct rte_eth_fdir_filter *)arg, + FALSE); + break; + default: + PMD_DRV_LOG(ERR, "unknown operation %u.", filter_op); + ret = -EINVAL; + break; + } + return ret; +} -- 1.8.1.4
next prev parent reply other threads:[~2014-09-26 5:57 UTC|newest] Thread overview: 123+ messages / expand[flat|nested] mbox.gz Atom feed top 2014-09-26 6:03 [dpdk-dev] [PATCH v3 00/20] Support flow director programming on Fortville Jingjing Wu 2014-09-26 6:03 ` [dpdk-dev] [PATCH v3 01/20] i40e: set up and initialize flow director Jingjing Wu 2014-09-26 6:03 ` [dpdk-dev] [PATCH v3 02/20] i40e: tear down " Jingjing Wu 2014-09-26 6:03 ` [dpdk-dev] [PATCH v3 03/20] i40e: initialize flexible payload setting Jingjing Wu 2014-09-26 6:03 ` [dpdk-dev] [PATCH v3 04/20] lib/librte_ether: new filter APIs definition Jingjing Wu 2014-09-26 6:03 ` [dpdk-dev] [PATCH v3 05/20] lib/librte_ether: define structures for adding/deleting flow director Jingjing Wu 2014-09-26 6:03 ` Jingjing Wu [this message] 2014-09-26 6:03 ` [dpdk-dev] [PATCH v3 07/20] app/test-pmd: add test commands to add/delete flow director filter Jingjing Wu 2014-09-26 6:03 ` [dpdk-dev] [PATCH v3 08/20] i40e: match counter for flow director Jingjing Wu 2014-09-26 6:03 ` [dpdk-dev] [PATCH v3 09/20] i40e: report flow director match info to mbuf Jingjing Wu 2014-09-26 6:03 ` [dpdk-dev] [PATCH v3 10/20] lib/librte_ether: define structures for getting flow director information Jingjing Wu 2014-09-26 6:03 ` [dpdk-dev] [PATCH v3 11/20] i40e: implement operations to get fdir info Jingjing Wu 2014-09-26 6:03 ` [dpdk-dev] [PATCH v3 12/20] app/test-pmd: display fdir statistics Jingjing Wu 2014-09-26 6:03 ` [dpdk-dev] [PATCH v3 13/20] i40e: implement operation to flush flow director table Jingjing Wu 2014-09-26 6:03 ` [dpdk-dev] [PATCH v3 14/20] app/test-pmd: add test command " Jingjing Wu 2014-09-26 6:03 ` [dpdk-dev] [PATCH v3 15/20] lib/librte_ether: define structures for configuring flexible payload Jingjing Wu 2014-09-26 6:03 ` [dpdk-dev] [PATCH v316/20] i40e: implement operations to configure " Jingjing Wu 2014-09-26 6:03 ` [dpdk-dev] [PATCH v3 17/20] app/test-pmd: add test command " Jingjing Wu 2014-09-26 6:03 ` [dpdk-dev] [PATCH v3 18/20] lib/librte_ether: define structures for configuring flex masks Jingjing Wu 2014-09-26 6:03 ` [dpdk-dev] [PATCH v3 19/20] i40e: implement operations to configure flexible masks Jingjing Wu 2014-09-26 6:03 ` [dpdk-dev] [PATCH v3 20/20] app/test-pmd: add test command " Jingjing Wu 2014-10-13 15:58 ` De Lara Guarch, Pablo 2014-10-22 1:01 ` [dpdk-dev] [PATCH v4 00/21] Support flow director programming on Fortville Jingjing Wu 2014-10-22 1:01 ` [dpdk-dev] [PATCH v4 01/21] i40e: set up and initialize flow director Jingjing Wu 2014-10-22 1:01 ` [dpdk-dev] [PATCH v4 02/21] i40e: tear down " Jingjing Wu 2014-10-22 1:01 ` [dpdk-dev] [PATCH v4 03/21] i40e: initialize flexible payload setting Jingjing Wu 2014-10-22 1:01 ` [dpdk-dev] [PATCH v4 04/21] ethdev: define structures for adding/deleting flow director Jingjing Wu 2014-10-27 16:57 ` Thomas Monjalon 2014-10-28 1:18 ` Wu, Jingjing 2014-10-28 13:17 ` Thomas Monjalon 2014-10-29 1:29 ` Wu, Jingjing 2014-10-22 1:01 ` [dpdk-dev] [PATCH v4 05/21] i40e: implement operations to add/delete " Jingjing Wu 2014-10-22 1:01 ` [dpdk-dev] [PATCH v4 06/21] testpmd: add test commands to add/delete flow director filter Jingjing Wu 2014-10-28 13:23 ` Thomas Monjalon 2014-10-22 1:01 ` [dpdk-dev] [PATCH v4 07/21] i40e: match counter for flow director Jingjing Wu 2014-10-22 1:01 ` [dpdk-dev] [PATCH v4 08/21] mbuf: extend fdir field Jingjing Wu 2014-10-28 13:28 ` Thomas Monjalon 2014-10-29 1:45 ` Wu, Jingjing 2014-10-22 1:01 ` [dpdk-dev] [PATCH v4 09/21] i40e: report flow director match info to mbuf Jingjing Wu 2014-10-22 1:01 ` [dpdk-dev] [PATCH v4 10/21] testpmd: print extended fdir info in mbuf Jingjing Wu 2014-10-22 1:01 ` [dpdk-dev] [PATCH v4 11/21] ethdev: define structures for getting flow director information Jingjing Wu 2014-10-28 13:44 ` Thomas Monjalon 2014-10-29 2:10 ` Wu, Jingjing 2014-10-29 9:48 ` Thomas Monjalon 2014-10-22 1:01 ` [dpdk-dev] [PATCH v4 12/21] i40e: implement operations to get fdir info Jingjing Wu 2014-10-22 1:01 ` [dpdk-dev] [PATCH v4 13/21] testpmd: display fdir statistics Jingjing Wu 2014-10-22 1:01 ` [dpdk-dev] [PATCH v4 14/21] i40e: implement operation to flush flow director table Jingjing Wu 2014-10-22 1:01 ` [dpdk-dev] [PATCH v4 15/21] testpmd: add test command " Jingjing Wu 2014-10-28 13:53 ` Thomas Monjalon 2014-10-22 1:01 ` [dpdk-dev] [PATCH v4 16/21] ethdev: define structures for configuring flexible payload Jingjing Wu 2014-10-28 14:14 ` Thomas Monjalon 2014-10-29 3:21 ` Wu, Jingjing 2014-10-29 9:55 ` Thomas Monjalon 2014-10-22 1:01 ` [dpdk-dev] [PATCH v4 17/21] i40e: implement operations to configure " Jingjing Wu 2014-10-22 1:01 ` [dpdk-dev] [PATCH v4 18/21] testpmd: add test command " Jingjing Wu 2014-10-22 1:01 ` [dpdk-dev] [PATCH v4 19/21] ethdev: define structures for configuring flex masks Jingjing Wu 2014-10-22 1:01 ` [dpdk-dev] [PATCH v4 20/21] i40e: implement operations to configure flexible masks Jingjing Wu 2014-10-22 1:01 ` [dpdk-dev] [PATCH v4 21/21] testpmd: add test command " Jingjing Wu 2014-10-28 14:18 ` Thomas Monjalon 2014-10-29 2:35 ` Wu, Jingjing 2014-10-27 15:22 ` [dpdk-dev] [PATCH v4 00/21] Support flow director programming on Fortville Thomas Monjalon 2014-10-28 0:48 ` Zhang, Helin 2014-10-30 7:26 ` [dpdk-dev] [PATCH v5 " Jingjing Wu 2014-10-30 7:26 ` [dpdk-dev] [PATCH v5 01/21] i40e: set up and initialize flow director Jingjing Wu 2014-10-30 8:25 ` Wu, Jingjing 2014-10-30 7:26 ` [dpdk-dev] [PATCH v5 02/21] i40e: tear down " Jingjing Wu 2014-11-19 7:53 ` Cao, Min 2014-10-30 7:26 ` [dpdk-dev] [PATCH v5 03/21] i40e: initialize flexible payload setting Jingjing Wu 2014-10-30 7:26 ` [dpdk-dev] [PATCH v5 04/21] ethdev: define structures for adding/deleting flow director Jingjing Wu 2014-10-30 7:26 ` [dpdk-dev] [PATCH v5 05/21] i40e: implement operations to add/delete " Jingjing Wu 2014-11-05 21:18 ` De Lara Guarch, Pablo 2014-11-13 9:50 ` Thomas Monjalon 2014-11-13 11:36 ` Wu, Jingjing 2014-10-30 7:26 ` [dpdk-dev] [PATCH v5 06/21] testpmd: add test commands to add/delete flow director filter Jingjing Wu 2014-10-30 7:26 ` [dpdk-dev] [PATCH v5 07/21] i40e: match counter for flow director Jingjing Wu 2014-10-30 7:26 ` [dpdk-dev] [PATCH v5 08/21] mbuf: extend fdir field Jingjing Wu 2014-10-30 7:26 ` [dpdk-dev] [PATCH v5 09/21] i40e: report flow director match info to mbuf Jingjing Wu 2014-10-30 7:26 ` [dpdk-dev] [PATCH v5 10/21] testpmd: print extended fdir info in mbuf Jingjing Wu 2014-10-30 7:26 ` [dpdk-dev] [PATCH v5 11/21] ethdev: define structures for getting flow director information Jingjing Wu 2014-10-30 7:26 ` [dpdk-dev] [PATCH v5 12/21] i40e: implement operations to get fdir info Jingjing Wu 2014-10-30 7:26 ` [dpdk-dev] [PATCH v5 13/21] testpmd: display fdir statistics Jingjing Wu 2014-10-30 7:26 ` [dpdk-dev] [PATCH v5 14/21] i40e: implement operation to flush flow director table Jingjing Wu 2014-10-30 7:26 ` [dpdk-dev] [PATCH v5 15/21] testpmd: add test command " Jingjing Wu 2014-10-30 7:26 ` [dpdk-dev] [PATCH v5 16/21] ethdev: define structures for configuring flexible payload Jingjing Wu 2014-10-30 7:26 ` [dpdk-dev] [PATCH v5 17/21] i40e: implement operations to configure " Jingjing Wu 2014-10-30 7:26 ` [dpdk-dev] [PATCH v5 18/21] testpmd: add test command " Jingjing Wu 2014-10-30 7:26 ` [dpdk-dev] [PATCH v5 19/21] ethdev: define structures for configuring flex masks Jingjing Wu 2014-10-30 7:26 ` [dpdk-dev] [PATCH v5 20/21] i40e: implement operations to configure flexible masks Jingjing Wu 2014-10-30 7:26 ` [dpdk-dev] [PATCH v5 21/21] testpmd: add test command " Jingjing Wu 2014-10-30 8:07 ` [dpdk-dev] [PATCH v5 01/21] i40e: set up and initialize flow director Jingjing Wu 2014-11-21 0:46 ` [dpdk-dev] [PATCH v6 00/22] Support flow director programming on Fortville Jingjing Wu 2014-11-21 0:46 ` [dpdk-dev] [PATCH v6 01/22] i40e: set up and initialize flow director Jingjing Wu 2014-11-21 0:46 ` [dpdk-dev] [PATCH v6 02/22] i40e: tear down " Jingjing Wu 2014-11-21 0:46 ` [dpdk-dev] [PATCH v6 03/22] i40e: initialize flexible payload setting Jingjing Wu 2014-11-21 0:46 ` [dpdk-dev] [PATCH v6 04/22] ethdev: define structures for adding/deleting flow director Jingjing Wu 2014-11-21 0:46 ` [dpdk-dev] [PATCH v6 05/22] i40e: define functions for transition between flow_type and pctype Jingjing Wu 2014-11-21 0:46 ` [dpdk-dev] [PATCH v6 06/22] i40e: implement operations to add/delete flow director Jingjing Wu 2014-11-21 0:46 ` [dpdk-dev] [PATCH v6 07/22] testpmd: add test commands to add/delete flow director filter Jingjing Wu 2014-11-21 0:46 ` [dpdk-dev] [PATCH v6 08/22] i40e: match counter for flow director Jingjing Wu 2014-11-21 0:46 ` [dpdk-dev] [PATCH v6 09/22] mbuf: extend fdir field Jingjing Wu 2014-11-21 17:03 ` Chilikin, Andrey 2014-11-21 19:34 ` Ananyev, Konstantin 2014-11-21 19:37 ` Chilikin, Andrey 2014-11-21 0:46 ` [dpdk-dev] [PATCH v6 10/22] i40e: report flow director match info to mbuf Jingjing Wu 2014-11-21 0:46 ` [dpdk-dev] [PATCH v6 11/22] testpmd: print extended fdir info in mbuf Jingjing Wu 2014-11-21 0:46 ` [dpdk-dev] [PATCH v6 12/22] i40e: implement operation to flush flow director table Jingjing Wu 2014-11-21 0:46 ` [dpdk-dev] [PATCH v6 13/22] testpmd: add test command " Jingjing Wu 2014-11-21 0:46 ` [dpdk-dev] [PATCH v6 14/22] ethdev: define structures for getting flow director information Jingjing Wu 2014-11-21 0:46 ` [dpdk-dev] [PATCH v6 15/22] i40e: implement operations to get fdir info Jingjing Wu 2014-11-21 0:46 ` [dpdk-dev] [PATCH v6 16/22] ethdev: define structures for getting flow director statistics Jingjing Wu 2014-11-21 0:46 ` [dpdk-dev] [PATCH v6 17/22] i40e: implement operations to get fdir statistics Jingjing Wu 2014-11-21 0:46 ` [dpdk-dev] [PATCH v6 18/22] testpmd: display fdir info Jingjing Wu 2014-11-21 0:46 ` [dpdk-dev] [PATCH v6 19/22] ethdev: add flexible payload setting in eth_conf Jingjing Wu 2014-11-21 0:46 ` [dpdk-dev] [PATCH v6 20/22] i40e: take flow director flexible payload configuration Jingjing Wu 2014-11-21 0:46 ` [dpdk-dev] [PATCH v6 21/22] testpmd: add test command to configure flexible mask Jingjing Wu 2014-11-21 0:46 ` [dpdk-dev] [PATCH v6 22/22] testpmd: add test command to configure flexible payload Jingjing Wu 2014-11-21 11:34 ` [dpdk-dev] [PATCH v6 00/22] Support flow director programming on Fortville Ananyev, Konstantin 2014-11-24 23:20 ` Thomas Monjalon 2014-11-25 4:51 ` Wu, Jingjing 2014-11-25 9:23 ` Thomas Monjalon 2014-10-30 7:34 ` [dpdk-dev] [PATCH v4 00/21] " Cao, Min 2014-11-19 7:53 ` Cao, Min 2014-10-30 7:12 ` [dpdk-dev] [PATCH v3 00/20] " Cao, Min
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=1411711418-12881-7-git-send-email-jingjing.wu@intel.com \ --to=jingjing.wu@intel.com \ --cc=dev@dpdk.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
DPDK patches and discussions This inbox may be cloned and mirrored by anyone: git clone --mirror https://inbox.dpdk.org/dev/0 dev/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 dev dev/ https://inbox.dpdk.org/dev \ dev@dpdk.org public-inbox-index dev Example config snippet for mirrors. Newsgroup available over NNTP: nntp://inbox.dpdk.org/inbox.dpdk.dev AGPL code for this site: git clone https://public-inbox.org/public-inbox.git