flow: add RSS support 21/25721/2
authorChenmin Sun <chenmin.sun@intel.com>
Fri, 28 Feb 2020 14:49:37 +0000 (22:49 +0800)
committerDamjan Marion <dmarion@me.com>
Tue, 28 Apr 2020 21:13:50 +0000 (21:13 +0000)
This patch enables the RSS configuration through vnet/flow interface
With this RSS feature, users can config the RSS functions for specific flows

Currently, it supports:
  default, toeplitz and symmetric_toeplitz rss function, and
  ipv4-tcp/ipv4-udp/ipv6-tcp/ipv6-ucp flow types

Users can use the following options to combine with above flow
types for more specific hash input set selection:
  l3-src-only, l3-dst-only, l4-src-only, l4-dst-only

Command line:
test flow add dst-ip any proto udp rss function default rss types ipv4-tcp use l3-dst-only
test flow add dst-ip any proto udp rss function toeplitz rss types ipv4-udp use l4-src-only
test flow add dst-ip any proto udp rss function symmetric_toeplitz rss types ipv6-udp use l3-src-only and l3-dst-only

Type: feature

Signed-off-by: Chenmin Sun <chenmin.sun@intel.com>
Change-Id: I213efc76dc8af37f2f63605884f353e05b0f5d2a

src/plugins/dpdk/device/dpdk.h
src/plugins/dpdk/device/flow.c
src/plugins/dpdk/device/format.c
src/plugins/dpdk/device/init.c
src/vnet/flow/flow.h
src/vnet/flow/flow_cli.c

index a044181..46d36a2 100644 (file)
@@ -410,6 +410,33 @@ typedef enum
 
 void dpdk_update_link_state (dpdk_device_t * xd, f64 now);
 
+#define foreach_dpdk_rss_hf                    \
+  _(0, ETH_RSS_FRAG_IPV4,           "ipv4-frag")    \
+  _(1, ETH_RSS_NONFRAG_IPV4_TCP,    "ipv4-tcp")     \
+  _(2, ETH_RSS_NONFRAG_IPV4_UDP,    "ipv4-udp")     \
+  _(3, ETH_RSS_NONFRAG_IPV4_SCTP,   "ipv4-sctp")    \
+  _(4, ETH_RSS_NONFRAG_IPV4_OTHER,  "ipv4-other")   \
+  _(5, ETH_RSS_IPV4,                "ipv4")         \
+  _(6, ETH_RSS_IPV6_TCP_EX,         "ipv6-tcp-ex")  \
+  _(7, ETH_RSS_IPV6_UDP_EX,         "ipv6-udp-ex")  \
+  _(8, ETH_RSS_FRAG_IPV6,           "ipv6-frag")    \
+  _(9, ETH_RSS_NONFRAG_IPV6_TCP,    "ipv6-tcp")     \
+  _(10, ETH_RSS_NONFRAG_IPV6_UDP,   "ipv6-udp")     \
+  _(11, ETH_RSS_NONFRAG_IPV6_SCTP,  "ipv6-sctp")    \
+  _(12, ETH_RSS_NONFRAG_IPV6_OTHER, "ipv6-other")   \
+  _(13, ETH_RSS_IPV6_EX,            "ipv6-ex")      \
+  _(14, ETH_RSS_IPV6,               "ipv6")         \
+  _(15, ETH_RSS_L2_PAYLOAD,         "l2-payload")   \
+  _(16, ETH_RSS_PORT,               "port")         \
+  _(17, ETH_RSS_VXLAN,              "vxlan")        \
+  _(18, ETH_RSS_GENEVE,             "geneve")       \
+  _(19, ETH_RSS_NVGRE,              "nvgre")        \
+  _(20, ETH_RSS_GTPU,               "gtpu")         \
+  _(60, ETH_RSS_L4_DST_ONLY,        "l4-dst-only")  \
+  _(61, ETH_RSS_L4_SRC_ONLY,        "l4-src-only")  \
+  _(62, ETH_RSS_L3_DST_ONLY,        "l3-dst-only")  \
+  _(63, ETH_RSS_L3_SRC_ONLY,        "l3-src-only")
+
 format_function_t format_dpdk_device_name;
 format_function_t format_dpdk_device;
 format_function_t format_dpdk_device_errors;
index 279468f..444a76e 100644 (file)
@@ -61,6 +61,24 @@ mac_address_is_all_zero (const u8 addr[6])
   return true;
 }
 
+static inline void
+dpdk_flow_convert_rss_types (u64 type, u64 * dpdk_rss_type)
+{
+#define BIT_IS_SET(v, b) \
+  ((v) & (u64)1<<(b))
+
+  *dpdk_rss_type = 0;
+
+#undef _
+#define _(n, f, s) \
+      if (n != -1 && BIT_IS_SET(type, n)) \
+        *dpdk_rss_type |= f;
+
+  foreach_dpdk_rss_hf
+#undef _
+    return;
+}
+
 static int
 dpdk_flow_add (dpdk_device_t * xd, vnet_flow_t * f, dpdk_flow_entry_t * fe)
 {
@@ -74,6 +92,7 @@ dpdk_flow_add (dpdk_device_t * xd, vnet_flow_t * f, dpdk_flow_entry_t * fe)
   struct rte_flow_item_gtp gtp[2] = { };
   struct rte_flow_action_mark mark = { 0 };
   struct rte_flow_action_queue queue = { 0 };
+  struct rte_flow_action_rss rss = { 0 };
   struct rte_flow_item *item, *items = 0;
   struct rte_flow_action *action, *actions = 0;
   bool fate = false;
@@ -265,13 +284,15 @@ dpdk_flow_add (dpdk_device_t * xd, vnet_flow_t * f, dpdk_flow_entry_t * fe)
          item->spec = NULL;
          item->mask = NULL;
        }
-
-      tcp[0].hdr.src_port = clib_host_to_net_u16 (src_port);
-      tcp[1].hdr.src_port = clib_host_to_net_u16 (src_port_mask);
-      tcp[0].hdr.dst_port = clib_host_to_net_u16 (dst_port);
-      tcp[1].hdr.dst_port = clib_host_to_net_u16 (dst_port_mask);
-      item->spec = tcp;
-      item->mask = tcp + 1;
+      else
+       {
+         tcp[0].hdr.src_port = clib_host_to_net_u16 (src_port);
+         tcp[1].hdr.src_port = clib_host_to_net_u16 (src_port_mask);
+         tcp[0].hdr.dst_port = clib_host_to_net_u16 (dst_port);
+         tcp[1].hdr.dst_port = clib_host_to_net_u16 (dst_port_mask);
+         item->spec = tcp;
+         item->mask = tcp + 1;
+       }
     }
   else
     {
@@ -504,6 +525,27 @@ pattern_end:
     {
       vec_add2 (actions, action, 1);
       action->type = RTE_FLOW_ACTION_TYPE_DROP;
+      if (fate == true)
+       {
+         rv = VNET_FLOW_ERROR_INTERNAL;
+         goto done;
+       }
+      else
+       fate = true;
+    }
+  if (f->actions & VNET_FLOW_ACTION_RSS)
+    {
+      u64 rss_type = 0;
+      vec_add2 (actions, action, 1);
+      action->type = RTE_FLOW_ACTION_TYPE_RSS;
+      action->conf = &rss;
+
+      /* convert types to DPDK rss bitmask */
+      dpdk_flow_convert_rss_types (f->rss_types, &rss_type);
+
+      rss.types = rss_type;
+      rss.func = f->rss_fun;
+
       if (fate == true)
        {
          rv = VNET_FLOW_ERROR_INTERNAL;
index 3d6e80f..dad1505 100644 (file)
   _ (tx_bytes_ok, q_obytes)                     \
   _ (rx_errors, q_errors)
 
-#define foreach_dpdk_rss_hf                    \
-  _(ETH_RSS_FRAG_IPV4,          "ipv4-frag")   \
-  _(ETH_RSS_NONFRAG_IPV4_TCP,   "ipv4-tcp")    \
-  _(ETH_RSS_NONFRAG_IPV4_UDP,   "ipv4-udp")    \
-  _(ETH_RSS_NONFRAG_IPV4_SCTP,  "ipv4-sctp")   \
-  _(ETH_RSS_NONFRAG_IPV4_OTHER, "ipv4-other")  \
-  _(ETH_RSS_IPV4,               "ipv4")        \
-  _(ETH_RSS_IPV6_TCP_EX,        "ipv6-tcp-ex") \
-  _(ETH_RSS_IPV6_UDP_EX,        "ipv6-udp-ex") \
-  _(ETH_RSS_FRAG_IPV6,          "ipv6-frag")   \
-  _(ETH_RSS_NONFRAG_IPV6_TCP,   "ipv6-tcp")    \
-  _(ETH_RSS_NONFRAG_IPV6_UDP,   "ipv6-udp")    \
-  _(ETH_RSS_NONFRAG_IPV6_SCTP,  "ipv6-sctp")   \
-  _(ETH_RSS_NONFRAG_IPV6_OTHER, "ipv6-other")  \
-  _(ETH_RSS_IPV6_EX,            "ipv6-ex")     \
-  _(ETH_RSS_IPV6,               "ipv6")        \
-  _(ETH_RSS_L2_PAYLOAD,         "l2-payload")  \
-  _(ETH_RSS_PORT,               "port")        \
-  _(ETH_RSS_VXLAN,              "vxlan")       \
-  _(ETH_RSS_GENEVE,             "geneve")      \
-  _(ETH_RSS_NVGRE,              "nvgre")
-
 #define foreach_dpdk_pkt_rx_offload_flag                                \
   _ (PKT_RX_VLAN, "RX packet is a 802.1q VLAN packet")                  \
   _ (PKT_RX_RSS_HASH, "RX packet with RSS hash result")                 \
@@ -402,7 +380,7 @@ format_dpdk_link_status (u8 * s, va_list * args)
   return s;
 }
 
-#define _(v, str)                                            \
+#define _(n, v, str)                                            \
 if (bitmap & v) {                                            \
   if (format_get_indent (s) > 72)                            \
     s = format(s,"\n%U", format_white_space, indent);        \
@@ -947,7 +925,7 @@ unformat_rss_fn (unformat_input_t * input, uword * rss_fn)
       if (0)
        ;
 #undef _
-#define _(f, s)                                 \
+#define _(n, f, s)                                 \
       else if (unformat (input, s))             \
         *rss_fn |= f;
 
index 2922ed3..a9e7393 100644 (file)
@@ -440,7 +440,8 @@ dpdk_lib_init (dpdk_main_t * dm)
                VNET_FLOW_ACTION_REDIRECT_TO_NODE |
                VNET_FLOW_ACTION_REDIRECT_TO_QUEUE |
                VNET_FLOW_ACTION_BUFFER_ADVANCE |
-               VNET_FLOW_ACTION_COUNT | VNET_FLOW_ACTION_DROP;
+               VNET_FLOW_ACTION_COUNT | VNET_FLOW_ACTION_DROP |
+               VNET_FLOW_ACTION_RSS;
 
              if (dm->conf->no_tx_checksum_offload == 0)
                {
index bd62135..d6850b2 100644 (file)
   _(2, BUFFER_ADVANCE, "buffer-advance") \
   _(3, REDIRECT_TO_NODE, "redirect-to-node") \
   _(4, REDIRECT_TO_QUEUE, "redirect-to-queue") \
-  _(5, DROP, "drop")
+  _(5, RSS, "rss") \
+  _(6, DROP, "drop")
 
 typedef enum
 {
@@ -147,6 +148,39 @@ typedef enum
   _( -5, NO_SUCH_INTERFACE, "no such interface")               \
   _( -6, INTERNAL, "internal error")
 
+#define foreach_flow_rss_types                    \
+  _(0, FRAG_IPV4,          "ipv4-frag")   \
+  _(1, IPV4_TCP,           "ipv4-tcp")    \
+  _(2, IPV4_UDP,           "ipv4-udp")    \
+  _(3, IPV4_SCTP,          "ipv4-sctp")   \
+  _(4, IPV4_OTHER,         "ipv4-other")  \
+  _(5, IPV4,               "ipv4")        \
+  _(6, IPV6_TCP_EX,        "ipv6-tcp-ex") \
+  _(7, IPV6_UDP_EX,        "ipv6-udp-ex") \
+  _(8, FRAG_IPV6,          "ipv6-frag")   \
+  _(9, IPV6_TCP,           "ipv6-tcp")    \
+  _(10, IPV6_UDP,          "ipv6-udp")    \
+  _(11, IPV6_SCTP,         "ipv6-sctp")   \
+  _(12, IPV6_OTHER,        "ipv6-other")  \
+  _(13, IPV6_EX,           "ipv6-ex")     \
+  _(14, IPV6,              "ipv6")        \
+  _(15, L2_PAYLOAD,        "l2-payload")  \
+  _(16, PORT,              "port")        \
+  _(17, VXLAN,             "vxlan")       \
+  _(18, GENEVE,            "geneve")      \
+  _(19, NVGRE,             "nvgre")       \
+  _(20, GTPU,              "gtpu")        \
+  _(60, L4_DST_ONLY,       "l4-dst-only") \
+  _(61, L4_SRC_ONLY,       "l4-src-only") \
+  _(62, L3_DST_ONLY,       "l3-dst-only") \
+  _(63, L3_SRC_ONLY,       "l3-src-only")
+
+#define foreach_rss_function           \
+  _(DEFAULT, "default")                \
+  _(TOEPLITZ, "toeplitz")              \
+  _(SIMPLE_XOR, "simple_xor")          \
+  _(SYMMETRIC_TOEPLITZ, "symmetric_toeplitz")
+
 typedef enum
 {
   VNET_FLOW_NO_ERROR = 0,
@@ -169,6 +203,13 @@ typedef enum
     VNET_FLOW_N_TYPES,
 } vnet_flow_type_t;
 
+typedef enum
+{
+#define _(a,b) VNET_RSS_FUNC_##a,
+  foreach_rss_function
+#undef _
+    VNET_RSS_N_TYPES,
+} vnet_rss_function_t;
 
 /*
  * Create typedef struct vnet_flow_XXX_t
@@ -208,6 +249,12 @@ typedef struct
   /* buffer offset for VNET_FLOW_ACTION_BUFFER_ADVANCE */
   i32 buffer_advance;
 
+  /* RSS types, including IPv4/IPv6/TCP/UDP... */
+  u64 rss_types;
+
+  /* RSS functions, including IPv4/IPv6/TCP/UDP... */
+  vnet_rss_function_t rss_fun;
+
   union
   {
 #define _(a,b,c) vnet_flow_##b##_t b;
index 500f16b..772f89a 100644 (file)
@@ -296,6 +296,8 @@ test_flow (vlib_main_t * vm, unformat_input_t * input,
   ip_port_and_mask_t dport = { };
   u16 eth_type;
   bool ethernet_set = false;
+  u8 *rss_type[3] = { };
+  u8 *type_str = NULL;
 
   clib_memset (&flow, 0, sizeof (vnet_flow_t));
   flow.index = ~0;
@@ -370,6 +372,65 @@ test_flow (vlib_main_t * vm, unformat_input_t * input,
        flow.actions |= VNET_FLOW_ACTION_REDIRECT_TO_QUEUE;
       else if (unformat (line_input, "drop"))
        flow.actions |= VNET_FLOW_ACTION_DROP;
+      else if (unformat (line_input, "rss function"))
+       {
+         if (0)
+           ;
+#undef _
+#define _(f, s)                                 \
+        else if (unformat (line_input, s)) \
+          flow.rss_fun = VNET_RSS_FUNC_##f;
+
+         foreach_rss_function
+#undef _
+           else
+           {
+             return clib_error_return (0, "unknown input `%U'",
+                                       format_unformat_error, line_input);
+           }
+
+         flow.actions |= VNET_FLOW_ACTION_RSS;
+       }
+      else if (unformat (line_input, "rss types"))
+       {
+         rss_type[0] = NULL;
+         rss_type[1] = NULL;
+         rss_type[2] = NULL;
+         type_str = NULL;
+
+         if (unformat (line_input, "%s use %s and %s",
+                       &rss_type[0], &rss_type[1], &rss_type[2]))
+           ;
+         else
+           if (unformat
+               (line_input, "%s use %s", &rss_type[0], &rss_type[1]))
+           ;
+         else if (unformat (line_input, "%s", &rss_type[0]))
+           ;
+
+#undef _
+#define _(a,b,c)     \
+        else if (!clib_strcmp(c, (const char *)type_str)) \
+          flow.rss_types |= (1ULL<<a);
+
+#define check_rss_types(_str)     \
+        if (_str != NULL) {\
+          type_str = _str;\
+          if (0) \
+                 ; \
+          foreach_flow_rss_types \
+          else \
+          { \
+            return clib_error_return (0, "parse error: '%U'", \
+              format_unformat_error, line_input); \
+          } \
+        }
+
+         check_rss_types (rss_type[0])
+           check_rss_types (rss_type[1]) check_rss_types (rss_type[2])
+#undef _
+           flow.actions |= VNET_FLOW_ACTION_RSS;
+       }
       else if (unformat (line_input, "%U", unformat_vnet_hw_interface, vnm,
                         &hw_if_index))
        ;
@@ -545,7 +606,7 @@ test_flow (vlib_main_t * vm, unformat_input_t * input,
 
          if (flow.ip6_n_tuple.protocol == (ip_protocol_t) ~ 0)
            return clib_error_return (0, "Please specify ip protocol");
-         if ((type != VNET_FLOW_TYPE_IP4_N_TUPLE) &&
+         if ((type != VNET_FLOW_TYPE_IP6_N_TUPLE) &&
              (flow.ip6_n_tuple.protocol != IP_PROTOCOL_UDP))
            return clib_error_return (0,
                                      "For GTP related flow, ip protocol must be UDP");