From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by dpdk.org (Postfix) with ESMTP id 29E03B106 for ; Sat, 17 May 2014 11:35:28 +0200 (CEST) Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga101.jf.intel.com with ESMTP; 17 May 2014 02:35:23 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.98,1071,1392192000"; d="scan'208";a="541997940" Received: from shilc102.sh.intel.com ([10.239.39.44]) by orsmga002.jf.intel.com with ESMTP; 17 May 2014 02:35:21 -0700 Received: from shecgisg004.sh.intel.com (shecgisg004.sh.intel.com [10.239.29.89]) by shilc102.sh.intel.com (8.13.6/8.13.6/SuSE Linux 0.8) with ESMTP id s4H9ZGQ1006478; Sat, 17 May 2014 17:35:18 +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 s4H9ZEeh025342; Sat, 17 May 2014 17:35:16 +0800 Received: (from wujingji@localhost) by shecgisg004.sh.intel.com (8.13.6/8.13.6/Submit) id s4H9ZDfu025338; Sat, 17 May 2014 17:35:13 +0800 From: Jingjing Wu To: dev@dpdk.org Date: Sat, 17 May 2014 17:35:09 +0800 Message-Id: <1400319309-25231-1-git-send-email-jingjing.wu@intel.com> X-Mailer: git-send-email 1.7.0.7 Subject: [dpdk-dev] [PATCH][PMD][GENERIC_FILTER] add NIC filters support for generic filter feature 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: Sat, 17 May 2014 09:35:32 -0000 A generic filter mechanism for handling special packet is required. It will allows filters to be set in HW when available for so that specific packets may be filtered by NICs to specific desriptor queues for processing. Currently only the Flow Director for Intel's 10GbE 82599 devices is available. Other types of filter are not supported. This pacth adds following NIC filters used to assign different packets to certain receive queues. ethertype filter/syn filter/2tuple filter/flex filter for E1000(82580, i350) ethertype filter/syn filter/5tuple filter for 10G(82599) Signed-off-by: jingjing.wu --- app/test-pmd/cmdline.c | 905 +++++++++++++++++++++++++++++++++++- app/test-pmd/config.c | 143 ++++++ app/test-pmd/testpmd.h | 6 + lib/librte_ether/rte_ethdev.c | 300 ++++++++++++ lib/librte_ether/rte_ethdev.h | 429 ++++++++++++++++- lib/librte_pmd_e1000/e1000_ethdev.h | 38 ++ lib/librte_pmd_e1000/igb_ethdev.c | 512 ++++++++++++++++++++ lib/librte_pmd_ixgbe/ixgbe_ethdev.c | 365 +++++++++++++++ lib/librte_pmd_ixgbe/ixgbe_ethdev.h | 33 ++ 9 files changed, 2729 insertions(+), 2 deletions(-) diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c index 7becedc..32787ae 100644 --- a/app/test-pmd/cmdline.c +++ b/app/test-pmd/cmdline.c @@ -113,6 +113,7 @@ static void cmd_help_brief_parsed(__attribute__((unused)) void *parsed_result, " help ports : Configuring ports.\n" " help flowdir : Flow Director filter help.\n" " help registers : Reading and setting port registers.\n" + " help filters : Filters configuration help.\n" " help all : All of the above sections.\n\n" ); @@ -550,6 +551,68 @@ static void cmd_help_long_parsed(void *parsed_result, " Set single bit value of a port register.\n\n" ); } + if (show_all || !strcmp(res->section, "filters")) { + + cmdline_printf( + cl, + "\n" + "filters:\n" + "----------\n\n" + + "add_ethertype_filter (port_id) ethertype (eth_value)" + " priority (enable|disable)(pri_value) queue (queue_id) index (idx) \n" + " add an ethertype filter.\n\n" + + "remove_ethertype_filter (port_id) index (idx)\n" + " remove an ethertype filter.\n\n" + + "get_ethertype_filter (port_id) index (idx)\n" + " get info of a ethertype filter.\n\n" + + "add_2tuple_filter (port_id) protocol (pro_value) (pro_mask)" + " dst_port (port_value) (port_mask) flags (flg_value) priority (prio_value)" + " queue (queue_id) index (idx)\n" + " add a 2tuple filter.\n\n" + + "remove_2tuple_filter (port_id) index (idx)\n" + " remove a 2tuple filter.\n\n" + + "get_2tuple_filter (port_id) index (idx)\n" + " get info of a 2tuple filter.\n\n" + + "add_5tuple_filter (port_id) dst_ip (dst_address) src_ip (src_address)" + " dst_port (dst_port_value) src_port (src_port_value) protocol (tcp|udp|sctp|none)" + " mask (mask_value) priority (prio_value) queue (queue_id) index (idx) \n" + " add a 5tuple filter.\n\n" + + "remove_5tuple_filter (port_id) index (idx)\n" + " remove a 5tuple filter.\n\n" + + "get_5tuple_filter (port_id) index (idx)\n" + " get info of a 5tuple filter.\n\n" + + "add_syn_filter (port_id) priority (high|low) queue (queue_id)" + " add syn filter.\n\n" + + "remove_syn_filter (port_id)" + " remove syn filter.\n\n" + + "get_syn_filter (port_id) " + " get syn filter info.\n\n" + + "add_felx_filter (port_id) len (len_value) bytes (bytes_string) mask (mask_value)" + " priority (prio_value) queue (queue_id) index (idx) \n" + " add a flex filter.\n\n" + + "remove_flex_filter (port_id) index (idx)\n" + " remove a flex filter.\n\n" + + "get_flex_filter (port_id) index (idx)\n" + " get info of a flex filter.\n\n" + + ); + + } } cmdline_parse_token_string_t cmd_help_long_help = @@ -558,7 +621,7 @@ cmdline_parse_token_string_t cmd_help_long_help = cmdline_parse_token_string_t cmd_help_long_section = TOKEN_STRING_INITIALIZER(struct cmd_help_long_result, section, "all#control#display#config#flowdir#" - "ports#registers"); + "ports#registers#filters"); cmdline_parse_inst_t cmd_help_long = { .f = cmd_help_long_parsed, @@ -5107,6 +5170,831 @@ cmdline_parse_inst_t cmd_dump_one = { }, }; +/* *** ADD/REMOVE an ethertype FILTER *** */ +struct cmd_ethertype_filter_result { + cmdline_fixed_string_t filter; + uint8_t port_id; + cmdline_fixed_string_t ethertype; + uint16_t ethertype_value; + cmdline_fixed_string_t priority; + cmdline_fixed_string_t priority_en; + uint8_t priority_value; + cmdline_fixed_string_t queue; + uint8_t queue_id; + cmdline_fixed_string_t index; + uint16_t index_value; +}; + +static void +cmd_ethertype_filter_parsed(void *parsed_result, + __attribute__((unused)) struct cmdline *cl, + __attribute__((unused)) void *data) +{ + int ret = 0; + struct cmd_ethertype_filter_result *res = parsed_result; + struct rte_ethertype_filter filter; + + + memset(&filter, 0, sizeof(struct rte_ethertype_filter)); + filter.ethertype = rte_cpu_to_le_16(res->ethertype_value); + filter.priority = res->priority_value; + + if (!strcmp(res->priority_en, "enable")) + filter.priority_en = 1; + if (!strcmp(res->filter, "add_ethertype_filter")) + ret = rte_eth_dev_add_ethertype_filter(res->port_id, res->index_value, + &filter, res->queue_id); + else if (!strcmp(res->filter, "remove_ethertype_filter")) + ret = rte_eth_dev_remove_ethertype_filter(res->port_id, res->index_value); + else if (!strcmp(res->filter, "get_ethertype_filter")) + get_ethertype_filter(res->port_id, res->index_value); + + if (ret < 0) + printf("ethertype filter setting error: (%s)\n", strerror(-ret)); +} + +cmdline_parse_token_num_t cmd_ethertype_filter_port_id = + TOKEN_NUM_INITIALIZER(struct cmd_ethertype_filter_result, + port_id, UINT8); +cmdline_parse_token_string_t cmd_ethertype_filter_ethertype = + TOKEN_STRING_INITIALIZER(struct cmd_ethertype_filter_result, + ethertype, "ethertype"); +cmdline_parse_token_ipaddr_t cmd_ethertype_filter_ethertype_value = + TOKEN_NUM_INITIALIZER(struct cmd_ethertype_filter_result, + ethertype_value, UINT16); +cmdline_parse_token_string_t cmd_ethertype_filter_priority = + TOKEN_STRING_INITIALIZER(struct cmd_ethertype_filter_result, + priority, "priority"); +cmdline_parse_token_string_t cmd_ethertype_filter_priority_en = + TOKEN_STRING_INITIALIZER(struct cmd_ethertype_filter_result, + priority_en, "enable#disable"); +cmdline_parse_token_num_t cmd_ethertype_filter_priority_value = + TOKEN_NUM_INITIALIZER(struct cmd_ethertype_filter_result, + priority_value, UINT8); +cmdline_parse_token_string_t cmd_ethertype_filter_queue = + TOKEN_STRING_INITIALIZER(struct cmd_ethertype_filter_result, + queue, "queue"); +cmdline_parse_token_num_t cmd_ethertype_filter_queue_id = + TOKEN_NUM_INITIALIZER(struct cmd_ethertype_filter_result, + queue_id, UINT8); +cmdline_parse_token_string_t cmd_ethertype_filter_index = + TOKEN_STRING_INITIALIZER(struct cmd_ethertype_filter_result, + index, "index"); +cmdline_parse_token_num_t cmd_ethertype_filter_index_value = + TOKEN_NUM_INITIALIZER(struct cmd_ethertype_filter_result, + index_value, UINT16); +cmdline_parse_token_string_t cmd_ethertype_filter_add_filter = + TOKEN_STRING_INITIALIZER(struct cmd_ethertype_filter_result, + filter, "add_ethertype_filter"); +cmdline_parse_inst_t cmd_add_ethertype_filter = { + .f = cmd_ethertype_filter_parsed, + .data = NULL, + .help_str = "add an ethertype filter", + .tokens = { + (void *)&cmd_ethertype_filter_add_filter, + (void *)&cmd_ethertype_filter_port_id, + (void *)&cmd_ethertype_filter_ethertype, + (void *)&cmd_ethertype_filter_ethertype_value, + (void *)&cmd_ethertype_filter_priority, + (void *)&cmd_ethertype_filter_priority_en, + (void *)&cmd_ethertype_filter_priority_value, + (void *)&cmd_ethertype_filter_queue, + (void *)&cmd_ethertype_filter_queue_id, + (void *)&cmd_ethertype_filter_index, + (void *)&cmd_ethertype_filter_index_value, + NULL, + }, +}; + +cmdline_parse_token_string_t cmd_ethertype_filter_remove_filter = + TOKEN_STRING_INITIALIZER(struct cmd_ethertype_filter_result, + filter, "remove_ethertype_filter"); +cmdline_parse_inst_t cmd_remove_ethertype_filter = { + .f = cmd_ethertype_filter_parsed, + .data = NULL, + .help_str = "remove an ethertype filter", + .tokens = { + (void *)&cmd_ethertype_filter_remove_filter, + (void *)&cmd_ethertype_filter_port_id, + (void *)&cmd_ethertype_filter_index, + (void *)&cmd_ethertype_filter_index_value, + NULL, + }, +}; +cmdline_parse_token_string_t cmd_ethertype_filter_get_filter = + TOKEN_STRING_INITIALIZER(struct cmd_ethertype_filter_result, + filter, "get_ethertype_filter"); +cmdline_parse_inst_t cmd_get_ethertype_filter = { + .f = cmd_ethertype_filter_parsed, + .data = NULL, + .help_str = "get an ethertype filter", + .tokens = { + (void *)&cmd_ethertype_filter_get_filter, + (void *)&cmd_ethertype_filter_port_id, + (void *)&cmd_ethertype_filter_index, + (void *)&cmd_ethertype_filter_index_value, + NULL, + }, +}; + +/* *** set SYN filter *** */ +struct cmd_set_syn_filter_result { + cmdline_fixed_string_t filter; + uint8_t port_id; + cmdline_fixed_string_t priority; + cmdline_fixed_string_t high; + cmdline_fixed_string_t queue; + uint8_t queue_id; +}; + +static void +cmd_set_syn_filter_parsed(void *parsed_result, + __attribute__((unused)) struct cmdline *cl, + __attribute__((unused)) void *data) +{ + int ret = 0; + struct cmd_set_syn_filter_result *res = parsed_result; + if (!strcmp(res->filter, "add_syn_filter")){ + if(!strcmp(res->high, "high")) + ret = rte_eth_dev_add_syn_filter(res->port_id, 1, res->queue_id); + else + ret = rte_eth_dev_add_syn_filter(res->port_id, 0, res->queue_id); + }else if(!strcmp(res->filter, "remove_syn_filter")) + ret = rte_eth_dev_remove_syn_filter(res->port_id); + else if(!strcmp(res->filter, "get_syn_filter")) + get_syn_filter(res->port_id); + if(ret < 0) + printf("syn filter setting error: (%s)\n", strerror(-ret)); + +} +cmdline_parse_token_string_t cmd_syn_filter_portid = + TOKEN_NUM_INITIALIZER(struct cmd_set_syn_filter_result, + port_id, UINT8); +cmdline_parse_token_string_t cmd_syn_filter_priority = + TOKEN_STRING_INITIALIZER(struct cmd_set_syn_filter_result, + priority, "priority"); +cmdline_parse_token_string_t cmd_syn_filter_high = + TOKEN_STRING_INITIALIZER(struct cmd_set_syn_filter_result, + high, "high#low"); +cmdline_parse_token_string_t cmd_syn_filter_queue = + TOKEN_STRING_INITIALIZER(struct cmd_set_syn_filter_result, + queue, "queue"); +cmdline_parse_token_num_t cmd_syn_filter_queue_id = + TOKEN_NUM_INITIALIZER(struct cmd_set_syn_filter_result, + queue_id, UINT8); +cmdline_parse_token_string_t cmd_syn_filter_add_filter = + TOKEN_STRING_INITIALIZER(struct cmd_set_syn_filter_result, + filter, "add_syn_filter"); +cmdline_parse_token_string_t cmd_syn_filter_remove_filter = + TOKEN_STRING_INITIALIZER(struct cmd_set_syn_filter_result, + filter, "remove_syn_filter"); +cmdline_parse_inst_t cmd_add_syn_filter = { + .f = cmd_set_syn_filter_parsed, + .data = NULL, + .help_str = "add syn filter", + .tokens = { + (void *)&cmd_syn_filter_add_filter, + (void *)&cmd_syn_filter_portid, + (void *)&cmd_syn_filter_priority, + (void *)&cmd_syn_filter_high, + (void *)&cmd_syn_filter_queue, + (void *)&cmd_syn_filter_queue_id, + NULL, + }, +}; +cmdline_parse_inst_t cmd_remove_syn_filter = { + .f = cmd_set_syn_filter_parsed, + .data = NULL, + .help_str = "remove syn filter", + .tokens = { + (void *)&cmd_syn_filter_remove_filter, + (void *)&cmd_syn_filter_portid, + NULL, + }, +}; + +cmdline_parse_token_string_t cmd_syn_filter_get_filter = + TOKEN_STRING_INITIALIZER(struct cmd_set_syn_filter_result, + filter, "get_syn_filter"); + +cmdline_parse_inst_t cmd_get_syn_filter = { + .f = cmd_set_syn_filter_parsed, + .data = NULL, + .help_str = "get syn filter", + .tokens = { + (void *)&cmd_syn_filter_get_filter, + (void *)&cmd_syn_filter_portid, + NULL, + }, +}; + +/* *** ADD/REMOVE A 2tuple FILTER *** */ +struct cmd_2tuple_filter_result { + cmdline_fixed_string_t filter; + uint8_t port_id; + cmdline_fixed_string_t protocol; + uint8_t protocol_value; + uint8_t protocol_mask; + cmdline_fixed_string_t dst_port; + uint16_t dst_port_value; + uint16_t dst_port_mask; + cmdline_fixed_string_t flags; + uint8_t flags_value; + cmdline_fixed_string_t priority; + uint8_t priority_value; + cmdline_fixed_string_t queue; + uint8_t queue_id; + cmdline_fixed_string_t index; + uint16_t index_value; +}; + +static void +cmd_2tuple_filter_parsed(void *parsed_result, + __attribute__((unused)) struct cmdline *cl, + __attribute__((unused)) void *data) +{ + int ret = 0; + struct rte_2tuple_filter filter; + struct cmd_2tuple_filter_result *res = parsed_result; + + memset(&filter, 0, sizeof(struct rte_2tuple_filter)); + + if (!strcmp(res->filter, "add_2tuple_filter")){ + /** need convert to big endian*/ + filter.dst_port = rte_cpu_to_be_16(res->dst_port_value); + filter.protocol = res->protocol_value; + filter.dst_port_mask = (res->dst_port_mask) ? 0 : 1; + filter.protocol_mask = (res->protocol_mask) ? 0 : 1; + filter.priority = res->priority_value; + filter.tcp_flags = res->flags_value; + + ret = rte_eth_dev_add_2tuple_filter(res->port_id, res->index_value, + &filter, res->queue_id); + } else if (!strcmp(res->filter, "remove_2tuple_filter")) + ret = rte_eth_dev_remove_2tuple_filter(res->port_id, res->index_value); + else if (!strcmp(res->filter, "get_2tuple_filter")) + get_2tuple_filter(res->port_id, res->index_value); + + if(ret < 0) + printf("2tuple filter setting error: (%s)\n", strerror(-ret)); +} + +cmdline_parse_token_num_t cmd_2tuple_filter_port_id = + TOKEN_NUM_INITIALIZER(struct cmd_2tuple_filter_result, + port_id, UINT8); +cmdline_parse_token_string_t cmd_2tuple_filter_protocol = + TOKEN_STRING_INITIALIZER(struct cmd_2tuple_filter_result, + protocol, "protocol"); +cmdline_parse_token_string_t cmd_2tuple_filter_protocol_value = + TOKEN_NUM_INITIALIZER(struct cmd_2tuple_filter_result, + protocol_value, UINT8); +cmdline_parse_token_num_t cmd_2tuple_filter_protocol_mask = + TOKEN_NUM_INITIALIZER(struct cmd_2tuple_filter_result, + protocol_mask, UINT8); +cmdline_parse_token_string_t cmd_2tuple_filter_dst_port = + TOKEN_STRING_INITIALIZER(struct cmd_2tuple_filter_result, + dst_port, "dst_port"); +cmdline_parse_token_num_t cmd_2tuple_filter_dst_port_value = + TOKEN_NUM_INITIALIZER(struct cmd_2tuple_filter_result, + dst_port_value, UINT16); +cmdline_parse_token_num_t cmd_2tuple_filter_dst_port_mask = + TOKEN_NUM_INITIALIZER(struct cmd_2tuple_filter_result, + dst_port_mask, UINT16); +cmdline_parse_token_string_t cmd_2tuple_filter_flags = + TOKEN_STRING_INITIALIZER(struct cmd_2tuple_filter_result, + flags, "flags"); +cmdline_parse_token_string_t cmd_2tuple_filter_flags_value = + TOKEN_NUM_INITIALIZER(struct cmd_2tuple_filter_result, + flags_value, UINT8); +cmdline_parse_token_string_t cmd_2tuple_filter_priority = + TOKEN_STRING_INITIALIZER(struct cmd_2tuple_filter_result, + priority, "priority"); +cmdline_parse_token_num_t cmd_2tuple_filter_priority_value = + TOKEN_NUM_INITIALIZER(struct cmd_2tuple_filter_result, + priority_value, UINT8); +cmdline_parse_token_string_t cmd_2tuple_filter_queue = + TOKEN_STRING_INITIALIZER(struct cmd_2tuple_filter_result, + queue, "queue"); +cmdline_parse_token_num_t cmd_2tuple_filter_queue_id = + TOKEN_NUM_INITIALIZER(struct cmd_2tuple_filter_result, + queue_id, UINT8); +cmdline_parse_token_string_t cmd_2tuple_filter_index = + TOKEN_STRING_INITIALIZER(struct cmd_2tuple_filter_result, + index, "index"); +cmdline_parse_token_num_t cmd_2tuple_filter_index_value = + TOKEN_NUM_INITIALIZER(struct cmd_2tuple_filter_result, + index_value, UINT16); +cmdline_parse_token_string_t cmd_2tuple_filter_add_filter = + TOKEN_STRING_INITIALIZER(struct cmd_2tuple_filter_result, + filter, "add_2tuple_filter"); +cmdline_parse_inst_t cmd_add_2tuple_filter = { + .f = cmd_2tuple_filter_parsed, + .data = NULL, + .help_str = "add a 2tuple filter", + .tokens = { + (void *)&cmd_2tuple_filter_add_filter, + (void *)&cmd_2tuple_filter_port_id, + (void *)&cmd_2tuple_filter_protocol, + (void *)&cmd_2tuple_filter_protocol_value, + (void *)&cmd_2tuple_filter_protocol_mask, + (void *)&cmd_2tuple_filter_dst_port, + (void *)&cmd_2tuple_filter_dst_port_value, + (void *)&cmd_2tuple_filter_dst_port_mask, + (void *)&cmd_2tuple_filter_flags, + (void *)&cmd_2tuple_filter_flags_value, + (void *)&cmd_2tuple_filter_priority, + (void *)&cmd_2tuple_filter_priority_value, + (void *)&cmd_2tuple_filter_queue, + (void *)&cmd_2tuple_filter_queue_id, + (void *)&cmd_2tuple_filter_index, + (void *)&cmd_2tuple_filter_index_value, + NULL, + }, +}; + +cmdline_parse_token_string_t cmd_2tuple_filter_remove_filter = + TOKEN_STRING_INITIALIZER(struct cmd_2tuple_filter_result, + filter, "remove_2tuple_filter"); +cmdline_parse_inst_t cmd_remove_2tuple_filter = { + .f = cmd_2tuple_filter_parsed, + .data = NULL, + .help_str = "remove a 2tuple filter", + .tokens = { + (void *)&cmd_2tuple_filter_remove_filter, + (void *)&cmd_2tuple_filter_port_id, + (void *)&cmd_2tuple_filter_index, + (void *)&cmd_2tuple_filter_index_value, + NULL, + }, +}; +cmdline_parse_token_string_t cmd_2tuple_filter_get_filter = + TOKEN_STRING_INITIALIZER(struct cmd_2tuple_filter_result, + filter, "get_2tuple_filter"); +cmdline_parse_inst_t cmd_get_2tuple_filter = { + .f = cmd_2tuple_filter_parsed, + .data = NULL, + .help_str = "get a 2tuple filter", + .tokens = { + (void *)&cmd_2tuple_filter_get_filter, + (void *)&cmd_2tuple_filter_port_id, + (void *)&cmd_2tuple_filter_index, + (void *)&cmd_2tuple_filter_index_value, + NULL, + }, +}; + +/* *** ADD/REMOVE A 5tuple FILTER *** */ +struct cmd_5tuple_filter_result { + cmdline_fixed_string_t filter; + uint8_t port_id; + cmdline_fixed_string_t dst_ip; + cmdline_ipaddr_t dst_ip_value; + cmdline_fixed_string_t src_ip; + cmdline_ipaddr_t src_ip_value; + cmdline_fixed_string_t dst_port; + uint16_t dst_port_value; + cmdline_fixed_string_t src_port; + uint16_t src_port_value; + cmdline_fixed_string_t protocol; + cmdline_fixed_string_t protocol_value; + cmdline_fixed_string_t mask; + uint8_t mask_value; + cmdline_fixed_string_t priority; + uint8_t priority_value; + cmdline_fixed_string_t queue; + uint8_t queue_id; + cmdline_fixed_string_t index; + uint16_t index_value; +}; + +static void +cmd_5tuple_filter_parsed(void *parsed_result, + __attribute__((unused)) struct cmdline *cl, + __attribute__((unused)) void *data) +{ + int ret = 0; + struct rte_5tuple_filter filter; + struct cmd_5tuple_filter_result *res = parsed_result; + + memset(&filter, 0, sizeof(struct rte_5tuple_filter)); + + if (!strcmp(res->filter, "add_5tuple_filter")){ + + filter.dst_ip_mask = (res->mask_value & 0x10) ? 0 : 1; + filter.src_ip_mask = (res->mask_value & 0x08) ? 0 : 1; + filter.dst_port_mask = (res->mask_value & 0x04) ? 0 : 1; + filter.src_port_mask = (res->mask_value & 0x02) ? 0 : 1; + filter.l4type_mask = (res->mask_value & 0x01) ? 0 : 1; + filter.priority = res->priority_value; + + if (res->dst_ip_value.family == AF_INET) + /** no need to convert, already big endian*/ + filter.dst_ip = res->dst_ip_value.addr.ipv4.s_addr; + else{ + if (filter.dst_ip_mask == 0){ + printf("can not support ipv6 invovle compare. \n"); + return; + } + filter.dst_ip = 0; + } + + if (res->src_ip_value.family == AF_INET) + /** no need to convert, already big endian*/ + filter.src_ip = res->src_ip_value.addr.ipv4.s_addr; + else{ + if (filter.src_ip_mask == 0){ + printf("can not support ipv6 invovle compare. \n"); + return; + } + filter.src_ip = 0; + } + /** need convert to big endian*/ + filter.dst_port = rte_cpu_to_be_16(res->dst_port_value); + filter.src_port = rte_cpu_to_be_16(res->src_port_value); + + if (!strcmp(res->protocol_value, "udp")) + filter.l4type = RTE_FILTER_L4TYPE_UDP; + else if (!strcmp(res->protocol_value, "tcp")) + filter.l4type = RTE_FILTER_L4TYPE_TCP; + else if (!strcmp(res->protocol_value, "sctp")) + filter.l4type = RTE_FILTER_L4TYPE_SCTP; + else + filter.l4type = RTE_FILTER_L4TYPE_NONE; + + ret = rte_eth_dev_add_5tuple_filter(res->port_id, res->index_value, + &filter, res->queue_id); + } else if (!strcmp(res->filter, "remove_5tuple_filter")) + ret = rte_eth_dev_remove_5tuple_filter(res->port_id, res->index_value); + else if (!strcmp(res->filter, "get_5tuple_filter")) + get_5tuple_filter(res->port_id, res->index_value); + if(ret < 0) + printf("5tuple filter setting error: (%s)\n", strerror(-ret)); +} + + +cmdline_parse_token_num_t cmd_5tuple_filter_port_id = + TOKEN_NUM_INITIALIZER(struct cmd_5tuple_filter_result, + port_id, UINT8); +cmdline_parse_token_string_t cmd_5tuple_filter_dst_ip = + TOKEN_STRING_INITIALIZER(struct cmd_5tuple_filter_result, + dst_ip, "dst_ip"); +cmdline_parse_token_ipaddr_t cmd_5tuple_filter_dst_ip_value = + TOKEN_IPADDR_INITIALIZER(struct cmd_5tuple_filter_result, + dst_ip_value); +cmdline_parse_token_string_t cmd_5tuple_filter_src_ip = + TOKEN_STRING_INITIALIZER(struct cmd_5tuple_filter_result, + src_ip, "src_ip"); +cmdline_parse_token_ipaddr_t cmd_5tuple_filter_src_ip_value = + TOKEN_IPADDR_INITIALIZER(struct cmd_5tuple_filter_result, + src_ip_value); +cmdline_parse_token_string_t cmd_5tuple_filter_dst_port = + TOKEN_STRING_INITIALIZER(struct cmd_5tuple_filter_result, + dst_port, "dst_port"); +cmdline_parse_token_num_t cmd_5tuple_filter_dst_port_value = + TOKEN_NUM_INITIALIZER(struct cmd_5tuple_filter_result, + dst_port_value, UINT16); +cmdline_parse_token_string_t cmd_5tuple_filter_src_port = + TOKEN_STRING_INITIALIZER(struct cmd_5tuple_filter_result, + src_port, "src_port"); +cmdline_parse_token_num_t cmd_5tuple_filter_src_port_value = + TOKEN_NUM_INITIALIZER(struct cmd_5tuple_filter_result, + src_port_value, UINT16); +cmdline_parse_token_string_t cmd_5tuple_filter_protocol = + TOKEN_STRING_INITIALIZER(struct cmd_5tuple_filter_result, + protocol, "protocol"); +cmdline_parse_token_string_t cmd_5tuple_filter_protocol_value = + TOKEN_STRING_INITIALIZER(struct cmd_5tuple_filter_result, + protocol_value, "tcp#udp#sctp#none"); +cmdline_parse_token_string_t cmd_5tuple_filter_mask = + TOKEN_STRING_INITIALIZER(struct cmd_5tuple_filter_result, + mask, "mask"); +cmdline_parse_token_num_t cmd_5tuple_filter_mask_value = + TOKEN_NUM_INITIALIZER(struct cmd_5tuple_filter_result, + mask_value, INT8); +cmdline_parse_token_string_t cmd_5tuple_filter_priority = + TOKEN_STRING_INITIALIZER(struct cmd_5tuple_filter_result, + priority, "priority"); +cmdline_parse_token_num_t cmd_5tuple_filter_priority_value = + TOKEN_NUM_INITIALIZER(struct cmd_5tuple_filter_result, + priority_value, UINT8); +cmdline_parse_token_string_t cmd_5tuple_filter_queue = + TOKEN_STRING_INITIALIZER(struct cmd_5tuple_filter_result, + queue, "queue"); +cmdline_parse_token_num_t cmd_5tuple_filter_queue_id = + TOKEN_NUM_INITIALIZER(struct cmd_5tuple_filter_result, + queue_id, UINT8); +cmdline_parse_token_string_t cmd_5tuple_filter_index = + TOKEN_STRING_INITIALIZER(struct cmd_5tuple_filter_result, + index, "index"); +cmdline_parse_token_num_t cmd_5tuple_filter_index_value = + TOKEN_NUM_INITIALIZER(struct cmd_5tuple_filter_result, + index_value, UINT16); + +cmdline_parse_token_string_t cmd_5tuple_filter_add_filter = + TOKEN_STRING_INITIALIZER(struct cmd_5tuple_filter_result, + filter, "add_5tuple_filter"); +cmdline_parse_inst_t cmd_add_5tuple_filter = { + .f = cmd_5tuple_filter_parsed, + .data = NULL, + .help_str = "add a 5tuple filter", + .tokens = { + (void *)&cmd_5tuple_filter_add_filter, + (void *)&cmd_5tuple_filter_port_id, + (void *)&cmd_5tuple_filter_dst_ip, + (void *)&cmd_5tuple_filter_dst_ip_value, + (void *)&cmd_5tuple_filter_src_ip, + (void *)&cmd_5tuple_filter_src_ip_value, + (void *)&cmd_5tuple_filter_dst_port, + (void *)&cmd_5tuple_filter_dst_port_value, + (void *)&cmd_5tuple_filter_src_port, + (void *)&cmd_5tuple_filter_src_port_value, + (void *)&cmd_5tuple_filter_protocol, + (void *)&cmd_5tuple_filter_protocol_value, + (void *)&cmd_5tuple_filter_mask, + (void *)&cmd_5tuple_filter_mask_value, + (void *)&cmd_5tuple_filter_priority, + (void *)&cmd_5tuple_filter_priority_value, + (void *)&cmd_5tuple_filter_queue, + (void *)&cmd_5tuple_filter_queue_id, + (void *)&cmd_5tuple_filter_index, + (void *)&cmd_5tuple_filter_index_value, + NULL, + }, +}; + +cmdline_parse_token_string_t cmd_5tuple_filter_remove_filter = + TOKEN_STRING_INITIALIZER(struct cmd_5tuple_filter_result, + filter, "remove_5tuple_filter"); +cmdline_parse_inst_t cmd_remove_5tuple_filter = { + .f = cmd_5tuple_filter_parsed, + .data = NULL, + .help_str = "remove a 5tuple filter", + .tokens = { + (void *)&cmd_5tuple_filter_remove_filter, + (void *)&cmd_5tuple_filter_port_id, + (void *)&cmd_5tuple_filter_index, + (void *)&cmd_5tuple_filter_index_value, + NULL, + }, +}; + +cmdline_parse_token_string_t cmd_5tuple_filter_get_filter = + TOKEN_STRING_INITIALIZER(struct cmd_5tuple_filter_result, + filter, "get_5tuple_filter"); +cmdline_parse_inst_t cmd_get_5tuple_filter = { + .f = cmd_5tuple_filter_parsed, + .data = NULL, + .help_str = "get a 5tuple filter", + .tokens = { + (void *)&cmd_5tuple_filter_get_filter, + (void *)&cmd_5tuple_filter_port_id, + (void *)&cmd_5tuple_filter_index, + (void *)&cmd_5tuple_filter_index_value, + NULL, + }, +}; + +/* *** ADD/REMOVE A flex FILTER *** */ +struct cmd_flex_filter_result { + cmdline_fixed_string_t filter; + uint8_t port_id; + cmdline_fixed_string_t len; + uint8_t len_value; + cmdline_fixed_string_t bytes; + cmdline_fixed_string_t bytes_value; + cmdline_fixed_string_t mask; + cmdline_fixed_string_t mask_value; + cmdline_fixed_string_t priority; + uint8_t priority_value; + cmdline_fixed_string_t queue; + uint8_t queue_id; + cmdline_fixed_string_t index; + uint16_t index_value; +}; + +static int xdigit2val(unsigned char c) +{ + int val; + if(isdigit(c)) + val = c - '0'; + else if(isupper(c)) + val = c - 'A' + 10; + else + val = c - 'a' + 10; + return val; +} + +static void +cmd_flex_filter_parsed(void *parsed_result, + __attribute__((unused)) struct cmdline *cl, + __attribute__((unused)) void *data) +{ + int ret = 0; + struct rte_flex_filter filter; + struct cmd_flex_filter_result *res = parsed_result; + char * bytes_ptr, *mask_ptr; + uint16_t len, i, j; + char c; + int val, mod = 0; + uint32_t dword = 0; + uint8_t byte = 0; + uint8_t hex = 0; + + if (!strcmp(res->filter, "add_flex_filter")){ + if(res->len_value > 128){ + printf("the len exceed the max length 128\n"); + return; + } + memset(&filter, 0, sizeof(struct rte_flex_filter)); + filter.len = res->len_value; + filter.priority = res->priority_value; + bytes_ptr = res->bytes_value; + mask_ptr = res->mask_value; + + j = 0; + /** translate bytes string to uint_32 array*/ + if (bytes_ptr[0] == '0' && ((bytes_ptr[1] == 'x') || + (bytes_ptr[1] == 'X')) ) + bytes_ptr += 2; + + len = strnlen(bytes_ptr, res->len_value * 2); + if (len == 0 || (len % 8 != 0)){ + printf("please check len and bytes input\n"); + return; + } + + for (i = 0; i < len; i++) { + c = bytes_ptr[i]; + if (isxdigit(c) == 0) { + /** invalid characters */ + printf("invalid input\n"); + return; + } + val = xdigit2val(c); + mod = i % 8; + if (i % 2){ + byte |= val; + dword |= byte << (4 * mod - 4); + byte = 0; + } + else + byte |= val << 4; + if (mod == 7){ + filter.dwords[j] = dword; + printf("dwords[%d]:%08x ",j, filter.dwords[j]); + j++; + dword = 0; + } + } + printf("\n"); + /** translate mask string to uint8_t array*/ + j = 0; + if (mask_ptr[0] == '0' && ((mask_ptr[1] == 'x') || + (mask_ptr[1] == 'X')) ) + mask_ptr += 2; + len = strnlen(mask_ptr, (res->len_value+3)/4); + if (len == 0){ + printf("invalid input\n"); + return; + } + for (i = 0; i < len; i++) { + c = mask_ptr[i]; + if (isxdigit(c) == 0) { + /** invalid characters */ + printf("invalid input\n"); + return; + } + val = xdigit2val(c); + hex |= (uint8_t)(val & 0x8) >> 3; + hex |= (uint8_t)(val & 0x4) >> 1; + hex |= (uint8_t)(val & 0x2) << 1; + hex |= (uint8_t)(val & 0x1) << 3; + + if (i % 2){ + byte |= hex << 4; + filter.mask[j] = byte; + printf("mask[%d]:%02x ",j, filter.mask[j]); + j++; + byte = 0; + } + else + byte |= hex; + hex = 0; + } + printf("\n"); + printf("call function rte_eth_dev_add_flex_filter: " + "index = %d, queue-id = %d, len = %d, priority = %d\n", + res->index_value, res->queue_id, + filter.len, filter.priority); + ret = rte_eth_dev_add_flex_filter(res->port_id, res->index_value, + &filter, res->queue_id); + + }else if (!strcmp(res->filter, "remove_flex_filter")) + ret = rte_eth_dev_remove_flex_filter(res->port_id, res->index_value); + else if (!strcmp(res->filter, "get_flex_filter")) + get_flex_filter(res->port_id, res->index_value); + + if(ret < 0) + printf("flex filter setting error: (%s)\n", strerror(-ret)); +} + +cmdline_parse_token_num_t cmd_flex_filter_port_id = + TOKEN_NUM_INITIALIZER(struct cmd_flex_filter_result, + port_id, UINT8); +cmdline_parse_token_string_t cmd_flex_filter_len = + TOKEN_STRING_INITIALIZER(struct cmd_flex_filter_result, + len, "len"); +cmdline_parse_token_string_t cmd_flex_filter_len_value = + TOKEN_NUM_INITIALIZER(struct cmd_flex_filter_result, + len_value, UINT8); +cmdline_parse_token_string_t cmd_flex_filter_bytes = + TOKEN_STRING_INITIALIZER(struct cmd_flex_filter_result, + bytes, "bytes"); +cmdline_parse_token_string_t cmd_flex_filter_bytes_value = + TOKEN_STRING_INITIALIZER(struct cmd_flex_filter_result, + bytes_value, NULL); +cmdline_parse_token_string_t cmd_flex_filter_mask = + TOKEN_STRING_INITIALIZER(struct cmd_flex_filter_result, + mask, "mask"); +cmdline_parse_token_string_t cmd_flex_filter_mask_value = + TOKEN_STRING_INITIALIZER(struct cmd_flex_filter_result, + mask_value, NULL); +cmdline_parse_token_string_t cmd_flex_filter_priority = + TOKEN_STRING_INITIALIZER(struct cmd_flex_filter_result, + priority, "priority"); +cmdline_parse_token_num_t cmd_flex_filter_priority_value = + TOKEN_NUM_INITIALIZER(struct cmd_flex_filter_result, + priority_value, UINT8); +cmdline_parse_token_string_t cmd_flex_filter_queue = + TOKEN_STRING_INITIALIZER(struct cmd_flex_filter_result, + queue, "queue"); +cmdline_parse_token_num_t cmd_flex_filter_queue_id = + TOKEN_NUM_INITIALIZER(struct cmd_flex_filter_result, + queue_id, UINT8); +cmdline_parse_token_string_t cmd_flex_filter_index = + TOKEN_STRING_INITIALIZER(struct cmd_flex_filter_result, + index, "index"); +cmdline_parse_token_num_t cmd_flex_filter_index_value = + TOKEN_NUM_INITIALIZER(struct cmd_flex_filter_result, + index_value, UINT16); +cmdline_parse_token_string_t cmd_flex_filter_add_filter = + TOKEN_STRING_INITIALIZER(struct cmd_flex_filter_result, + filter, "add_flex_filter"); +cmdline_parse_inst_t cmd_add_flex_filter = { + .f = cmd_flex_filter_parsed, + .data = NULL, + .help_str = "add a flex filter", + .tokens = { + (void *)&cmd_flex_filter_add_filter, + (void *)&cmd_flex_filter_port_id, + (void *)&cmd_flex_filter_len, + (void *)&cmd_flex_filter_len_value, + (void *)&cmd_flex_filter_bytes, + (void *)&cmd_flex_filter_bytes_value, + (void *)&cmd_flex_filter_mask, + (void *)&cmd_flex_filter_mask_value, + (void *)&cmd_flex_filter_priority, + (void *)&cmd_flex_filter_priority_value, + (void *)&cmd_flex_filter_queue, + (void *)&cmd_flex_filter_queue_id, + (void *)&cmd_flex_filter_index, + (void *)&cmd_flex_filter_index_value, + NULL, + }, +}; + +cmdline_parse_token_string_t cmd_flex_filter_remove_filter = + TOKEN_STRING_INITIALIZER(struct cmd_flex_filter_result, + filter, "remove_flex_filter"); +cmdline_parse_inst_t cmd_remove_flex_filter = { + .f = cmd_flex_filter_parsed, + .data = NULL, + .help_str = "remove a flex filter", + .tokens = { + (void *)&cmd_flex_filter_remove_filter, + (void *)&cmd_flex_filter_port_id, + (void *)&cmd_flex_filter_index, + (void *)&cmd_flex_filter_index_value, + NULL, + }, +}; + +cmdline_parse_token_string_t cmd_flex_filter_get_filter = + TOKEN_STRING_INITIALIZER(struct cmd_flex_filter_result, + filter, "get_flex_filter"); +cmdline_parse_inst_t cmd_get_flex_filter = { + .f = cmd_flex_filter_parsed, + .data = NULL, + .help_str = "get a flex filter", + .tokens = { + (void *)&cmd_flex_filter_get_filter, + (void *)&cmd_flex_filter_port_id, + (void *)&cmd_flex_filter_index, + (void *)&cmd_flex_filter_index_value, + NULL, + }, +}; + /* ******************************************************************************** */ /* list of instructions */ @@ -5189,6 +6077,21 @@ cmdline_parse_ctx_t main_ctx[] = { (cmdline_parse_inst_t *)&cmd_reset_mirror_rule, (cmdline_parse_inst_t *)&cmd_dump, (cmdline_parse_inst_t *)&cmd_dump_one, + (cmdline_parse_inst_t *)&cmd_add_ethertype_filter, + (cmdline_parse_inst_t *)&cmd_remove_ethertype_filter, + (cmdline_parse_inst_t *)&cmd_get_ethertype_filter, + (cmdline_parse_inst_t *)&cmd_add_syn_filter, + (cmdline_parse_inst_t *)&cmd_remove_syn_filter, + (cmdline_parse_inst_t *)&cmd_get_syn_filter, + (cmdline_parse_inst_t *)&cmd_add_2tuple_filter, + (cmdline_parse_inst_t *)&cmd_remove_2tuple_filter, + (cmdline_parse_inst_t *)&cmd_get_2tuple_filter, + (cmdline_parse_inst_t *)&cmd_add_5tuple_filter, + (cmdline_parse_inst_t *)&cmd_remove_5tuple_filter, + (cmdline_parse_inst_t *)&cmd_get_5tuple_filter, + (cmdline_parse_inst_t *)&cmd_add_flex_filter, + (cmdline_parse_inst_t *)&cmd_remove_flex_filter, + (cmdline_parse_inst_t *)&cmd_get_flex_filter, NULL, }; diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c index 134bf07..5d8b92f 100644 --- a/app/test-pmd/config.c +++ b/app/test-pmd/config.c @@ -1641,3 +1641,146 @@ set_vf_rx_vlan(portid_t port_id, uint16_t vlan_id, uint64_t vf_mask, uint8_t on) "diag=%d\n", port_id, diag); } +void +get_ethertype_filter(uint8_t port_id, uint16_t index) +{ + struct rte_ethertype_filter filter; + int ret = 0; + uint8_t rx_queue; + + memset(&filter, 0, sizeof(filter)); + ret = rte_eth_dev_get_ethertype_filter(port_id, index, + &filter, &rx_queue); + if (ret < 0){ + if (ret == (-ENOENT)) + printf("filter[%d] is not enabled\n", index); + else + printf("get ethertype filter fails(%s)\n", strerror(-ret)); + return; + }else{ + printf("filter[%d]: \n", index); + printf(" ethertype: 0x%04x \n", + rte_le_to_cpu_32(filter.ethertype)); + printf(" priority: %s, %d \n", + filter.priority_en ? "enable" : "disable", + filter.priority); + printf(" queue: %d \n", rx_queue); + } +} + +void +get_syn_filter(uint8_t port_id) +{ + struct rte_syn_filter filter; + int ret = 0; + uint8_t rx_queue; + + memset(&filter, 0, sizeof(filter)); + ret = rte_eth_dev_get_syn_filter(port_id, &filter, &rx_queue); + + if (ret < 0){ + printf("get syn filter fails(%s)\n", strerror(-ret)); + return; + } + printf("syn filter: %s, priority: %s, queue: %d\n", + filter.enable? "on" : "off", + filter.hig_pri? "high" : "low", + rx_queue); +} +void +get_2tuple_filter(uint8_t port_id, uint16_t index) +{ + struct rte_2tuple_filter filter; + int ret = 0; + uint8_t rx_queue; + + memset(&filter, 0, sizeof(filter)); + ret = rte_eth_dev_get_2tuple_filter(port_id, index, + &filter, &rx_queue); + if (ret < 0){ + if (ret == (-ENOENT)) + printf("filter[%d] is not enabled\n", index); + else + printf("get 2tuple filter fails(%s)\n", strerror(-ret)); + return; + }else{ + printf("filter[%d]: \n", index); + printf(" Destination Port: 0x%04x mask: %d \n", + rte_be_to_cpu_16(filter.dst_port), + filter.dst_port_mask ? 0 : 1); + printf(" protocol: 0x%02x mask:%d", + filter.protocol, filter.protocol_mask ? 0 : 1); + printf(" priority: %d queue: %d \n", filter.priority, rx_queue); + } +} + +void +get_5tuple_filter(uint8_t port_id, uint16_t index) +{ + struct rte_5tuple_filter filter; + int ret = 0; + uint8_t rx_queue; + const char *protocol_type[] = {"tcp", "udp", "sctp", "none"}; + + memset(&filter, 0, sizeof(filter)); + ret = rte_eth_dev_get_5tuple_filter(port_id, index, + &filter, &rx_queue); + if (ret < 0){ + if (ret == (-ENOENT)) + printf("filter[%d] is not enabled\n", index); + else + printf("get 5tuple filter fails(%s)\n", strerror(-ret)); + return; + }else{ + printf("filter[%d]: \n", index); + printf(" Destination IP: 0x%08x mask: %d \n", + (unsigned)rte_be_to_cpu_32(filter.dst_ip), + filter.dst_ip_mask ? 0 : 1); + printf(" Source IP: 0x%08x mask: %d \n", + (unsigned)rte_be_to_cpu_32(filter.src_ip), + filter.src_ip_mask ? 0 : 1); + printf(" Destination Port: 0x%04x mask: %d \n", + rte_be_to_cpu_16(filter.dst_port), + filter.dst_port_mask ? 0 : 1); + printf(" Source Port: 0x%04x mask: %d \n", + rte_be_to_cpu_16(filter.src_port), + filter.src_port_mask ? 0 :1); + printf(" protocol_type: %s mask: %d \n", + protocol_type[filter.l4type], + filter.l4type_mask ? 0 : 1); + printf(" priority: %d queue: %d \n", filter.priority, rx_queue); + } +} +void +get_flex_filter(uint8_t port_id, uint16_t index) + +{ + struct rte_flex_filter filter; + int ret = 0; + uint8_t rx_queue; + int i, j; + + memset(&filter, 0, sizeof(filter)); + ret = rte_eth_dev_get_flex_filter(port_id, index, + &filter, &rx_queue); + if (ret < 0){ + if (ret == (-ENOENT)) + printf("filter[%d] is not enabled\n", index); + else + printf("get flex filter fails(%s)\n", strerror(-ret)); + return; + }else{ + printf("filter[%d]: ", index); + printf("\n length: %d", filter.len); + printf("\n dword[]: 0x"); + for (i = 0; i < 32; i++) + printf("%08x ", (unsigned)rte_be_to_cpu_32(filter.dwords[i])); + printf("\n mask[]: 0b"); + for (i = 0; i < 16; i++){ + for(j = 0; j < 8; j++){ + printf("%c", (filter.mask[i] & (1 << j)) ? '1' : '0'); + } + } + printf("\n priority: %d queue: %d \n", filter.priority, rx_queue); + } +} diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h index 5b4ee6f..1b50898 100644 --- a/app/test-pmd/testpmd.h +++ b/app/test-pmd/testpmd.h @@ -521,6 +521,12 @@ void set_vf_traffic(portid_t port_id, uint8_t is_rx, uint16_t vf, uint8_t on); void set_vf_rx_vlan(portid_t port_id, uint16_t vlan_id, uint64_t vf_mask, uint8_t on); +void get_syn_filter(uint8_t port_id); +void get_ethertype_filter(uint8_t port_id, uint16_t index); +void get_2tuple_filter(uint8_t port_id, uint16_t index); +void get_5tuple_filter(uint8_t port_id, uint16_t index); +void get_flex_filter(uint8_t port_id, uint16_t index); + /* * Work-around of a compilation error with ICC on invocations of the * rte_be_to_cpu_16() function. diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c index a5727dd..ec411db 100644 --- a/lib/librte_ether/rte_ethdev.c +++ b/lib/librte_ether/rte_ethdev.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -2335,3 +2336,302 @@ rte_eth_dev_bypass_wd_reset(uint8_t port_id) return 0; } #endif + +int +rte_eth_dev_add_syn_filter(uint8_t port_id, uint8_t high_pri, + uint8_t rx_queue) +{ + struct rte_eth_dev *dev; + struct rte_syn_filter filter; + + if (port_id >= nb_ports) { + PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id); + return (-ENODEV); + } + + dev = &rte_eth_devices[port_id]; + filter.enable = 1; + filter.hig_pri = high_pri; + + FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_syn_filter, -ENOTSUP); + return (*dev->dev_ops->set_syn_filter)(dev, &filter, rx_queue); +} + +int +rte_eth_dev_remove_syn_filter(uint8_t port_id) +{ + struct rte_eth_dev *dev; + struct rte_syn_filter filter; + + if (port_id >= nb_ports) { + PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id); + return (-ENODEV); + } + + dev = &rte_eth_devices[port_id]; + filter.enable = 0; + filter.hig_pri = 0; + + FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_syn_filter, -ENOTSUP); + return (*dev->dev_ops->set_syn_filter)(dev, &filter, 0); +} + +int +rte_eth_dev_get_syn_filter(uint8_t port_id, + struct rte_syn_filter *filter, uint8_t *rx_queue) +{ + struct rte_eth_dev *dev; + + if (filter == NULL || rx_queue == NULL) + return (-EINVAL); + + if (port_id >= nb_ports) { + PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id); + return (-ENODEV); + } + + dev = &rte_eth_devices[port_id]; + + FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_syn_filter, -ENOTSUP); + return(*dev->dev_ops->get_syn_filter)(dev, filter, rx_queue); +} + +int +rte_eth_dev_add_ethertype_filter(uint8_t port_id, uint16_t index, + struct rte_ethertype_filter *filter, uint8_t rx_queue) +{ + struct rte_eth_dev *dev; + + if (port_id >= nb_ports) { + PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id); + return (-ENODEV); + } + if (filter->ethertype == ETHER_TYPE_IPv4 || filter->ethertype == ETHER_TYPE_IPv6){ + PMD_DEBUG_TRACE("IP and IPv6 are not supported in ethertype filter\n"); + return (-EINVAL); + } + dev = &rte_eth_devices[port_id]; + + FUNC_PTR_OR_ERR_RET(*dev->dev_ops->add_ethertype_filter, -ENOTSUP); + return (*dev->dev_ops->add_ethertype_filter)(dev, index, + filter, rx_queue); +} + +int +rte_eth_dev_remove_ethertype_filter(uint8_t port_id, uint16_t index) +{ + struct rte_eth_dev *dev; + + if (port_id >= nb_ports) { + PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id); + return (-ENODEV); + } + + dev = &rte_eth_devices[port_id]; + + FUNC_PTR_OR_ERR_RET(*dev->dev_ops->remove_ethertype_filter, -ENOTSUP); + return (*dev->dev_ops->remove_ethertype_filter)(dev, index); +} + +int +rte_eth_dev_get_ethertype_filter(uint8_t port_id, uint16_t index, + struct rte_ethertype_filter *filter, uint8_t *rx_queue) +{ + struct rte_eth_dev *dev; + + if (filter == NULL || rx_queue == NULL) + return (-EINVAL); + + if (port_id >= nb_ports) { + PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id); + return (-ENODEV); + } + + dev = &rte_eth_devices[port_id]; + + FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_ethertype_filter, -ENOTSUP); + return (*dev->dev_ops->get_ethertype_filter)(dev, index, + filter, rx_queue); +} + +int +rte_eth_dev_add_2tuple_filter(uint8_t port_id, uint16_t index, + struct rte_2tuple_filter *filter, uint8_t rx_queue) +{ + struct rte_eth_dev *dev; + + if (port_id >= nb_ports) { + PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id); + return (-ENODEV); + } + if (filter->protocol != IPPROTO_TCP && + filter->tcp_flags != 0){ + PMD_DEBUG_TRACE("tcp flags is 0x%x, but the protocol value is not TCP\n", + filter->tcp_flags); + return (-EINVAL); + } + + dev = &rte_eth_devices[port_id]; + + FUNC_PTR_OR_ERR_RET(*dev->dev_ops->add_2tuple_filter, -ENOTSUP); + return (*dev->dev_ops->add_2tuple_filter)(dev, index, filter, rx_queue); +} + +int +rte_eth_dev_remove_2tuple_filter(uint8_t port_id, uint16_t index) +{ + + struct rte_eth_dev *dev; + + if (port_id >= nb_ports) { + PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id); + return (-ENODEV); + } + + dev = &rte_eth_devices[port_id]; + + FUNC_PTR_OR_ERR_RET(*dev->dev_ops->remove_2tuple_filter, -ENOTSUP); + return (*dev->dev_ops->remove_2tuple_filter)(dev, index); + +} + +int +rte_eth_dev_get_2tuple_filter(uint8_t port_id, uint16_t index, + struct rte_2tuple_filter *filter, uint8_t *rx_queue) +{ + struct rte_eth_dev *dev; + + if (filter == NULL || rx_queue == NULL) + return (-EINVAL); + + if (port_id >= nb_ports) { + PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id); + return (-ENODEV); + } + + dev = &rte_eth_devices[port_id]; + + FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_2tuple_filter, -ENOTSUP); + return (*dev->dev_ops->get_2tuple_filter)(dev, index, filter, rx_queue); +} + +int +rte_eth_dev_add_5tuple_filter(uint8_t port_id, uint16_t index, + struct rte_5tuple_filter *filter, uint8_t rx_queue) +{ + struct rte_eth_dev *dev; + + if (port_id >= nb_ports) { + PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id); + return (-ENODEV); + } + if ((filter->l4type == RTE_FILTER_L4TYPE_NONE) && + (filter->dst_port_mask == 0 || filter->src_port_mask == 0)) { + PMD_DEBUG_TRACE(" the L4 protocol type is none, port are meaningless " \ + "should not involve!\n"); + return (-EINVAL); + } + + dev = &rte_eth_devices[port_id]; + + + FUNC_PTR_OR_ERR_RET(*dev->dev_ops->add_5tuple_filter, -ENOTSUP); + return (*dev->dev_ops->add_5tuple_filter)(dev, index, filter, rx_queue); + +} + +int +rte_eth_dev_remove_5tuple_filter(uint8_t port_id, uint16_t index) +{ + + struct rte_eth_dev *dev; + + if (port_id >= nb_ports) { + PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id); + return (-ENODEV); + } + + dev = &rte_eth_devices[port_id]; + + FUNC_PTR_OR_ERR_RET(*dev->dev_ops->remove_5tuple_filter, -ENOTSUP); + return (*dev->dev_ops->remove_5tuple_filter)(dev, index); + +} + +int +rte_eth_dev_get_5tuple_filter(uint8_t port_id, uint16_t index, + struct rte_5tuple_filter *filter, uint8_t *rx_queue) +{ + struct rte_eth_dev *dev; + + if (filter == NULL || rx_queue == NULL) + return (-EINVAL); + + if (port_id >= nb_ports) { + PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id); + return (-ENODEV); + } + + dev = &rte_eth_devices[port_id]; + + FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_5tuple_filter, -ENOTSUP); + return (*dev->dev_ops->get_5tuple_filter)(dev, index, filter, + rx_queue); +} + +int +rte_eth_dev_add_flex_filter(uint8_t port_id, uint16_t index, + struct rte_flex_filter *filter, uint8_t rx_queue) +{ + struct rte_eth_dev *dev; + + if (port_id >= nb_ports) { + PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id); + return (-ENODEV); + } + + dev = &rte_eth_devices[port_id]; + + FUNC_PTR_OR_ERR_RET(*dev->dev_ops->add_flex_filter, -ENOTSUP); + return (*dev->dev_ops->add_flex_filter)(dev, index, filter, rx_queue); + +} + +int +rte_eth_dev_remove_flex_filter(uint8_t port_id, uint16_t index) +{ + + struct rte_eth_dev *dev; + + if (port_id >= nb_ports) { + PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id); + return (-ENODEV); + } + + dev = &rte_eth_devices[port_id]; + + FUNC_PTR_OR_ERR_RET(*dev->dev_ops->remove_flex_filter, -ENOTSUP); + return (*dev->dev_ops->remove_flex_filter)(dev, index); + +} + +int +rte_eth_dev_get_flex_filter(uint8_t port_id, uint16_t index, + struct rte_flex_filter *filter, uint8_t *rx_queue) +{ + struct rte_eth_dev *dev; + + if (filter == NULL || rx_queue == NULL) + return (-EINVAL); + + if (port_id >= nb_ports) { + PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id); + return (-ENODEV); + } + + dev = &rte_eth_devices[port_id]; + + FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_flex_filter, -ENOTSUP); + return (*dev->dev_ops->get_flex_filter)(dev, index, filter, + rx_queue); +} diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h index dea7471..cd4bec6 100644 --- a/lib/librte_ether/rte_ethdev.h +++ b/lib/librte_ether/rte_ethdev.h @@ -808,6 +808,81 @@ struct rte_eth_dev_callback; /** @internal Structure to keep track of registered callbacks */ TAILQ_HEAD(rte_eth_dev_cb_list, rte_eth_dev_callback); + +/** + * Possible l4type of 5tuple filters. + */ +enum rte_filter_l4type{ + RTE_FILTER_L4TYPE_TCP = 0, + RTE_FILTER_L4TYPE_UDP, + RTE_FILTER_L4TYPE_SCTP, + RTE_FILTER_L4TYPE_NONE, +}; +#define TCP_UGR_FLAG 0x20 +#define TCP_ACK_FLAG 0x10 +#define TCP_PSH_FLAG 0x08 +#define TCP_RST_FLAG 0x04 +#define TCP_SYN_FLAG 0x02 +#define TCP_FIN_FLAG 0x01 +#define TCP_FLAG_ALL 0x3F + +/** + * A structure used to define an ethertype filter. + */ +struct rte_ethertype_filter{ + uint16_t ethertype; /**data->dev_private); + uint32_t synqf, rfctl; + + MAC_TYPE_FILTER_SUP(hw->mac.type); + + if (rx_queue >= IGB_MAX_RX_QUEUE_NUM) + return (-EINVAL); + + synqf = E1000_READ_REG(hw, E1000_SYNQF(0)); + rfctl = E1000_READ_REG(hw, E1000_RFCTL); + + if (filter->enable){ + if (synqf & E1000_SYN_FILTER_ENABLE) + return (-EINVAL); + synqf = (uint32_t)(((rx_queue << E1000_SYN_FILTER_QUEUE_SHIFT) & E1000_SYN_FILTER_QUEUE) | + E1000_SYN_FILTER_ENABLE); + }else + synqf = 0; + + if (filter->hig_pri) + rfctl |= E1000_RFCTL_SYNQFP; + else + rfctl &= ~E1000_RFCTL_SYNQFP; + + E1000_WRITE_REG(hw, E1000_SYNQF(0), synqf); + E1000_WRITE_REG(hw, E1000_RFCTL, rfctl); + return 0; +} + +/* + *get the syn filter's info + * + * @param + * dev: Pointer to struct rte_eth_dev. + * *syn: pointer to syn value (1 means enable, 0 means disable). + * *rx_queue: pointer to the queue id the filter assigned to + * + * @return + * - On success, zero. + * - On failure, a negative value. + */ +static int +eth_igb_get_syn_filter(struct rte_eth_dev *dev, + struct rte_syn_filter *filter, uint8_t *rx_queue) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t synqf, rfctl; + + MAC_TYPE_FILTER_SUP(hw->mac.type); + + synqf = E1000_READ_REG(hw, E1000_SYNQF(0)); + rfctl = E1000_READ_REG(hw, E1000_RFCTL); + filter->enable = (synqf & E1000_SYN_FILTER_ENABLE)? 1 : 0; + filter->hig_pri = (rfctl & E1000_RFCTL_SYNQFP) ? 1 : 0; + *rx_queue = (uint8_t)((synqf & E1000_SYN_FILTER_QUEUE)>> E1000_SYN_FILTER_QUEUE_SHIFT); + + return 0; +} + +/* + *add an ethertype filter + * + * @param + * dev: Pointer to struct rte_eth_dev. + * index: the index the filter allocates + * filter: ponter to the filter that will be added + * rx_queue: the queue id the filter assigned to + * + * @return + * - On success, zero. + * - On failure, a negative value. + */ +static int +eth_igb_add_ethertype_filter(struct rte_eth_dev *dev, uint16_t index, + struct rte_ethertype_filter *filter, uint8_t rx_queue) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t etqf; + + MAC_TYPE_FILTER_SUP(hw->mac.type); + + if (index >= E1000_MAX_ETQF_FILTERS || rx_queue >= IGB_MAX_RX_QUEUE_NUM) + return (-EINVAL); + + etqf = E1000_READ_REG(hw, E1000_ETQF(index)); + if (etqf & E1000_ETQF_FILTER_ENABLE){ + return (-EINVAL); /**filter index is in use*/ + } + else + etqf = 0; + + etqf |= E1000_ETQF_FILTER_ENABLE | E1000_ETQF_QUEUE_ENABLE; + etqf |= (uint32_t)(filter->ethertype & E1000_ETQF_ETHERTYPE); + etqf |= rx_queue << E1000_ETQF_QUEUE_SHIFT; + + if (filter->priority_en){ + PMD_INIT_LOG(ERR, "vlan and priority (%d) is not support in E1000.\n", + filter->priority); + return (-EINVAL); + } + + E1000_WRITE_REG(hw, E1000_ETQF(index), etqf); + + return 0; +} + +/* + *remove an ethertype filter + * + * @param + * dev: Pointer to struct rte_eth_dev. + * index: the index the filter allocates + * + * @return + * - On success, zero. + * - On failure, a negative value. + */ +static int +eth_igb_remove_ethertype_filter(struct rte_eth_dev *dev, uint16_t index) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + MAC_TYPE_FILTER_SUP(hw->mac.type); + + if (index >= E1000_MAX_ETQF_FILTERS) + return (-EINVAL); + + E1000_WRITE_REG(hw, E1000_ETQF(index), 0); + + return 0; +} + +/* + *gets an ethertype filter + * + * @param + * dev: Pointer to struct rte_eth_dev. + * index: the index the filter allocates + * filter: ponter to the filter that will be gotten + * *rx_queue: the ponited of the queue id the filter assigned to + * + * @return + * - On success, zero. + * - On failure, a negative value. + */ +static int +eth_igb_get_ethertype_filter(struct rte_eth_dev *dev, uint16_t index, + struct rte_ethertype_filter *filter, uint8_t *rx_queue) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t etqf; + + MAC_TYPE_FILTER_SUP(hw->mac.type); + + if (index >= E1000_MAX_ETQF_FILTERS) + return (-EINVAL); + + etqf = E1000_READ_REG(hw, E1000_ETQF(index)); + if (etqf & E1000_ETQF_FILTER_ENABLE ){ + filter->ethertype = etqf & E1000_ETQF_ETHERTYPE; + filter->priority_en = 0; + *rx_queue = (etqf & E1000_ETQF_QUEUE) >> E1000_ETQF_QUEUE_SHIFT; + return 0; + } + return (-ENOENT); +} + +/* + *add a 2tuple filter + * + * @param + * dev: Pointer to struct rte_eth_dev. + * index: the index the filter allocates + * filter: ponter to the filter that will be added + * rx_queue: the queue id the filter assigned to + * + * @return + * - On success, zero. + * - On failure, a negative value. + */ +static int +eth_igb_add_2tuple_filter(struct rte_eth_dev *dev, uint16_t index, + struct rte_2tuple_filter *filter, uint8_t rx_queue) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t ttqf, imir = 0; + uint32_t imir_ext = 0; + + MAC_TYPE_FILTER_SUP(hw->mac.type); + + if (index >= E1000_MAX_TTQF_FILTERS || + rx_queue >= IGB_MAX_RX_QUEUE_NUM || filter->priority > E1000_2TUPLE_MAX_PRI) + return (-EINVAL); /**filter index is out of range*/ + if (filter->tcp_flags > TCP_FLAG_ALL) + return (-EINVAL); /**flags is invalid*/ + + ttqf = E1000_READ_REG(hw, E1000_TTQF(index)); + if (ttqf & E1000_TTQF_QUEUE_ENABLE) + return (-EINVAL); /**filter index is in use*/ + + imir = (uint32_t)(filter->dst_port & E1000_IMIR_DSTPORT); + if (filter->dst_port_mask == 1) /**1b means not compare*/ + imir |= E1000_IMIR_PORT_BP; + else + imir &= ~E1000_IMIR_PORT_BP; + + imir |= filter->priority << E1000_IMIR_PRIORITY_SHIFT; + + ttqf = 0; + ttqf |= E1000_TTQF_QUEUE_ENABLE; + ttqf |= (uint32_t)(rx_queue << E1000_TTQF_QUEUE_SHIFT); + ttqf |= (uint32_t)(filter->protocol & E1000_TTQF_PROTOCOL_MASK); + if (filter->protocol_mask == 1) + ttqf |= E1000_TTQF_MASK_ENABLE; + else + ttqf &= ~E1000_TTQF_MASK_ENABLE; + + imir_ext |= E1000_IMIR_EXT_SIZE_BP; + /*tcp flags bits setting*/ + if (filter->tcp_flags & TCP_FLAG_ALL){ + if (filter->tcp_flags & TCP_UGR_FLAG) + imir_ext |= E1000_IMIR_EXT_CTRL_UGR; + if (filter->tcp_flags & TCP_ACK_FLAG) + imir_ext |= E1000_IMIR_EXT_CTRL_ACK; + if (filter->tcp_flags & TCP_PSH_FLAG) + imir_ext |= E1000_IMIR_EXT_CTRL_PSH; + if (filter->tcp_flags & TCP_RST_FLAG) + imir_ext |= E1000_IMIR_EXT_CTRL_RST; + if (filter->tcp_flags & TCP_SYN_FLAG) + imir_ext |= E1000_IMIR_EXT_CTRL_SYN; + if (filter->tcp_flags & TCP_FIN_FLAG) + imir_ext |= E1000_IMIR_EXT_CTRL_FIN; + imir_ext &= ~E1000_IMIR_EXT_CTRL_BP; + } + else + imir_ext |= E1000_IMIR_EXT_CTRL_BP; + E1000_WRITE_REG(hw, E1000_IMIR(index), imir); + E1000_WRITE_REG(hw, E1000_TTQF(index), ttqf); + E1000_WRITE_REG(hw, E1000_IMIREXT(index), imir_ext); + + return 0; +} + +/* + *remove a 2tuple filter + * + * @param + * dev: Pointer to struct rte_eth_dev. + * index: the index the filter allocates + * + * @return + * - On success, zero. + * - On failure, a negative value. + */ +static int +eth_igb_remove_2tuple_filter(struct rte_eth_dev *dev, + uint16_t index) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + MAC_TYPE_FILTER_SUP(hw->mac.type); + + if (index >= E1000_MAX_TTQF_FILTERS) + return (-EINVAL); /**filter index is out of range*/ + + E1000_WRITE_REG(hw, E1000_TTQF(index), 0); + E1000_WRITE_REG(hw, E1000_IMIR(index), 0); + E1000_WRITE_REG(hw, E1000_IMIREXT(index), 0); + return 0; + +} + +/* + *get a 2tuple filter + * + * @param + * dev: Pointer to struct rte_eth_dev. + * index: the index the filter allocates + * filter: ponter to the filter that returns + * *rx_queue: pointer of the queue id the filter assigned to + * + * @return + * - On success, zero. + * - On failure, a negative value. + */ +static int +eth_igb_get_2tuple_filter(struct rte_eth_dev *dev, uint16_t index, + struct rte_2tuple_filter *filter, uint8_t *rx_queue) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t imir, ttqf; + + MAC_TYPE_FILTER_SUP(hw->mac.type); + + if (index >= E1000_MAX_TTQF_FILTERS) + return (-EINVAL); /**filter index is out of range*/ + + ttqf = E1000_READ_REG(hw, E1000_TTQF(index)); + if (ttqf & E1000_TTQF_QUEUE_ENABLE){ + imir = E1000_READ_REG(hw, E1000_IMIR(index)); + filter->protocol = ttqf & E1000_TTQF_PROTOCOL_MASK; + filter->protocol_mask = (ttqf & E1000_TTQF_MASK_ENABLE) ? 1 : 0; + *rx_queue = (ttqf & E1000_TTQF_RX_QUEUE_MASK) >> E1000_TTQF_QUEUE_SHIFT; + filter->dst_port = (uint16_t)(imir & E1000_IMIR_DSTPORT); + filter->dst_port_mask = (imir & E1000_IMIR_PORT_BP) ? 1 : 0; + filter->priority = (imir & E1000_IMIR_PRIORITY) >> E1000_IMIR_PRIORITY_SHIFT; + return 0; + } + return (-ENOENT); +} + +/* + *add a flex filter + * + * @param + * dev: Pointer to struct rte_eth_dev. + * index: the index the filter allocates + * filter: ponter to the filter that will be added + * rx_queue: the queue id the filter assigned to + * + * @return + * - On success, zero. + * - On failure, a negative value. + */ +static int +eth_igb_add_flex_filter(struct rte_eth_dev *dev, uint16_t index, + struct rte_flex_filter *filter, uint8_t rx_queue) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t wufc, en_bits = 0; + uint32_t queueing = 0; + uint32_t reg_off = 0; + uint8_t i, j= 0; + + MAC_TYPE_FILTER_SUP(hw->mac.type); + + if (index >= E1000_MAX_FLEXIBLE_FILTERS) + return (-EINVAL); /**filter index is out of range*/ + + if (filter->len == 0 || filter->len > E1000_MAX_FLEX_FILTER_LEN|| + filter->len % 8 != 0 || filter->priority > E1000_MAX_FLEX_FILTER_PRI) + return (-EINVAL); + + + wufc = E1000_READ_REG(hw, E1000_WUFC); + en_bits = IXGBE_WUFC_FLEX_HQ | (E1000_WUFC_FLX0 << index); + if ((wufc & en_bits) == en_bits) + return (-EINVAL); /**the filter is enabled*/ + + E1000_WRITE_REG(hw, E1000_WUFC, wufc | IXGBE_WUFC_FLEX_HQ | (E1000_WUFC_FLX0 << index)); + + j = 0; + if (index < E1000_MAX_FHFT) + reg_off = E1000_FHFT(index); + else + reg_off = E1000_FHFT_EXT(index - E1000_MAX_FHFT); + + for (i = 0; i < 16; i++){ + E1000_WRITE_REG(hw, reg_off + i*4*4, filter->dwords[j]); + E1000_WRITE_REG(hw, reg_off + (i*4+1)*4, filter->dwords[++j]); + E1000_WRITE_REG(hw, reg_off + (i*4+2)*4, (uint32_t)filter->mask[i]); + ++j; + } + queueing |= filter->len | (rx_queue << E1000_FHFT_QUEUEING_QUEUE_SHIFT) | + (filter->priority << E1000_FHFT_QUEUEING_PRIO_SHIFT); + E1000_WRITE_REG(hw, reg_off + E1000_FHFT_QUEUEING_OFFSET, queueing); + return 0; +} + +/* + *remove a flex filter + * + * @param + * dev: Pointer to struct rte_eth_dev. + * index: the index the filter allocates + * + * @return + * - On success, zero. + * - On failure, a negative value. + */ +static int +eth_igb_remove_flex_filter(struct rte_eth_dev *dev, + uint16_t index) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t wufc, reg_off = 0; + uint8_t i; + + MAC_TYPE_FILTER_SUP(hw->mac.type); + + if (index >= E1000_MAX_FLEXIBLE_FILTERS) + return (-EINVAL); /**filter index is out of range*/ + + wufc = E1000_READ_REG(hw, E1000_WUFC); + E1000_WRITE_REG(hw, E1000_WUFC, wufc &(~(E1000_WUFC_FLX0 << index))); + + if (index < E1000_MAX_FHFT) + reg_off = E1000_FHFT(index); + else + reg_off = E1000_FHFT_EXT(index - E1000_MAX_FHFT); + + for (i = 0; i < 64; i++) + E1000_WRITE_REG(hw, reg_off + i*4, 0); + return 0; +} + +/* + *get a flex filter + * + * @param + * dev: Pointer to struct rte_eth_dev. + * index: the index the filter allocates + * filter: ponter to the filter that returns + * *rx_queue: the pointer of the queue id the filter assigned to + * + * @return + * - On success, zero. + * - On failure, a negative value. + */ +static int +eth_igb_get_flex_filter(struct rte_eth_dev *dev, uint16_t index, + struct rte_flex_filter *filter, uint8_t *rx_queue) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t wufc, queueing, wufc_en = 0; + uint8_t i,j; + + MAC_TYPE_FILTER_SUP(hw->mac.type); + + if (index >= E1000_MAX_FLEXIBLE_FILTERS) + return (-EINVAL); /**filter index is out of range*/ + + wufc = E1000_READ_REG(hw,E1000_WUFC); + wufc_en = IXGBE_WUFC_FLEX_HQ | (E1000_WUFC_FLX0 << index); + + if ((wufc & wufc_en) == wufc_en){ + uint32_t reg_off = 0; + + j = 0; + if (index < E1000_MAX_FHFT) + reg_off = E1000_FHFT(index); + else + reg_off = E1000_FHFT_EXT(index - E1000_MAX_FHFT); + + for (i = 0; i < 16; i++, j = i * 2){ + filter->dwords[j] = E1000_READ_REG(hw, reg_off + i*4*4); + filter->dwords[j+1] = E1000_READ_REG(hw, reg_off + (i*4+1)*4); + filter->mask[i] = E1000_READ_REG(hw, reg_off + (i*4+2)*4); + } + queueing = E1000_READ_REG(hw, reg_off + E1000_FHFT_QUEUEING_OFFSET); + filter->len = queueing & E1000_FHFT_QUEUEING_LEN; + filter->priority = (queueing & E1000_FHFT_QUEUEING_PRIO) >> E1000_FHFT_QUEUEING_PRIO_SHIFT; + *rx_queue = (queueing & E1000_FHFT_QUEUEING_QUEUE) >> E1000_FHFT_QUEUEING_QUEUE_SHIFT; + return 0; + } + return (-ENOENT); +} diff --git a/lib/librte_pmd_ixgbe/ixgbe_ethdev.c b/lib/librte_pmd_ixgbe/ixgbe_ethdev.c index 89ab4aa..49ff0d1 100644 --- a/lib/librte_pmd_ixgbe/ixgbe_ethdev.c +++ b/lib/librte_pmd_ixgbe/ixgbe_ethdev.c @@ -181,6 +181,22 @@ static int ixgbe_mirror_rule_set(struct rte_eth_dev *dev, static int ixgbe_mirror_rule_reset(struct rte_eth_dev *dev, uint8_t rule_id); +static int ixgbe_set_syn_filter(struct rte_eth_dev *dev, + struct rte_syn_filter *filter, uint8_t rx_queue); +static int ixgbe_get_syn_filter(struct rte_eth_dev *dev, + struct rte_syn_filter *filter, uint8_t *rx_queue); +static int ixgbe_add_ethertype_filter(struct rte_eth_dev *dev, uint16_t index, + struct rte_ethertype_filter *filter, uint8_t rx_queue); +static int ixgbe_remove_ethertype_filter(struct rte_eth_dev *dev, uint16_t index); +static int ixgbe_get_ethertype_filter(struct rte_eth_dev *dev, uint16_t index, + struct rte_ethertype_filter *filter, uint8_t *rx_queue); +static int ixgbe_add_5tuple_filter(struct rte_eth_dev *dev, uint16_t index, + struct rte_5tuple_filter *filter, uint8_t rx_queue); +static int ixgbe_remove_5tuple_filter(struct rte_eth_dev *dev, + uint16_t index); +static int ixgbe_get_5tuple_filter(struct rte_eth_dev *dev, uint16_t index, + struct rte_5tuple_filter *filter, uint8_t *rx_queue); + /* * Define VF Stats MACRO for Non "cleared on read" register */ @@ -300,6 +316,14 @@ static struct eth_dev_ops ixgbe_eth_dev_ops = { .bypass_ver_show = ixgbe_bypass_ver_show, .bypass_wd_reset = ixgbe_bypass_wd_reset, #endif /* RTE_NIC_BYPASS */ + .set_syn_filter = ixgbe_set_syn_filter, + .get_syn_filter = ixgbe_get_syn_filter, + .add_ethertype_filter = ixgbe_add_ethertype_filter, + .remove_ethertype_filter = ixgbe_remove_ethertype_filter, + .get_ethertype_filter = ixgbe_get_ethertype_filter, + .add_5tuple_filter = ixgbe_add_5tuple_filter, + .remove_5tuple_filter = ixgbe_remove_5tuple_filter, + .get_5tuple_filter = ixgbe_get_5tuple_filter, }; /* @@ -3060,3 +3084,344 @@ ixgbe_mirror_rule_reset(struct rte_eth_dev *dev, uint8_t rule_id) return 0; } + +/* + * set the syn filter + * + * @param + * dev: Pointer to struct rte_eth_dev. + * syn: 1 means enable, 0 means disable. + * rx_queue: the queue id the filter assigned to + * + * @return + * - On success, zero. + * - On failure, a negative value. + */ +static int +ixgbe_set_syn_filter(struct rte_eth_dev *dev, + struct rte_syn_filter *filter, uint8_t rx_queue) +{ + struct ixgbe_hw *hw= IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t synqf; + + if (hw->mac.type != ixgbe_mac_82599EB) + return -ENOSYS; + + if (rx_queue >= IXGBE_MAX_RX_QUEUE_NUM) + return (-EINVAL); + + synqf = IXGBE_READ_REG(hw, IXGBE_SYNQF); + + if (filter->enable) + synqf = (uint32_t)(((rx_queue << IXGBE_SYN_FILTER_QUEUE_SHIFT) & + IXGBE_SYN_FILTER_QUEUE) | IXGBE_SYN_FILTER_ENABLE); + else + synqf &= ~(IXGBE_SYN_FILTER_QUEUE | IXGBE_SYN_FILTER_ENABLE); + + + if (filter->hig_pri) + synqf |= IXGBE_SYN_FILTER_SYNQFP; + else + synqf &= ~IXGBE_SYN_FILTER_SYNQFP; + + IXGBE_WRITE_REG(hw, IXGBE_SYNQF, synqf); + + return 0; +} + +/* + * get the syn filter's info + * + * @param + * dev: Pointer to struct rte_eth_dev. + * *syn: pointer to syn value (1 means enable, 0 means disable). + * *rx_queue: pointer to the queue id the filter assigned to + * + * @return + * - On success, zero. + * - On failure, a negative value. + */ +static int +ixgbe_get_syn_filter(struct rte_eth_dev *dev, + struct rte_syn_filter *filter, uint8_t *rx_queue) + +{ + struct ixgbe_hw *hw= IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t synqf; + + if (hw->mac.type != ixgbe_mac_82599EB) + return -ENOSYS; + + synqf = IXGBE_READ_REG(hw, IXGBE_SYNQF); + filter->enable = (synqf & IXGBE_SYN_FILTER_ENABLE) ? 1 : 0; + filter->hig_pri = (synqf & IXGBE_SYN_FILTER_SYNQFP) ? 1 : 0; + *rx_queue = (uint8_t)((synqf & IXGBE_SYN_FILTER_QUEUE)>> 1); + + return 0; +} + +/* + * add an ethertype filter + * + * @param + * dev: Pointer to struct rte_eth_dev. + * index: the index the filter allocates + * filter: ponter to the filter that will be added + * rx_queue: the queue id the filter assigned to + * + * @return + * - On success, zero. + * - On failure, a negative value. + */ +static int +ixgbe_add_ethertype_filter(struct rte_eth_dev *dev, + uint16_t index, struct rte_ethertype_filter *filter, + uint8_t rx_queue) +{ + struct ixgbe_hw *hw= IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t etqf, etqs = 0; + + if (hw->mac.type != ixgbe_mac_82599EB) + return -ENOSYS; + + if (index >= IXGBE_MAX_ETQF_FILTERS || rx_queue >= IXGBE_MAX_RX_QUEUE_NUM) + return (-EINVAL); + + etqf = IXGBE_READ_REG(hw, IXGBE_ETQF(index)); + if (etqf & IXGBE_ETQF_FILTER_EN) + return (-EINVAL); /** filter index is in use*/ + + etqf = 0; + etqf |= IXGBE_ETQF_FILTER_EN; + etqf |= (uint32_t)filter->ethertype; + + if (filter->priority_en){ + if (filter->priority > IXGBE_ETQF_MAX_PRI) + return (-EINVAL); + etqf |= (uint32_t)((filter->priority << IXGBE_ETQF_SHIFT ) & IXGBE_ETQF_UP); + etqf |= IXGBE_ETQF_UP_EN; + } + etqs |= (uint32_t)((rx_queue << IXGBE_ETQS_RX_QUEUE_SHIFT) & IXGBE_ETQS_RX_QUEUE); + etqs |= IXGBE_ETQS_QUEUE_EN; + + IXGBE_WRITE_REG(hw, IXGBE_ETQF(index), etqf); + IXGBE_WRITE_REG(hw, IXGBE_ETQS(index), etqs); + + return 0; +} + +/* + * remove an ethertype filter + * + * @param + * dev: Pointer to struct rte_eth_dev. + * index: the index the filter allocates + * + * @return + * - On success, zero. + * - On failure, a negative value. + */ +static int +ixgbe_remove_ethertype_filter(struct rte_eth_dev *dev, + uint16_t index) +{ + struct ixgbe_hw *hw= IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + if (hw->mac.type != ixgbe_mac_82599EB) + return -ENOSYS; + + if (index >= IXGBE_MAX_ETQF_FILTERS) + return (-EINVAL); + + IXGBE_WRITE_REG(hw, IXGBE_ETQF(index), 0); + IXGBE_WRITE_REG(hw, IXGBE_ETQS(index), 0); + + return 0; +} + +/* + * gets an ethertype filter + * + * @param + * dev: Pointer to struct rte_eth_dev. + * index: the index the filter allocates + * filter: ponter to the filter that will be gotten + * *rx_queue: the ponited of the queue id the filter assigned to + * + * @return + * - On success, zero. + * - On failure, a negative value. + */ +static int +ixgbe_get_ethertype_filter(struct rte_eth_dev *dev, + uint16_t index, struct rte_ethertype_filter *filter, + uint8_t *rx_queue) +{ + struct ixgbe_hw *hw= IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t etqf, etqs; + + if (hw->mac.type != ixgbe_mac_82599EB) + return -ENOSYS; + + if (index >= IXGBE_MAX_ETQF_FILTERS) + return (-EINVAL); + + etqf = IXGBE_READ_REG(hw, IXGBE_ETQF(index)); + etqs = IXGBE_READ_REG(hw, IXGBE_ETQS(index)); + if (etqf & IXGBE_ETQF_FILTER_EN){ + filter->ethertype = etqf & IXGBE_ETQF_ETHERTYPE; + filter->priority_en = (etqf & IXGBE_ETQF_UP_EN)? 1 : 0; + if (filter->priority_en) + filter->priority = (etqf & IXGBE_ETQF_UP) >> 16; + *rx_queue = (etqs & IXGBE_ETQS_RX_QUEUE) >> IXGBE_ETQS_RX_QUEUE_SHIFT; + return 0; + } + + return (-ENOENT); +} + +/* + * add a 5tuple filter + * + * @param + * dev: Pointer to struct rte_eth_dev. + * index: the index the filter allocates + * filter: ponter to the filter that will be added + * rx_queue: the queue id the filter assigned to + * + * @return + * - On success, zero. + * - On failure, a negative value. + */ +static int +ixgbe_add_5tuple_filter(struct rte_eth_dev *dev, uint16_t index, + struct rte_5tuple_filter *filter, uint8_t rx_queue) +{ + struct ixgbe_hw *hw= IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t ftqf, sdpqf = 0; + uint32_t l34timir = 0; + + if (hw->mac.type != ixgbe_mac_82599EB) + return -ENOSYS; + + if (index >= IXGBE_MAX_FTQF_FILTERS || rx_queue >= IXGBE_MAX_RX_QUEUE_NUM || + filter->priority > IXGBE_5TUPLE_MAX_PRI || + filter->priority < IXGBE_5TUPLE_MIN_PRI) + return (-EINVAL); /** filter index is out of range*/ + + ftqf = IXGBE_READ_REG(hw, IXGBE_FTQF(index)); + if (ftqf & IXGBR_FTQF_ENABLE) + return (-EINVAL); /** filter index is in use*/ + ftqf = 0; + + sdpqf = (uint32_t)(filter->dst_port << IXGBE_SDQPF_DSTPORT_SHIFT); + sdpqf = sdpqf |(filter->src_port & IXGBE_SDQPF_SRCPORT); + + ftqf |= (uint32_t)(filter->l4type & IXGBR_FTQF_PROTOCOL); + ftqf |= (uint32_t)((filter->priority << IXGBR_FTQF_PRIORITY_SHIFT) & IXGBR_FTQF_PRIORITY); + if (filter->src_ip_mask == 1) /** 1b means not compare*/ + ftqf |= IXGBR_FTQF_SRCIP_MASK; + if (filter->dst_ip_mask == 1) + ftqf |= IXGBR_FTQF_DSTIP_MASK; + if (filter->src_port_mask == 1) + ftqf |= IXGBR_FTQF_SRCPORT_MASK; + if (filter->dst_port_mask == 1) + ftqf |= IXGBR_FTQF_DSTPORT_MASK; + if (filter->l4type_mask == 1) + ftqf |= IXGBR_FTQF_L4TYPE_MASK; + ftqf |= IXGBR_FTQF_POOL_MASK; + ftqf |= IXGBR_FTQF_ENABLE; + + IXGBE_WRITE_REG(hw, IXGBE_DAQF(index), filter->dst_ip); + IXGBE_WRITE_REG(hw, IXGBE_SAQF(index), filter->src_ip); + IXGBE_WRITE_REG(hw, IXGBE_SDPQF(index), sdpqf); + IXGBE_WRITE_REG(hw, IXGBE_FTQF(index), ftqf); + + l34timir |= IXGBE_L34T_IMIR_RESERVE ; + l34timir |= (uint32_t)(rx_queue << IXGBE_L34T_IMIR_QUEUE_SHIFT); + IXGBE_WRITE_REG(hw, IXGBE_L34T_IMIR(index), l34timir); + + return 0; +} + +/* + * remove a 5tuple filter + * + * @param + * dev: Pointer to struct rte_eth_dev. + * index: the index the filter allocates + * + * @return + * - On success, zero. + * - On failure, a negative value. + */ +static int +ixgbe_remove_5tuple_filter(struct rte_eth_dev *dev, + uint16_t index) +{ + struct ixgbe_hw *hw= IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + if (hw->mac.type != ixgbe_mac_82599EB) + return -ENOSYS; + + if (index >= IXGBE_MAX_FTQF_FILTERS) + return (-EINVAL); /** filter index is out of range*/ + + IXGBE_WRITE_REG(hw, IXGBE_DAQF(index), 0); + IXGBE_WRITE_REG(hw, IXGBE_SAQF(index), 0); + IXGBE_WRITE_REG(hw, IXGBE_SDPQF(index), 0); + IXGBE_WRITE_REG(hw, IXGBE_FTQF(index), 0); + IXGBE_WRITE_REG(hw, IXGBE_FTQF(index), 0); + IXGBE_WRITE_REG(hw, IXGBE_L34T_IMIR(index), 0); + return 0; + +} + +/* + * get a 5tuple filter + * + * @param + * dev: Pointer to struct rte_eth_dev. + * index: the index the filter allocates + * filter: ponter to the filter that returns + * *rx_queue: pointer of the queue id the filter assigned to + * + * @return + * - On success, zero. + * - On failure, a negative value. + */ +static int +ixgbe_get_5tuple_filter(struct rte_eth_dev *dev, uint16_t index, + struct rte_5tuple_filter *filter, uint8_t *rx_queue) +{ + struct ixgbe_hw *hw= IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t sdpqf, ftqf, l34timir; + + if (hw->mac.type != ixgbe_mac_82599EB) + return -ENOSYS; + + if (index >= IXGBE_MAX_FTQF_FILTERS) + return (-EINVAL); /** filter index is out of range*/ + + ftqf = IXGBE_READ_REG(hw, IXGBE_FTQF(index)); + if (ftqf & IXGBR_FTQF_ENABLE){ + filter->l4type = (enum rte_filter_l4type)(ftqf & IXGBR_FTQF_PROTOCOL); + filter->priority = (ftqf & IXGBR_FTQF_PRIORITY) >> IXGBR_FTQF_PRIORITY_SHIFT; + filter->src_ip_mask = (ftqf & IXGBR_FTQF_SRCIP_MASK) ? 1 : 0; + filter->dst_ip_mask = (ftqf & IXGBR_FTQF_DSTIP_MASK) ? 1 : 0; + filter->src_port_mask = (ftqf & IXGBR_FTQF_SRCPORT_MASK) ? 1 : 0; + filter->dst_port_mask = (ftqf & IXGBR_FTQF_DSTPORT_MASK) ? 1 : 0; + filter->l4type_mask = (ftqf & IXGBR_FTQF_L4TYPE_MASK) ? 1 : 0; + + sdpqf = IXGBE_READ_REG(hw, IXGBE_SDPQF(index)); + filter->dst_port = (sdpqf & IXGBE_SDQPF_DSTPORT) >> IXGBE_SDQPF_DSTPORT_SHIFT; + filter->src_port = sdpqf & IXGBE_SDQPF_SRCPORT; + filter->dst_ip = IXGBE_READ_REG(hw, IXGBE_DAQF(index)); + filter->src_ip = IXGBE_READ_REG(hw, IXGBE_SAQF(index)); + + l34timir = IXGBE_READ_REG(hw, IXGBE_L34T_IMIR(index)); + *rx_queue = (l34timir & IXGBE_L34T_IMIR_QUEUE) >> IXGBE_L34T_IMIR_QUEUE_SHIFT; + return 0; + } + return (-ENOENT); +} diff --git a/lib/librte_pmd_ixgbe/ixgbe_ethdev.h b/lib/librte_pmd_ixgbe/ixgbe_ethdev.h index 9d7e93f..7c6139b 100644 --- a/lib/librte_pmd_ixgbe/ixgbe_ethdev.h +++ b/lib/librte_pmd_ixgbe/ixgbe_ethdev.h @@ -67,6 +67,39 @@ #define IXGBE_LPBK_82599_NONE 0x0 /* Default value. Loopback is disabled. */ #define IXGBE_LPBK_82599_TX_RX 0x1 /* Tx->Rx loopback operation is enabled. */ +#define IXGBE_SYN_FILTER_ENABLE 0x00000001 /** syn filter enable field*/ +#define IXGBE_SYN_FILTER_QUEUE 0x000000FE /** syn filter queue field*/ +#define IXGBE_SYN_FILTER_QUEUE_SHIFT 1 /** syn filter queue field shift*/ +#define IXGBE_SYN_FILTER_SYNQFP 0x80000000 /**syn filter SYNQFP*/ + +#define IXGBE_ETQF_UP 0x00070000 /** ethertype filter priority field*/ +#define IXGBE_ETQF_SHIFT 16 +#define IXGBE_ETQF_UP_EN 0x00080000 +#define IXGBE_ETQF_ETHERTYPE 0x0000FFFF /** ethertype filter ethertype field*/ +#define IXGBE_ETQF_MAX_PRI 7 + +#define IXGBE_SDQPF_DSTPORT 0xFFFF0000 /** dst port field */ +#define IXGBE_SDQPF_DSTPORT_SHIFT 16 /** dst port field shift*/ +#define IXGBE_SDQPF_SRCPORT 0x0000FFFF /** src port field */ +#define IXGBR_FTQF_PROTOCOL 0x00000003 /** protocol */ +#define IXGBR_FTQF_PRIORITY 0x0000001C /** priority */ +#define IXGBR_FTQF_PRIORITY_SHIFT 2 +#define IXGBR_FTQF_SRCIP_MASK 0x02000000 /** src IP mask */ +#define IXGBR_FTQF_DSTIP_MASK 0x04000000 /** dst IP mask */ +#define IXGBR_FTQF_SRCPORT_MASK 0x08000000 /** src port mask */ +#define IXGBR_FTQF_DSTPORT_MASK 0x10000000 /** dst port mask */ +#define IXGBR_FTQF_L4TYPE_MASK 0x20000000 /** protocol mask */ +#define IXGBR_FTQF_POOL_MASK 0x40000000 /** pool mask */ +#define IXGBR_FTQF_ENABLE 0x80000000 /** enable bit */ +#define IXGBR_FTQF_PRIORITY_DEFAULT 0x00000004 +#define IXGBE_L34T_IMIR_SIZE_BP 0x00001000 +#define IXGBE_L34T_IMIR_RESERVE 0x00080000 /** bit 13 to 19 must be set to 1000000b*/ +#define IXGBE_L34T_IMIR_LLI 0x00100000 +#define IXGBE_L34T_IMIR_QUEUE 0x0FE00000 +#define IXGBE_L34T_IMIR_QUEUE_SHIFT 21 +#define IXGBE_5TUPLE_MAX_PRI 7 +#define IXGBE_5TUPLE_MIN_PRI 1 + /* * Information about the fdir mode. */ -- 1.8.1.4