"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"
        },
 };
 
+/* *** 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;
        (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,
 
        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)
 {
 
 #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. */
 #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
                                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 */
 
        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;
 };
 
 /**
  */
 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
 }