From patchwork Fri Aug 1 07:08:35 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jingjing Wu X-Patchwork-Id: 118 Return-Path: Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) by dpdk.org (Postfix) with ESMTP id 0D2D7B37D for ; Fri, 1 Aug 2014 09:07:02 +0200 (CEST) Received: from orsmga001.jf.intel.com ([10.7.209.18]) by orsmga102.jf.intel.com with ESMTP; 01 Aug 2014 00:03:21 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.01,778,1400050800"; d="scan'208";a="552236317" Received: from shvmail01.sh.intel.com ([10.239.29.42]) by orsmga001.jf.intel.com with ESMTP; 01 Aug 2014 00:09:04 -0700 Received: from shecgisg004.sh.intel.com (shecgisg004.sh.intel.com [10.239.29.89]) by shvmail01.sh.intel.com with ESMTP id s71792oX014934; Fri, 1 Aug 2014 15:09:02 +0800 Received: from shecgisg004.sh.intel.com (localhost [127.0.0.1]) by shecgisg004.sh.intel.com (8.13.6/8.13.6/SuSE Linux 0.8) with ESMTP id s7178wpr025063; Fri, 1 Aug 2014 15:09:00 +0800 Received: (from wujingji@localhost) by shecgisg004.sh.intel.com (8.13.6/8.13.6/Submit) id s7178wZ8025059; Fri, 1 Aug 2014 15:08:58 +0800 From: Jingjing Wu To: dev@dpdk.org Date: Fri, 1 Aug 2014 15:08:35 +0800 Message-Id: <1406876916-24869-6-git-send-email-jingjing.wu@intel.com> X-Mailer: git-send-email 1.7.0.7 In-Reply-To: <1406876916-24869-1-git-send-email-jingjing.wu@intel.com> References: <1406876916-24869-1-git-send-email-jingjing.wu@intel.com> Subject: [dpdk-dev] [PATCH 5/6] app/test-pmd: add commands and config functions for i40e flow director support X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 01 Aug 2014 07:07:04 -0000 add structure definition to construct programming packet. add commands to programming 6 flow types for the flow director filters, which is called PCTYPE in fortville: ipv4, tcpv4, udpv4, ipv6, tcpv6, udpv6 add command to support flushing flow director table Signed-off-by: jingjing.wu --- app/test-pmd/cmdline.c | 665 +++++++++++++++++++++++++++++++++++++++++++++++++ app/test-pmd/config.c | 54 +++- app/test-pmd/testpmd.c | 22 ++ app/test-pmd/testpmd.h | 57 +++++ 4 files changed, 786 insertions(+), 12 deletions(-) diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c index 345be11..bf7e45c 100644 --- a/app/test-pmd/cmdline.c +++ b/app/test-pmd/cmdline.c @@ -74,6 +74,14 @@ #include #include #include +#include +#include +#include +#include +#include +#ifdef RTE_LIBRTE_I40E_PMD +#include +#endif /* RTE_LIBRTE_I40E_PMD */ #include #include @@ -655,6 +663,25 @@ static void cmd_help_long_parsed(void *parsed_result, "get_flex_filter (port_id) index (idx)\n" " get info of a flex filter.\n\n" + +#ifdef RTE_LIBRTE_I40E_PMD + "i40e_flow_director_filter (port_id) (add|del)" + " flow (ip4|ip6) src (src_ip_address) dst (dst_ip_address)" + " flexwords (flexwords_value) (drop|fwd)" + " queue (queue_id) fd_id (fd_id_value)\n" + " Add/Del a IP type flow director filter for i40e NIC.\n\n" + + "i40e_flow_director_filter (port_id) (add|del)" + " flow (udp4|tcp4|udp6|tcp6)" + " src (src_ip_address) (src_port)" + " dst (dst_ip_address) (dst_port)" + " flexwords (flexwords_value) (drop|fwd)" + " queue (queue_id) fd_id (fd_id_value)\n" + " Add/Del a UDP/TCP type flow director filter for i40e NIC.\n\n" + + "i40e_flush_flow_diretor (port_id)\n" + " Flush all flow director entries of a device on i40e NIC.\n\n" +#endif /* RTE_LIBRTE_I40E_PMD */ ); } } @@ -7304,6 +7331,639 @@ cmdline_parse_inst_t cmd_get_flex_filter = { }, }; +/* *** Classification Filters Control *** */ +#ifdef RTE_LIBRTE_I40E_PMD +/* *** deal with i40e flow director filter *** */ +struct cmd_i40e_flow_director_result { + cmdline_fixed_string_t flow_director_filter; + uint8_t port_id; + cmdline_fixed_string_t ops; + cmdline_fixed_string_t flow; + cmdline_fixed_string_t flow_type; + cmdline_fixed_string_t src; + cmdline_ipaddr_t ip_src; + uint16_t port_src; + cmdline_fixed_string_t dst; + cmdline_ipaddr_t ip_dst; + uint16_t port_dst; + cmdline_fixed_string_t flexwords; + cmdline_fixed_string_t flexwords_value; + cmdline_fixed_string_t drop; + cmdline_fixed_string_t queue; + uint16_t queue_id; + cmdline_fixed_string_t fd_id; + uint32_t fd_id_value; +}; + +static inline int +parse_flexwords(const char *q_arg, uint16_t *flexwords) +{ +#define MAX_NUM_WORD 8 + char s[256]; + const char *p, *p0 = q_arg; + char *end; + unsigned long int_fld[MAX_NUM_WORD]; + char *str_fld[MAX_NUM_WORD]; + int i; + unsigned size; + int num_words = -1; + + p = strchr(p0, '('); + if (p == NULL) + return -1; + ++p; + p0 = strchr(p, ')'); + if (p0 == NULL) + return -1; + + size = p0 - p; + if (size >= sizeof(s)) + return -1; + + snprintf(s, sizeof(s), "%.*s", size, p); + num_words = rte_strsplit(s, sizeof(s), str_fld, MAX_NUM_WORD, ','); + if (num_words < 0 || num_words > MAX_NUM_WORD) + return -1; + for (i = 0; i < num_words; i++) { + errno = 0; + int_fld[i] = strtoul(str_fld[i], &end, 0); + if (errno != 0 || end == str_fld[i] || int_fld[i] > UINT16_MAX) + return -1; + flexwords[i] = rte_cpu_to_be_16((uint16_t)int_fld[i]); + } + return num_words; +} + +static inline struct rte_mbuf * +tx_mbuf_alloc(struct rte_mempool *mp) +{ + struct rte_mbuf *m; + + m = __rte_mbuf_raw_alloc(mp); + __rte_mbuf_sanity_check_raw(m, RTE_MBUF_PKT, 0); + return m; +} + +static inline void +rte_i40e_fdir_construct_ip4_input(struct ipv4_other_flow *flow, + unsigned char *raw_pkt) +{ + struct ether_hdr *ether; + struct ipv4_hdr *ip; + unsigned char *payload; + + 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; + /* set len to 46 bytes 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 = flow->dst_ip; + ip->dst_addr = flow->src_ip; + (void)rte_memcpy(payload, + flow->flexwords, + BYTES_PER_WORD * flow->num_flexwords); +} + +static inline void +rte_i40e_fdir_construct_udp4_input(struct ipv4_udp_flow *flow, + unsigned char *raw_pkt) +{ + struct ether_hdr *ether; + struct ipv4_hdr *ip; + struct udp_hdr *udp; + unsigned char *payload; + + 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 = flow->dst_ip; + ip->dst_addr = flow->src_ip; + ip->next_proto_id = IPPROTO_UDP; + udp->src_port = flow->dst_port; + udp->dst_port = flow->src_port; + udp->dgram_len = rte_cpu_to_be_16(I40E_FDIR_UDP_DEFAULT_LEN); + (void)rte_memcpy(payload, + flow->flexwords, + BYTES_PER_WORD * flow->num_flexwords); +} + +static inline void +rte_i40e_fdir_construct_tcp4_input(struct ipv4_tcp_flow *flow, + unsigned char *raw_pkt) +{ + struct ether_hdr *ether; + struct ipv4_hdr *ip; + struct tcp_hdr *tcp; + unsigned char *payload; + + 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; + /* set len 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 = flow->dst_ip; + ip->dst_addr = flow->src_ip; + ip->next_proto_id = IPPROTO_TCP; + tcp->src_port = flow->dst_port; + tcp->dst_port = flow->src_port; + tcp->data_off = I40E_FDIR_TCP_DEFAULT_DATAOFF; + (void)rte_memcpy(payload, + flow->flexwords, + BYTES_PER_WORD * flow->num_flexwords); +} + +static inline void +rte_i40e_fdir_construct_ip6_input(struct ipv6_other_flow *flow, + unsigned char *raw_pkt) +{ + struct ether_hdr *ether; + struct ipv6_hdr *ip; + unsigned char *payload; + + ether = (struct ether_hdr *)raw_pkt; + ip = (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); + ip->vtc_flow = rte_cpu_to_be_32(I40E_FDIR_IPv6_DEFAULT_VTC_FLOW); + ip->payload_len = rte_cpu_to_be_16(I40E_FDIR_IPv6_DEFAULT_PAYLOAD_LEN); + ip->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(&(ip->src_addr), &(flow->dst_ip), IPV6_ADDR_LEN); + rte_memcpy(&(ip->dst_addr), &(flow->src_ip), IPV6_ADDR_LEN); + (void)rte_memcpy(payload, + flow->flexwords, + BYTES_PER_WORD * flow->num_flexwords); +} + +static inline void +rte_i40e_fdir_construct_udp6_input(struct ipv6_udp_flow *flow, + unsigned char *raw_pkt) +{ + struct ether_hdr *ether; + struct ipv6_hdr *ip; + struct udp_hdr *udp; + unsigned char *payload; + + ether = (struct ether_hdr *)raw_pkt; + ip = (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); + ip->vtc_flow = rte_cpu_to_be_32(I40E_FDIR_IPv6_DEFAULT_VTC_FLOW); + ip->payload_len = rte_cpu_to_be_16(I40E_FDIR_IPv6_DEFAULT_PAYLOAD_LEN); + ip->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(&(ip->src_addr), &(flow->dst_ip), IPV6_ADDR_LEN); + rte_memcpy(&(ip->dst_addr), &(flow->src_ip), IPV6_ADDR_LEN); + ip->proto = IPPROTO_UDP; + udp->src_port = flow->dst_port; + udp->dst_port = flow->src_port; + udp->dgram_len = rte_cpu_to_be_16(I40E_FDIR_UDP_DEFAULT_LEN); + (void)rte_memcpy(payload, + flow->flexwords, + BYTES_PER_WORD * flow->num_flexwords); +} + +static inline void +rte_i40e_fdir_construct_tcp6_input(struct ipv6_tcp_flow *flow, + unsigned char *raw_pkt) +{ + struct ether_hdr *ether; + struct ipv6_hdr *ip; + struct tcp_hdr *tcp; + unsigned char *payload; + + ether = (struct ether_hdr *)raw_pkt; + ip = (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); + ip->vtc_flow = rte_cpu_to_be_32(I40E_FDIR_IPv6_DEFAULT_VTC_FLOW); + ip->payload_len = rte_cpu_to_be_16(I40E_FDIR_IPv6_DEFAULT_PAYLOAD_LEN); + ip->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(&(ip->src_addr), &(flow->dst_ip), IPV6_ADDR_LEN); + rte_memcpy(&(ip->dst_addr), &(flow->src_ip), IPV6_ADDR_LEN); + ip->proto = IPPROTO_TCP; + tcp->data_off = I40E_FDIR_TCP_DEFAULT_DATAOFF; + tcp->src_port = flow->dst_port; + tcp->dst_port = flow->src_port; + (void)rte_memcpy(payload, + flow->flexwords, + BYTES_PER_WORD * flow->num_flexwords); +} + +static void +cmd_i40e_flow_director_parsed(void *parsed_result, + __attribute__((unused)) struct cmdline *cl, + __attribute__((unused)) void *data) +{ + struct cmd_i40e_flow_director_result *res = parsed_result; + struct rte_port *port; + struct rte_i40e_fdir_entry entry; + struct rte_mbuf *m_pkt = NULL; + uint16_t flexwords[8]; + enum rte_eth_command cmd; + int num_flexwords; + int ret = 0; + + memset(flexwords, 0, sizeof(flexwords)); + memset(&entry, 0, sizeof(struct rte_i40e_fdir_entry)); + num_flexwords = parse_flexwords(res->flexwords_value, flexwords); + if (num_flexwords < 0) { + printf("error: Cannot pase flexwords input.\n"); + return; + } + port = &ports[res->port_id]; + m_pkt = tx_mbuf_alloc(port->i40e_fdir_mp); + if (m_pkt == NULL) { + printf("error: Cannot malloc mbuf for fdir.\n"); + return; + } + + if (!strcmp(res->flow_type, "ip4")) { + struct ipv4_other_flow ip4_flow; + memset(&ip4_flow, 0, sizeof(struct ipv4_other_flow)); + /* no need to convert, already big endian. */ + if (res->ip_dst.family == AF_INET) + ip4_flow.dst_ip = res->ip_dst.addr.ipv4.s_addr; + else { + printf("error paramters.\n"); + goto pktbuf_free; + } + if (res->ip_src.family == AF_INET) + ip4_flow.src_ip = res->ip_src.addr.ipv4.s_addr; + else { + printf("error paramters.\n"); + goto pktbuf_free; + } + ip4_flow.num_flexwords = num_flexwords; + rte_memcpy(ip4_flow.flexwords, + flexwords, + num_flexwords); + rte_i40e_fdir_construct_ip4_input(&ip4_flow, m_pkt->pkt.data); + entry.input.pctype = ETH_PCTYPE_NONF_IPV4_OTHER; + } else if (!strcmp(res->flow_type, "udp4")) { + struct ipv4_udp_flow udp4_flow; + memset(&udp4_flow, 0, sizeof(struct ipv4_udp_flow)); + /* no need to convert, already big endian. */ + if (res->ip_dst.family == AF_INET) + udp4_flow.dst_ip = res->ip_dst.addr.ipv4.s_addr; + else { + printf("error paramters.\n"); + goto pktbuf_free; + } + if (res->ip_src.family == AF_INET) + udp4_flow.src_ip = res->ip_src.addr.ipv4.s_addr; + else { + printf("error paramters.\n"); + goto pktbuf_free; + } + /* need convert to big endian. */ + udp4_flow.dst_port = rte_cpu_to_be_16(res->port_dst); + udp4_flow.src_port = rte_cpu_to_be_16(res->port_src); + udp4_flow.num_flexwords = num_flexwords; + rte_memcpy(udp4_flow.flexwords, + flexwords, + udp4_flow.num_flexwords); + rte_i40e_fdir_construct_udp4_input(&udp4_flow, m_pkt->pkt.data); + entry.input.pctype = ETH_PCTYPE_NONF_IPV4_UDP; + } else if (!strcmp(res->flow_type, "tcp4")) { + struct ipv4_tcp_flow tcp4_flow; + memset(&tcp4_flow, 0, sizeof(struct ipv4_tcp_flow)); + if (res->ip_dst.family == AF_INET) + tcp4_flow.dst_ip = res->ip_dst.addr.ipv4.s_addr; + else { + printf("error paramters.\n"); + goto pktbuf_free; + } + if (res->ip_src.family == AF_INET) + tcp4_flow.src_ip = res->ip_src.addr.ipv4.s_addr; + else { + printf("error paramters.\n"); + goto pktbuf_free; + } + /* need convert to big endian. */ + tcp4_flow.dst_port = rte_cpu_to_be_16(res->port_dst); + tcp4_flow.src_port = rte_cpu_to_be_16(res->port_src); + tcp4_flow.num_flexwords = num_flexwords; + rte_memcpy(tcp4_flow.flexwords, + flexwords, + tcp4_flow.num_flexwords); + rte_i40e_fdir_construct_tcp4_input(&tcp4_flow, m_pkt->pkt.data); + entry.input.pctype = ETH_PCTYPE_NONF_IPV4_TCP; + } else if (!strcmp(res->flow_type, "ip6")) { + struct ipv6_other_flow ip6_flow; + memset(&ip6_flow, 0, sizeof(struct ipv6_other_flow)); + if (res->ip_src.family == AF_INET6) + (void)rte_memcpy(&(ip6_flow.src_ip), + &(res->ip_src.addr.ipv6), + sizeof(struct in6_addr)); + else { + printf("error paramters.\n"); + goto pktbuf_free; + } + if (res->ip_dst.family == AF_INET6) + (void)rte_memcpy(&(ip6_flow.dst_ip), + &(res->ip_dst.addr.ipv6), + sizeof(struct in6_addr)); + else { + printf("error paramters.\n"); + goto pktbuf_free; + } + ip6_flow.num_flexwords = num_flexwords; + rte_memcpy(ip6_flow.flexwords, + flexwords, + ip6_flow.num_flexwords); + rte_i40e_fdir_construct_ip6_input(&ip6_flow, m_pkt->pkt.data); + entry.input.pctype = ETH_PCTYPE_NONF_IPV6_OTHER; + } else if (!strcmp(res->flow_type, "udp6")) { + struct ipv6_udp_flow udp6_flow; + memset(&udp6_flow, 0, sizeof(struct ipv6_udp_flow)); + if (res->ip_src.family == AF_INET6) + (void)rte_memcpy(&(udp6_flow.src_ip), + &(res->ip_src.addr.ipv6), + sizeof(struct in6_addr)); + else { + printf("error paramters.\n"); + goto pktbuf_free; + } + if (res->ip_dst.family == AF_INET6) + (void)rte_memcpy(&(udp6_flow.dst_ip), + &(res->ip_dst.addr.ipv6), + sizeof(struct in6_addr)); + else { + printf("error paramters.\n"); + goto pktbuf_free; + } + udp6_flow.dst_port = rte_cpu_to_be_16(res->port_dst); + udp6_flow.src_port = rte_cpu_to_be_16(res->port_src); + udp6_flow.num_flexwords = num_flexwords; + rte_memcpy(udp6_flow.flexwords, + flexwords, + udp6_flow.num_flexwords); + rte_i40e_fdir_construct_udp6_input(&udp6_flow, m_pkt->pkt.data); + entry.input.pctype = ETH_PCTYPE_NONF_IPV6_UDP; + } else if (!strcmp(res->flow_type, "tcp6")) { + struct ipv6_tcp_flow tcp6_flow; + memset(&tcp6_flow, 0, sizeof(struct ipv6_tcp_flow)); + if (res->ip_src.family == AF_INET6) + (void)rte_memcpy(&(tcp6_flow.src_ip), + &(res->ip_src.addr.ipv6), + sizeof(struct in6_addr)); + else { + printf("error paramters.\n"); + goto pktbuf_free; + } + if (res->ip_dst.family == AF_INET6) + (void)rte_memcpy(&(tcp6_flow.dst_ip), + &(res->ip_dst.addr.ipv6), + sizeof(struct in6_addr)); + else { + printf("error paramters.\n"); + goto pktbuf_free; + } + tcp6_flow.dst_port = rte_cpu_to_be_16(res->port_dst); + tcp6_flow.src_port = rte_cpu_to_be_16(res->port_src); + tcp6_flow.num_flexwords = num_flexwords; + rte_memcpy(tcp6_flow.flexwords, + flexwords, + tcp6_flow.num_flexwords); + rte_i40e_fdir_construct_tcp6_input(&tcp6_flow, m_pkt->pkt.data); + entry.input.pctype = ETH_PCTYPE_NONF_IPV6_TCP; + } + m_pkt->pkt.data_len = I40E_FDIR_PKT_LEN; + m_pkt->pkt.next = NULL; + + entry.input.data = m_pkt; + entry.input.dest_vsi = 0; /* if set to 0, will use main vsi by default*/ + entry.input.flex_off = 0; /*use 0 by default*/ + if (!strcmp(res->drop, "drop")) + entry.action.drop = RTE_I40E_DEST_DROP_PACKET; + else + entry.action.drop = RTE_I40E_DEST_DIRECT_PACKET_QINDEX; + /* set to report FD ID by default temporary*/ + entry.action.report_status = RTE_I40E_FDIR_REPORT_FD_ID; + entry.action.rx_queue = res->queue_id; + /* use 0 by default, will set it to fdir counter per dev */ + entry.action.cnt_index = 0; + entry.soft_id = res->fd_id_value; + if (!strcmp(res->ops, "add")) + cmd = RTE_CMD_FDIR_RULE_ADD; + else + cmd = RTE_CMD_FDIR_RULE_DEL; + ret = rte_eth_dev_rx_classification_filter_ctl(res->port_id, cmd, &entry); + if (ret < 0) + printf("i40e flow director programming error," + " return code = %d \n", ret); +pktbuf_free: + rte_pktmbuf_free(entry.input.data); +} + +cmdline_parse_token_string_t cmd_i40e_flow_director_filter = + TOKEN_STRING_INITIALIZER(struct cmd_i40e_flow_director_result, + flow_director_filter, "i40e_flow_director_filter"); +cmdline_parse_token_num_t cmd_i40e_flow_director_port_id = + TOKEN_NUM_INITIALIZER(struct cmd_i40e_flow_director_result, + port_id, UINT8); +cmdline_parse_token_string_t cmd_i40e_flow_director_ops = + TOKEN_STRING_INITIALIZER(struct cmd_i40e_flow_director_result, + ops, "add#del"); +cmdline_parse_token_string_t cmd_i40e_flow_director_flow = + TOKEN_STRING_INITIALIZER(struct cmd_i40e_flow_director_result, + flow, "flow"); +cmdline_parse_token_string_t cmd_i40e_flow_director_flow_type = + TOKEN_STRING_INITIALIZER(struct cmd_i40e_flow_director_result, + flow_type, "ip4#tcp4#udp4#ip6#tcp6#udp6"); +cmdline_parse_token_string_t cmd_i40e_flow_director_src = + TOKEN_STRING_INITIALIZER(struct cmd_i40e_flow_director_result, + src, "src"); +cmdline_parse_token_ipaddr_t cmd_i40e_flow_director_ip_src = + TOKEN_IPADDR_INITIALIZER(struct cmd_i40e_flow_director_result, + ip_src); +cmdline_parse_token_num_t cmd_i40e_flow_director_port_src = + TOKEN_NUM_INITIALIZER(struct cmd_i40e_flow_director_result, + port_src, UINT16); +cmdline_parse_token_string_t cmd_i40e_flow_director_dst = + TOKEN_STRING_INITIALIZER(struct cmd_i40e_flow_director_result, + dst, "dst"); +cmdline_parse_token_ipaddr_t cmd_i40e_flow_director_ip_dst = + TOKEN_IPADDR_INITIALIZER(struct cmd_i40e_flow_director_result, + ip_dst); +cmdline_parse_token_num_t cmd_i40e_flow_director_port_dst = + TOKEN_NUM_INITIALIZER(struct cmd_i40e_flow_director_result, + port_dst, UINT16); +cmdline_parse_token_string_t cmd_i40e_flow_director_flexwords = + TOKEN_STRING_INITIALIZER(struct cmd_i40e_flow_director_result, + flexwords, "flexwords"); +cmdline_parse_token_string_t cmd_i40e_flow_director_flexwords_value = + TOKEN_STRING_INITIALIZER(struct cmd_i40e_flow_director_result, + flexwords_value, NULL); +cmdline_parse_token_string_t cmd_i40e_flow_director_drop = + TOKEN_STRING_INITIALIZER(struct cmd_i40e_flow_director_result, + drop, "drop#fwd"); +cmdline_parse_token_string_t cmd_i40e_flow_director_queue = + TOKEN_STRING_INITIALIZER(struct cmd_i40e_flow_director_result, + queue, "queue"); +cmdline_parse_token_num_t cmd_i40e_flow_director_queue_id = + TOKEN_NUM_INITIALIZER(struct cmd_i40e_flow_director_result, + queue_id, UINT16); +cmdline_parse_token_string_t cmd_i40e_flow_director_fd_id = + TOKEN_STRING_INITIALIZER(struct cmd_i40e_flow_director_result, + fd_id, "fd_id"); +cmdline_parse_token_num_t cmd_i40e_flow_director_fd_id_value = + TOKEN_NUM_INITIALIZER(struct cmd_i40e_flow_director_result, + fd_id_value, UINT32); + +cmdline_parse_inst_t cmd_i40e_add_del_ip_flow_director = { + .f = cmd_i40e_flow_director_parsed, + .data = NULL, + .help_str = "add or delete a ip flow director entry on i40e NIC", + .tokens = { + (void *)&cmd_i40e_flow_director_filter, + (void *)&cmd_i40e_flow_director_port_id, + (void *)&cmd_i40e_flow_director_ops, + (void *)&cmd_i40e_flow_director_flow, + (void *)&cmd_i40e_flow_director_flow_type, + (void *)&cmd_i40e_flow_director_src, + (void *)&cmd_i40e_flow_director_ip_src, + (void *)&cmd_i40e_flow_director_dst, + (void *)&cmd_i40e_flow_director_ip_dst, + (void *)&cmd_i40e_flow_director_flexwords, + (void *)&cmd_i40e_flow_director_flexwords_value, + (void *)&cmd_i40e_flow_director_drop, + (void *)&cmd_i40e_flow_director_queue, + (void *)&cmd_i40e_flow_director_queue_id, + (void *)&cmd_i40e_flow_director_fd_id, + (void *)&cmd_i40e_flow_director_fd_id_value, + NULL, + }, +}; + +cmdline_parse_inst_t cmd_i40e_add_del_udp_flow_director = { + .f = cmd_i40e_flow_director_parsed, + .data = NULL, + .help_str = "add or delete a udp/tcp flow director entry on i40e NIC", + .tokens = { + (void *)&cmd_i40e_flow_director_filter, + (void *)&cmd_i40e_flow_director_port_id, + (void *)&cmd_i40e_flow_director_ops, + (void *)&cmd_i40e_flow_director_flow, + (void *)&cmd_i40e_flow_director_flow_type, + (void *)&cmd_i40e_flow_director_src, + (void *)&cmd_i40e_flow_director_ip_src, + (void *)&cmd_i40e_flow_director_port_src, + (void *)&cmd_i40e_flow_director_dst, + (void *)&cmd_i40e_flow_director_ip_dst, + (void *)&cmd_i40e_flow_director_port_dst, + (void *)&cmd_i40e_flow_director_flexwords, + (void *)&cmd_i40e_flow_director_flexwords_value, + (void *)&cmd_i40e_flow_director_drop, + (void *)&cmd_i40e_flow_director_queue, + (void *)&cmd_i40e_flow_director_queue_id, + (void *)&cmd_i40e_flow_director_fd_id, + (void *)&cmd_i40e_flow_director_fd_id_value, + NULL, + }, +}; + +struct cmd_i40e_flush_flow_director_result { + cmdline_fixed_string_t flush_flow_director; + uint8_t port_id; +}; + +cmdline_parse_token_string_t cmd_i40e_flush_flow_director_flush = + TOKEN_STRING_INITIALIZER(struct cmd_i40e_flush_flow_director_result, + flush_flow_director, "i40e_flush_flow_director"); +cmdline_parse_token_num_t cmd_i40e_flush_flow_director_port_id = + TOKEN_NUM_INITIALIZER(struct cmd_i40e_flush_flow_director_result, + port_id, UINT8); + +static void +cmd_i40e_flush_flow_director_parsed(void *parsed_result, + __attribute__((unused)) struct cmdline *cl, + __attribute__((unused)) void *data) +{ + struct cmd_i40e_flow_director_result *res = parsed_result; + int ret = 0; + + ret = rte_eth_dev_rx_classification_filter_ctl(res->port_id, + RTE_CMD_FDIR_FLUSH, NULL); + if (ret < 0) + printf("i40e flow director table flushing error," + " return code = %d \n", ret); +} + +cmdline_parse_inst_t cmd_i40e_flush_flow_director = { + .f = cmd_i40e_flush_flow_director_parsed, + .data = NULL, + .help_str = "flush all flow director entries of a device on i40e NIC", + .tokens = { + (void *)&cmd_i40e_flush_flow_director_flush, + (void *)&cmd_i40e_flush_flow_director_port_id, + NULL, + }, +}; +#endif /* RTE_LIBRTE_I40E_PMD */ + /* ******************************************************************************** */ /* list of instructions */ @@ -7429,6 +8089,11 @@ cmdline_parse_ctx_t main_ctx[] = { (cmdline_parse_inst_t *)&cmd_add_flex_filter, (cmdline_parse_inst_t *)&cmd_remove_flex_filter, (cmdline_parse_inst_t *)&cmd_get_flex_filter, +#ifdef RTE_LIBRTE_I40E_PMD + (cmdline_parse_inst_t *)&cmd_i40e_add_del_ip_flow_director, + (cmdline_parse_inst_t *)&cmd_i40e_add_del_udp_flow_director, + (cmdline_parse_inst_t *)&cmd_i40e_flush_flow_director, +#endif /* RTE_LIBRTE_I40E_PMD */ NULL, }; diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c index c72f6ee..4c40afe 100644 --- a/app/test-pmd/config.c +++ b/app/test-pmd/config.c @@ -93,6 +93,10 @@ #include #include #include +#include +#ifdef RTE_LIBRTE_I40E_PMD +#include +#endif /* RTE_LIBRTE_I40E_PMD */ #include "testpmd.h" @@ -1781,26 +1785,52 @@ fdir_remove_signature_filter(portid_t port_id, void fdir_get_infos(portid_t port_id) { - struct rte_eth_fdir fdir_infos; + struct rte_eth_dev_info dev_info; static const char *fdir_stats_border = "########################"; if (port_id_is_invalid(port_id)) return; - rte_eth_dev_fdir_get_infos(port_id, &fdir_infos); - printf("\n %s FDIR infos for port %-2d %s\n", fdir_stats_border, port_id, fdir_stats_border); - - printf(" collision: %-10"PRIu64" free: %"PRIu64"\n" - " maxhash: %-10"PRIu64" maxlen: %"PRIu64"\n" - " add: %-10"PRIu64" remove: %"PRIu64"\n" - " f_add: %-10"PRIu64" f_remove: %"PRIu64"\n", - (uint64_t)(fdir_infos.collision), (uint64_t)(fdir_infos.free), - (uint64_t)(fdir_infos.maxhash), (uint64_t)(fdir_infos.maxlen), - fdir_infos.add, fdir_infos.remove, - fdir_infos.f_add, fdir_infos.f_remove); + memset(&dev_info, 0, sizeof(dev_info)); + rte_eth_dev_info_get(port_id, &dev_info); +#ifdef RTE_LIBRTE_I40E_PMD + if (strstr(dev_info.driver_name, "i40e") != NULL) { + struct rte_i40e_fdir_info i40e_fdir_info; + memset(&i40e_fdir_info, 0, sizeof(struct rte_i40e_fdir_info)); + rte_eth_dev_rx_classification_filter_ctl(port_id, + RTE_CMD_FDIR_INFO_GET, (void *)&i40e_fdir_info); + if (i40e_fdir_info.mode) { + printf(" FDIR is enabled\n"); + printf(" guarant_space: %-10"PRIu16 + " best_space: %"PRIu16"\n", + i40e_fdir_info.guarant_spc, + i40e_fdir_info.best_spc); + printf(" guarant_count: %-10"PRIu16 + " best_count: %"PRIu16"\n", + i40e_fdir_info.guarant_cnt, + i40e_fdir_info.best_cnt); + } else + printf(" FDIR is disabled\n"); + } else { +#endif /* RTE_LIBRTE_I40E_PMD */ + struct rte_eth_fdir fdir_infos; + + rte_eth_dev_fdir_get_infos(port_id, &fdir_infos); + + printf(" collision: %-10"PRIu64" free: %"PRIu64"\n" + " maxhash: %-10"PRIu64" maxlen: %"PRIu64"\n" + " add: %-10"PRIu64" remove: %"PRIu64"\n" + " f_add: %-10"PRIu64" f_remove: %"PRIu64"\n", + (uint64_t)(fdir_infos.collision), (uint64_t)(fdir_infos.free), + (uint64_t)(fdir_infos.maxhash), (uint64_t)(fdir_infos.maxlen), + fdir_infos.add, fdir_infos.remove, + fdir_infos.f_add, fdir_infos.f_remove); +#ifdef RTE_LIBRTE_I40E_PMD + } +#endif /* RTE_LIBRTE_I40E_PMD */ printf(" %s############################%s\n", fdir_stats_border, fdir_stats_border); } diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c index e8a4b45..d0d4fc1 100644 --- a/app/test-pmd/testpmd.c +++ b/app/test-pmd/testpmd.c @@ -1676,6 +1676,28 @@ init_port_config(void) port = &ports[pid]; port->dev_conf.rxmode = rx_mode; port->dev_conf.fdir_conf = fdir_conf; +#ifdef RTE_LIBRTE_I40E_PMD +#define I40E_FDIR_NB_MBUF 4 +#define I40E_FDIR_MBUF_SIZE (512 + sizeof(struct rte_mbuf)) +#define I40E_FDIR_PKT_LEN 512 +#define MEMPOOL_CACHE_SIZE 256 +#define I40E_FDIR_MBUF_NAME "FDIR_MBUF_POOL" + + port->i40e_fdir_mp = rte_mempool_lookup(I40E_FDIR_MBUF_NAME); + if (port->i40e_fdir_mp == NULL) { + port->i40e_fdir_mp = rte_mempool_create(I40E_FDIR_MBUF_NAME, + I40E_FDIR_NB_MBUF, I40E_FDIR_MBUF_SIZE, + MEMPOOL_CACHE_SIZE, + sizeof(struct rte_pktmbuf_pool_private), + rte_pktmbuf_pool_init, NULL, + rte_pktmbuf_init, NULL, + 0, 0); + + if (port->i40e_fdir_mp == NULL) + printf("error: Cannot init mbuf pool for" + "i40e flow director.\n"); + } +#endif /* RTE_LIBRTE_I40E_PMD */ if (nb_rxq > 1) { port->dev_conf.rx_adv_conf.rss_conf.rss_key = NULL; port->dev_conf.rx_adv_conf.rss_conf.rss_hf = rss_hf; diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h index ac86bfe..1e6d16f 100644 --- a/app/test-pmd/testpmd.h +++ b/app/test-pmd/testpmd.h @@ -73,6 +73,9 @@ int main(int argc, char **argv); #define NUMA_NO_CONFIG 0xFF #define UMA_NO_CONFIG 0xFF +#define BYTES_PER_WORD 2 +#define IPV6_ADDR_LEN 16 + typedef uint8_t lcoreid_t; typedef uint8_t portid_t; typedef uint16_t queueid_t; @@ -155,6 +158,9 @@ struct rte_port { uint8_t dcb_flag; /**< enable dcb */ struct rte_eth_rxconf rx_conf; /**< rx configuration */ struct rte_eth_txconf tx_conf; /**< tx configuration */ +#ifdef RTE_LIBRTE_I40E_PMD + struct rte_mempool *i40e_fdir_mp; /**< mempool used for fdir programing */ +#endif /* RTE_LIBRTE_I40E_PMD */ }; /** @@ -352,6 +358,57 @@ extern uint32_t param_total_num_mbufs; extern struct rte_fdir_conf fdir_conf; +#ifdef RTE_LIBRTE_I40E_PMD +struct ipv4_udp_flow { + uint32_t src_ip; /**< IPv4 source address to match. */ + uint32_t dst_ip; /**< IPv4 destination address to match. */ + uint16_t src_port; /**< UDP Source port to match. */ + uint16_t dst_port; /**< UDP Destination port to match. */ + uint8_t num_flexwords; /**< number of the flexwords. */ + uint16_t flexwords[8]; /**< flexwords in payload. */ +}; + +struct ipv4_tcp_flow { + uint32_t src_ip; /**< IPv4 source address to match. */ + uint32_t dst_ip; /**< IPv4 destination address to match. */ + uint16_t src_port; /**< TCP Source port to match. */ + uint16_t dst_port; /**< TCP Destination port to match. */ + uint8_t num_flexwords; /**< number of the flexwords. */ + uint16_t flexwords[8]; /**< flexwords in payload. */ +}; + +struct ipv4_other_flow { + uint32_t src_ip; /**< IPv4 source address to match. */ + uint32_t dst_ip; /**< IPv4 destination address to match. */ + uint8_t num_flexwords; /**< number of the flexwords. */ + uint16_t flexwords[8]; /**< flexwords in payload. */ +}; + +struct ipv6_udp_flow { + uint32_t src_ip[4]; /**< IPv6 source address to match. */ + uint32_t dst_ip[4]; /**< IPv6 destination address to match. */ + uint16_t src_port; /**< UDP Source port to match. */ + uint16_t dst_port; /**< UDP Destination port to match. */ + uint8_t num_flexwords; /**< number of the flexwords. */ + uint16_t flexwords[8]; /**< flexwords in payload. */ +}; + +struct ipv6_tcp_flow { + uint32_t src_ip[4]; /**< IPv6 source address to match. */ + uint32_t dst_ip[4]; /**< IPv6 destination address to match. */ + uint16_t src_port; /**< TCP Source port to match. */ + uint16_t dst_port; /**< TCP Destination port to match. */ + uint8_t num_flexwords; /**< number of the flexwords. */ + uint16_t flexwords[8]; /**< flexwords in payload. */ +}; + +struct ipv6_other_flow { + uint32_t src_ip[4]; /**< IPv6 source address to match. */ + uint32_t dst_ip[4]; /**< IPv6 destination address to match. */ + uint8_t num_flexwords; /**< number of the flexwords. */ + uint16_t flexwords[8]; /**< flexwords in payload. */ +}; +#endif /* RTE_LIBRTE_I40E_PMD */ /* * Configuration of packet segments used by the "txonly" processing engine. */