ethdev: RSS RETA configuration
authorIntel <intel.com>
Mon, 3 Jun 2013 00:00:00 +0000 (00:00 +0000)
committerThomas Monjalon <thomas.monjalon@6wind.com>
Tue, 17 Sep 2013 12:16:07 +0000 (14:16 +0200)
Signed-off-by: Intel
app/test-pmd/cmdline.c
app/test-pmd/config.c
app/test-pmd/rxonly.c
app/test-pmd/testpmd.h
lib/librte_ether/rte_ethdev.c
lib/librte_ether/rte_ethdev.h

index f909597..9c1bda9 100644 (file)
@@ -405,6 +405,9 @@ static void cmd_help_long_parsed(void *parsed_result,
                        "port config all rss (ip|udp|none)\n"
                        "    Set the RSS mode.\n\n"
 
+                       "port config port-id rss reta (hash,queue)[,(hash,queue)]\n"
+                       "    Set the RSS redirection table.\n\n"
+
                        "port config (port_id) dcb vt (on|off) (traffic_class)"
                        " pfc (on|off)\n"
                        "    Set the DCB mode.\n\n"
@@ -1079,6 +1082,182 @@ cmdline_parse_inst_t cmd_config_rss = {
        },
 };
 
+/* *** Configure RSS RETA *** */
+struct cmd_config_rss_reta {
+       cmdline_fixed_string_t port;
+       cmdline_fixed_string_t keyword;
+       uint8_t port_id;
+       cmdline_fixed_string_t name;
+       cmdline_fixed_string_t list_name;
+       cmdline_fixed_string_t list_of_items;
+};
+
+static int
+parse_reta_config(const char *str, struct rte_eth_rss_reta *reta_conf)
+{
+       int i;
+       unsigned size;
+       uint8_t hash_index;
+       uint8_t nb_queue;
+       char s[256];
+       const char *p, *p0 = str;
+       char *end;
+       enum fieldnames {
+               FLD_HASH_INDEX = 0,
+               FLD_QUEUE,
+               _NUM_FLD
+       };
+       unsigned long int_fld[_NUM_FLD];
+       char *str_fld[_NUM_FLD];
+
+       while ((p = strchr(p0,'(')) != NULL) {
+               ++p;
+               if((p0 = strchr(p,')')) == NULL)
+                       return -1;
+
+               size = p0 - p;
+               if(size >= sizeof(s))
+                       return -1;
+
+               rte_snprintf(s, sizeof(s), "%.*s", size, p);
+               if (rte_strsplit(s, sizeof(s), str_fld, _NUM_FLD, ',') != _NUM_FLD)
+                       return -1;
+               for (i = 0; i < _NUM_FLD; i++) {
+                       errno = 0;
+                       int_fld[i] = strtoul(str_fld[i], &end, 0);
+                       if (errno != 0 || end == str_fld[i] || int_fld[i] > 255)
+                               return -1;
+               }
+
+               hash_index = (uint8_t)int_fld[FLD_HASH_INDEX];
+               nb_queue = (uint8_t)int_fld[FLD_QUEUE];
+
+               if (hash_index >= ETH_RSS_RETA_NUM_ENTRIES) {
+                       printf("Invalid RETA hash index=%d",hash_index);
+                       return -1;
+               }
+
+               if (hash_index < ETH_RSS_RETA_NUM_ENTRIES/2)
+                       reta_conf->mask_lo |= (1ULL << hash_index);
+               else
+                       reta_conf->mask_hi |= (1ULL << (hash_index - ETH_RSS_RETA_NUM_ENTRIES/2));
+
+               reta_conf->reta[hash_index] = nb_queue;
+       }
+
+       return 0;
+}
+
+static void
+cmd_set_rss_reta_parsed(void *parsed_result,
+                               __attribute__((unused)) struct cmdline *cl,
+                               __attribute__((unused)) void *data)
+{
+       int ret;
+       struct rte_eth_rss_reta reta_conf;
+       struct cmd_config_rss_reta *res = parsed_result;
+
+       memset(&reta_conf,0,sizeof(struct rte_eth_rss_reta));
+       if (!strcmp(res->list_name, "reta")) {
+               if (parse_reta_config(res->list_of_items, &reta_conf)) {
+                       printf("Invalid RSS Redirection Table config entered\n");
+                       return;
+               }
+               ret = rte_eth_dev_rss_reta_update(res->port_id, &reta_conf);
+               if (ret != 0)
+                       printf("Bad redirection table parameter, return code = %d \n",ret);
+       }
+}
+
+cmdline_parse_token_string_t cmd_config_rss_reta_port =
+       TOKEN_STRING_INITIALIZER(struct cmd_config_rss_reta, port, "port");
+cmdline_parse_token_string_t cmd_config_rss_reta_keyword =
+       TOKEN_STRING_INITIALIZER(struct cmd_config_rss_reta, keyword, "config");
+cmdline_parse_token_num_t cmd_config_rss_reta_port_id =
+       TOKEN_NUM_INITIALIZER(struct cmd_config_rss_reta, port_id, UINT8);
+cmdline_parse_token_string_t cmd_config_rss_reta_name =
+       TOKEN_STRING_INITIALIZER(struct cmd_config_rss_reta, name, "rss");
+cmdline_parse_token_string_t cmd_config_rss_reta_list_name =
+       TOKEN_STRING_INITIALIZER(struct cmd_config_rss_reta, list_name, "reta");
+cmdline_parse_token_string_t cmd_config_rss_reta_list_of_items =
+        TOKEN_STRING_INITIALIZER(struct cmd_config_rss_reta, list_of_items,
+                                 NULL);
+cmdline_parse_inst_t cmd_config_rss_reta = {
+       .f = cmd_set_rss_reta_parsed,
+       .data = NULL,
+       .help_str = "port config X rss reta (hash,queue)[,(hash,queue)]",
+       .tokens = {
+               (void *)&cmd_config_rss_reta_port,
+               (void *)&cmd_config_rss_reta_keyword,
+               (void *)&cmd_config_rss_reta_port_id,
+               (void *)&cmd_config_rss_reta_name,
+               (void *)&cmd_config_rss_reta_list_name,
+               (void *)&cmd_config_rss_reta_list_of_items,
+               NULL,
+       },
+};
+
+/* *** SHOW PORT INFO *** */
+struct cmd_showport_reta {
+       cmdline_fixed_string_t show;
+       cmdline_fixed_string_t port;
+       uint8_t port_id;
+       cmdline_fixed_string_t rss;
+       cmdline_fixed_string_t reta;
+       uint64_t mask_lo;
+       uint64_t mask_hi;
+};
+
+static void cmd_showport_reta_parsed(void *parsed_result,
+                               __attribute__((unused)) struct cmdline *cl,
+                               __attribute__((unused)) void *data)
+{
+       struct cmd_showport_reta *res = parsed_result;
+       struct rte_eth_rss_reta reta_conf;
+
+       if ((res->mask_lo == 0) && (res->mask_hi == 0)) {
+               printf("Invalid RSS Redirection Table config entered\n");
+               return;
+       }
+
+       reta_conf.mask_lo = res->mask_lo;
+       reta_conf.mask_hi = res->mask_hi;
+
+       port_rss_reta_info(res->port_id,&reta_conf);
+}
+
+cmdline_parse_token_string_t cmd_showport_reta_show =
+        TOKEN_STRING_INITIALIZER(struct  cmd_showport_reta, show, "show");
+cmdline_parse_token_string_t cmd_showport_reta_port =
+        TOKEN_STRING_INITIALIZER(struct  cmd_showport_reta, port, "port");
+cmdline_parse_token_num_t cmd_showport_reta_port_id =
+        TOKEN_NUM_INITIALIZER(struct cmd_showport_reta, port_id, UINT8);
+cmdline_parse_token_string_t cmd_showport_reta_rss =
+        TOKEN_STRING_INITIALIZER(struct cmd_showport_reta, rss, "rss");
+cmdline_parse_token_string_t cmd_showport_reta_reta =
+        TOKEN_STRING_INITIALIZER(struct cmd_showport_reta, reta, "reta");
+cmdline_parse_token_num_t cmd_showport_reta_mask_lo =
+        TOKEN_NUM_INITIALIZER(struct cmd_showport_reta,mask_lo,UINT64);
+cmdline_parse_token_num_t cmd_showport_reta_mask_hi =
+       TOKEN_NUM_INITIALIZER(struct cmd_showport_reta,mask_hi,UINT64);
+
+cmdline_parse_inst_t cmd_showport_reta = {
+       .f = cmd_showport_reta_parsed,
+       .data = NULL,
+       .help_str = "show port X rss reta mask_lo mask_hi (X = port number)\n\
+                       (mask_lo and mask_hi is UINT64)",
+       .tokens = {
+               (void *)&cmd_showport_reta_show,
+               (void *)&cmd_showport_reta_port,
+               (void *)&cmd_showport_reta_port_id,
+               (void *)&cmd_showport_reta_rss,
+               (void *)&cmd_showport_reta_reta,
+               (void *)&cmd_showport_reta_mask_lo,
+               (void *)&cmd_showport_reta_mask_hi,
+               NULL,
+       },
+};
+
 /* *** Configure DCB *** */
 struct cmd_config_dcb {
        cmdline_fixed_string_t port;
@@ -3691,6 +3870,8 @@ cmdline_parse_ctx_t main_ctx[] = {
        (cmdline_parse_inst_t *)&cmd_config_max_pkt_len,
        (cmdline_parse_inst_t *)&cmd_config_rx_mode_flag,
        (cmdline_parse_inst_t *)&cmd_config_rss,
+       (cmdline_parse_inst_t *)&cmd_config_rss_reta,
+       (cmdline_parse_inst_t *)&cmd_showport_reta,
        (cmdline_parse_inst_t *)&cmd_config_burst,
        (cmdline_parse_inst_t *)&cmd_config_thresh,
        (cmdline_parse_inst_t *)&cmd_config_threshold,
index 2d18212..aaf8b9e 100644 (file)
@@ -640,6 +640,40 @@ rxtx_config_display(void)
               tx_rs_thresh, txq_flags);
 }
 
+void
+port_rss_reta_info(portid_t port_id,struct rte_eth_rss_reta *reta_conf)
+{
+       uint8_t i,j;
+       int ret;
+
+       if (port_id_is_invalid(port_id)) 
+               return;
+
+       ret = rte_eth_dev_rss_reta_query(port_id, reta_conf);
+       if (ret != 0) {
+               printf("Failed to get RSS RETA info, return code = %d\n", ret);
+               return;
+       }
+
+       if (reta_conf->mask_lo != 0) {
+               for (i = 0; i< ETH_RSS_RETA_NUM_ENTRIES/2; i++) {
+                       if (reta_conf->mask_lo & (uint64_t)(1ULL << i))
+                               printf("RSS RETA configuration: hash index=%d,"
+                                       "queue=%d\n",i,reta_conf->reta[i]);     
+               }
+       }
+       
+       if (reta_conf->mask_hi != 0) {
+               for (i = 0; i< ETH_RSS_RETA_NUM_ENTRIES/2; i++) {
+                       if(reta_conf->mask_hi & (uint64_t)(1ULL << i)) {
+                               j = (uint8_t)(i + ETH_RSS_RETA_NUM_ENTRIES/2);          
+                               printf("RSS RETA configuration: hash index=%d,"
+                                       "queue=%d\n",j,reta_conf->reta[j]);
+                       }
+               }
+       }
+}
+
 /*
  * Setup forwarding configuration for each logical core.
  */
index 8154c92..ed0c2db 100644 (file)
@@ -158,8 +158,10 @@ pkt_burst_receive(struct fwd_stream *fs)
                printf(" - type=0x%04x - length=%u - nb_segs=%d",
                       eth_type, (unsigned) mb->pkt.pkt_len,
                       (int)mb->pkt.nb_segs);
-               if (ol_flags & PKT_RX_RSS_HASH)
+               if (ol_flags & PKT_RX_RSS_HASH) {
                        printf(" - RSS hash=0x%x", (unsigned) mb->pkt.hash.rss);
+                       printf(" - RSS queue=0x%x",(unsigned) fs->rx_queue);
+               }
                else if (ol_flags & PKT_RX_FDIR)
                        printf(" - FDIR hash=0x%x - FDIR id=0x%x ",
                               mb->pkt.hash.fdir.hash, mb->pkt.hash.fdir.id);
index 0f05b2d..615a752 100644 (file)
@@ -506,6 +506,7 @@ void fdir_update_perfect_filter(portid_t port_id, uint16_t soft_id,
 void fdir_remove_perfect_filter(portid_t port_id, uint16_t soft_id,
                                struct rte_fdir_filter *fdir_filter);
 void fdir_set_masks(portid_t port_id, struct rte_fdir_masks *fdir_masks);
+void port_rss_reta_info(portid_t port_id, struct rte_eth_rss_reta *reta_conf);
 
 /*
  * Work-around of a compilation error with ICC on invocations of the
index 2fd8498..06fc251 100644 (file)
@@ -1416,6 +1416,78 @@ rte_eth_dev_priority_flow_ctrl_set(uint8_t port_id, struct rte_eth_pfc_conf *pfc
        return (-ENOTSUP);
 }
 
+int
+rte_eth_dev_rss_reta_update(uint8_t port_id, struct rte_eth_rss_reta *reta_conf)
+{
+       struct rte_eth_dev *dev;
+       uint8_t i,j;
+
+       if (port_id >= nb_ports) {
+               PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+               return (-ENODEV);
+       }
+
+       /* Invalid mask bit(s) setting */
+       if ((reta_conf->mask_lo == 0) && (reta_conf->mask_hi == 0)) {
+               PMD_DEBUG_TRACE("Invalid update mask bits for port=%d\n",port_id);
+               return (-EINVAL);
+       }
+
+       if (reta_conf->mask_lo != 0) {
+               for (i = 0; i < ETH_RSS_RETA_NUM_ENTRIES/2; i++) {
+                       if ((reta_conf->mask_lo & (1ULL << i)) &&
+                               (reta_conf->reta[i] >= ETH_RSS_RETA_MAX_QUEUE)) {
+                               PMD_DEBUG_TRACE("RETA hash index output"
+                                       "configration for port=%d,invalid"
+                                       "queue=%d\n",port_id,reta_conf->reta[i]);
+
+                               return (-EINVAL);
+                       } 
+               }
+       }
+
+       if (reta_conf->mask_hi != 0) {
+               for (i = 0; i< ETH_RSS_RETA_NUM_ENTRIES/2; i++) {       
+                       j = (uint8_t)(i + ETH_RSS_RETA_NUM_ENTRIES/2);
+
+                       /* Check if the max entry >= 128 */
+                       if ((reta_conf->mask_hi & (1ULL << i)) && 
+                               (reta_conf->reta[j] >= ETH_RSS_RETA_MAX_QUEUE)) {
+                               PMD_DEBUG_TRACE("RETA hash index output"
+                                       "configration for port=%d,invalid"
+                                       "queue=%d\n",port_id,reta_conf->reta[j]);
+
+                               return (-EINVAL);
+                       }
+               }
+       }
+
+       dev = &rte_eth_devices[port_id];
+
+       FUNC_PTR_OR_ERR_RET(*dev->dev_ops->reta_update, -ENOTSUP);
+       return (*dev->dev_ops->reta_update)(dev, reta_conf);
+}
+
+int 
+rte_eth_dev_rss_reta_query(uint8_t port_id, struct rte_eth_rss_reta *reta_conf)
+{
+       struct rte_eth_dev *dev;
+       
+       if (port_id >= nb_ports) {
+               PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+               return (-ENODEV);
+       }
+
+       if((reta_conf->mask_lo == 0) && (reta_conf->mask_hi == 0)) {
+               PMD_DEBUG_TRACE("Invalid update mask bits for the port=%d\n",port_id);
+               return (-EINVAL);
+       }
+
+       dev = &rte_eth_devices[port_id];
+       FUNC_PTR_OR_ERR_RET(*dev->dev_ops->reta_query, -ENOTSUP);
+       return (*dev->dev_ops->reta_query)(dev, reta_conf);
+}
+
 int
 rte_eth_led_on(uint8_t port_id)
 {
index 6c006d5..74b3a5b 100644 (file)
@@ -306,6 +306,9 @@ struct rte_eth_rss_conf {
 #define ETH_RSS_IPV4_UDP    0x0040 /**< IPv4/UDP packet. */
 #define ETH_RSS_IPV6_UDP    0x0080 /**< IPv6/UDP packet. */
 #define ETH_RSS_IPV6_UDP_EX 0x0100 /**< IPv6/UDP with extension headers. */
+/* Definitions used for redirection table entry size */
+#define ETH_RSS_RETA_NUM_ENTRIES 128
+#define ETH_RSS_RETA_MAX_QUEUE   16  
 
 /* Definitions used for VMDQ and DCB functionality */
 #define ETH_VMDQ_MAX_VLAN_FILTERS   64 /**< Maximum nb. of VMDQ vlan filters. */
@@ -327,6 +330,18 @@ struct rte_eth_rss_conf {
 #define ETH_VLAN_FILTER_MASK  0x0002 /**< VLAN Filter  setting mask*/
 #define ETH_VLAN_EXTEND_MASK  0x0004 /**< VLAN Extend  setting mask*/
 
+/**
+ * A structure used to configure Redirection Table of  the Receive Side
+ * Scaling (RSS) feature of an Ethernet port.
+ */
+struct rte_eth_rss_reta {
+       /** First 64 mask bits indicate which entry(s) need to updated/queried. */
+       uint64_t mask_lo; 
+       /** Second 64 mask bits indicate which entry(s) need to updated/queried. */
+       uint64_t mask_hi; 
+       uint8_t reta[ETH_RSS_RETA_NUM_ENTRIES];  /**< 128 RETA entries*/
+};
+
 /**
  * This enum indicates the possible number of traffic classes
  * in DCB configratioins
@@ -813,6 +828,14 @@ typedef int (*priority_flow_ctrl_set_t)(struct rte_eth_dev *dev,
                                struct rte_eth_pfc_conf *pfc_conf);
 /**< @internal Setup priority flow control parameter on an Ethernet device */
 
+typedef int (*reta_update_t)(struct rte_eth_dev *dev,
+                               struct rte_eth_rss_reta *reta_conf);
+/**< @internal Update RSS redirection table on an Ethernet device */
+
+typedef int (*reta_query_t)(struct rte_eth_dev *dev,
+                               struct rte_eth_rss_reta *reta_conf);
+/**< @internal Query RSS redirection table on an Ethernet device */
+
 typedef int (*eth_dev_led_on_t)(struct rte_eth_dev *dev);
 /**< @internal Turn on SW controllable LED on an Ethernet device */
 
@@ -877,6 +900,10 @@ struct eth_dev_ops {
        fdir_remove_perfect_filter_t fdir_remove_perfect_filter;
        /** Setup masks for FDIR filtering. */
        fdir_set_masks_t fdir_set_masks;
+       /** Update redirection table. */
+       reta_update_t reta_update;
+       /** Query redirection table. */
+       reta_query_t reta_query;
 };
 
 /**
@@ -2106,6 +2133,35 @@ int rte_eth_dev_mac_addr_add(uint8_t port, struct ether_addr *mac_addr,
  */
 int rte_eth_dev_mac_addr_remove(uint8_t port, struct ether_addr *mac_addr);
 
+/**
+ * Update Redirection Table(RETA) of Receive Side Scaling of Ethernet device.
+ * 
+ * @param port
+ *   The port identifier of the Ethernet device.
+ * @param reta_conf 
+ *    RETA to update.
+ * @return
+ *   - (0) if successful. 
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-EINVAL) if bad parameter.
+ */
+int rte_eth_dev_rss_reta_update(uint8_t port, 
+                       struct rte_eth_rss_reta *reta_conf);
+
+ /**
+ * Query Redirection Table(RETA) of Receive Side Scaling of Ethernet device.
+ *  
+ * @param port
+ *   The port identifier of the Ethernet device.
+ * @param reta_conf 
+ *   RETA to query.
+ * @return
+ *   - (0) if successful. 
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-EINVAL) if bad parameter.
+ */
+int rte_eth_dev_rss_reta_query(uint8_t port, 
+                       struct rte_eth_rss_reta *reta_conf);
 
 #ifdef __cplusplus
 }