dev: add support for changing RSS key 01/43701/2
authorDamjan Marion <[email protected]>
Mon, 15 Sep 2025 17:35:48 +0000 (19:35 +0200)
committerFlorin Coras <[email protected]>
Mon, 15 Sep 2025 21:30:17 +0000 (21:30 +0000)
Type: improvement
Change-Id: I40350be4c362d20f60b94c82faf564f06d8e86f6
Signed-off-by: Damjan Marion <[email protected]>
src/vnet/dev/api.c
src/vnet/dev/api.h
src/vnet/dev/args.c
src/vnet/dev/cli.c
src/vnet/dev/config.c
src/vnet/dev/dev.h
src/vnet/dev/format.c
src/vnet/dev/port.c
src/vnet/dev/types.h

index 55c3de3..5787fe2 100644 (file)
@@ -344,3 +344,43 @@ vnet_dev_api_port_del_sec_if (vlib_main_t *vm,
     vm, port, vnet_dev_port_del_sec_if,
     &(vnet_dev_port_del_sec_if_args_t){ .sw_if_index = args->sw_if_index });
 }
+
+vnet_dev_rv_t
+vnet_dev_api_port_set_rss_key (vlib_main_t *vm,
+                              vnet_dev_api_port_set_rss_key_args_t *args)
+{
+  vnet_dev_port_t *port = 0;
+  vnet_dev_t *dev = vnet_dev_by_index (args->dev_index);
+  vnet_dev_rv_t rv = VNET_DEV_OK;
+  vnet_dev_port_cfg_change_req_t req = {
+    .type = VNET_DEV_PORT_CFG_SET_RSS_KEY,
+    .rss_key = args->rss_key,
+  };
+
+  if (!dev)
+    return VNET_DEV_ERR_UNKNOWN_DEVICE;
+
+  log_debug (dev, "port %u rss_key %U", args->port_id,
+            format_hex_bytes_no_wrap, args->rss_key.key,
+            args->rss_key.length);
+
+  port = vnet_dev_get_port_by_id (dev, args->port_id);
+  if (!port)
+    return VNET_DEV_ERR_UNKNOWN_DEVICE;
+
+  rv = vnet_dev_port_cfg_change_req_validate (vm, port, &req);
+  if (rv != VNET_DEV_OK)
+    {
+      log_err (dev, "RSS key cannot be set");
+      return rv;
+    }
+
+  rv = vnet_dev_process_port_cfg_change_req (vm, port, &req);
+  if (rv != VNET_DEV_OK)
+    {
+      log_err (dev, "device failed to set RSS key");
+      return rv;
+    }
+
+  return rv;
+}
index 3e552e4..24f2423 100644 (file)
@@ -88,4 +88,15 @@ vnet_dev_rv_t
 vnet_dev_api_port_del_sec_if (vlib_main_t *,
                              vnet_dev_api_port_del_sec_if_args_t *);
 
+typedef struct
+{
+  u32 dev_index;
+  vnet_dev_port_id_t port_id;
+  vnet_dev_rss_key_t rss_key;
+} vnet_dev_api_port_set_rss_key_args_t;
+
+vnet_dev_rv_t
+vnet_dev_api_port_set_rss_key (vlib_main_t *,
+                              vnet_dev_api_port_set_rss_key_args_t *);
+
 #endif /* _VNET_DEV_API_H_ */
index e302517..07d1078 100644 (file)
@@ -82,7 +82,7 @@ vnet_dev_arg_parse (vlib_main_t *vm, vnet_dev_t *dev, vnet_dev_arg_t *args,
       else if (a->type == VNET_DEV_ARG_TYPE_UINT32)
        {
          u32 val, min = 0, max = CLIB_U32_MAX;
-         if (!unformat (&in, "%u", &val))
+         if (!unformat (&in, "0x%x", &val) && !unformat (&in, "%u", &val))
            {
              err = format (0,
                            "unsigned integer in range %u - %u expected for "
index 6002a2f..90014f8 100644 (file)
@@ -418,3 +418,70 @@ VLIB_CLI_COMMAND (show_device_counters_cmd, static) = {
   .function = show_device_counters_cmd_fn,
   .is_mp_safe = 1,
 };
+
+static clib_error_t *
+device_set_rss_key_cmd_fn (vlib_main_t *vm, unformat_input_t *input,
+                          vlib_cli_command_t *cmd)
+{
+  vnet_dev_api_port_set_rss_key_args_t a = {};
+  vnet_dev_rv_t rv;
+  int device_id_set = 0;
+  int sw_if_index_set = 0;
+  vnet_dev_device_id_t device_id = {};
+  uint32_t sw_if_index, n;
+
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "port %u", &n))
+       a.port_id = n;
+      else if (unformat (input, "dev %U", unformat_c_string_array, &device_id,
+                        sizeof (device_id)))
+       device_id_set = 1;
+      else if (unformat (input, "key %U", unformat_vnet_dev_rss_key,
+                        &a.rss_key))
+       ;
+      else if (unformat (input, "%U", unformat_vnet_sw_interface,
+                        vnet_get_main (), &sw_if_index))
+       sw_if_index_set = 1;
+      else
+       return clib_error_return (0, "unknown input `%U'",
+                                 format_unformat_error, input);
+    }
+
+  if (sw_if_index_set == device_id_set)
+    return clib_error_return (
+      0, "please specify either interface name or port id");
+
+  if (sw_if_index_set)
+    {
+      vnet_dev_port_t *port = vnet_dev_get_port_from_sw_if_index (sw_if_index);
+
+      if (port == 0)
+       return clib_error_return (0, "unsupported interface");
+      a.port_id = port->port_id;
+      a.dev_index = port->dev->index;
+    }
+  else
+    {
+      vnet_dev_t *dev = vnet_dev_by_id (device_id);
+      if (!dev)
+       return clib_error_return (0, "please specify valid device id");
+      a.dev_index = dev->index;
+    }
+
+  rv = vnet_dev_api_port_set_rss_key (vm, &a);
+
+  if (rv != VNET_DEV_OK)
+    return clib_error_return (0, "unable to set_rss_key: %U",
+                             format_vnet_dev_rv, rv);
+
+  return 0;
+}
+
+VLIB_CLI_COMMAND (device_set_rss_key_cmd, static) = {
+  .path = "device set-rss-key",
+  .short_help = "device set-rss-key [<intf>] [port <port-id>] [dev "
+               "<device-id>] [key <rss-key>]",
+  .function = device_set_rss_key_cmd_fn,
+  .is_mp_safe = 1,
+};
index 1e428a5..9cb8e94 100644 (file)
@@ -15,34 +15,44 @@ VLIB_REGISTER_LOG_CLASS (dev_log, static) = {
   .subclass_name = "config",
 };
 
+typedef struct
+{
+  vnet_dev_api_create_port_if_args_t intf;
+  vnet_dev_api_port_set_rss_key_args_t rss_key_args;
+} port_config_t;
+
 static clib_error_t *
 vnet_dev_config_one_interface (vlib_main_t *vm, unformat_input_t *input,
-                              vnet_dev_api_create_port_if_args_t *args)
+                              port_config_t *args)
 {
   clib_error_t *err = 0;
 
-  log_debug (0, "port %u %U", args->port_id, format_unformat_input, input);
+  log_debug (0, "port %u %U", args->intf.port_id, format_unformat_input,
+            input);
 
   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     {
       u32 n;
 
-      if (unformat (input, "name %U", unformat_c_string_array, args->intf_name,
-                   sizeof (args->intf_name)))
+      if (unformat (input, "name %U", unformat_c_string_array,
+                   args->intf.intf_name, sizeof (args->intf.intf_name)))
        ;
       else if (unformat (input, "num-rx-queues %u", &n))
-       args->num_rx_queues = n;
+       args->intf.num_rx_queues = n;
       else if (unformat (input, "num-tx-queues %u", &n))
-       args->num_tx_queues = n;
+       args->intf.num_tx_queues = n;
       else if (unformat (input, "rx-queue-size %u", &n))
-       args->rx_queue_size = n;
+       args->intf.rx_queue_size = n;
       else if (unformat (input, "tx-queue-size %u", &n))
-       args->tx_queue_size = n;
+       args->intf.tx_queue_size = n;
+      else if (unformat (input, "rss-key %U", unformat_vnet_dev_rss_key,
+                        &args->rss_key_args.rss_key))
+       ;
       else if (unformat (input, "flags %U", unformat_vnet_dev_port_flags,
-                        &args->flags))
+                        &args->intf.flags))
        ;
       else if (unformat (input, "args %U", unformat_single_quoted_string,
-                        &args->args))
+                        &args->intf.args))
        ;
       else
        {
@@ -112,7 +122,6 @@ vnet_dev_config_driver_args (vlib_main_t *vm, unformat_input_t *input,
 
   return err;
 }
-
 static clib_error_t *
 vnet_dev_config_one_device (vlib_main_t *vm, unformat_input_t *input,
                            char *device_id)
@@ -120,7 +129,7 @@ vnet_dev_config_one_device (vlib_main_t *vm, unformat_input_t *input,
   log_debug (0, "device %s %U", device_id, format_unformat_input, input);
   clib_error_t *err = 0;
   vnet_dev_api_attach_args_t args = {};
-  vnet_dev_api_create_port_if_args_t *if_args_vec = 0, *if_args;
+  port_config_t *ports = 0, *p;
 
   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     {
@@ -139,10 +148,9 @@ vnet_dev_config_one_device (vlib_main_t *vm, unformat_input_t *input,
       else if (unformat (input, "port %u %U", &n, unformat_vlib_cli_sub_input,
                         &sub_input))
        {
-         vnet_dev_api_create_port_if_args_t *if_args;
-         vec_add2 (if_args_vec, if_args, 1);
-         if_args->port_id = n;
-         err = vnet_dev_config_one_interface (vm, &sub_input, if_args);
+         vec_add2 (ports, p, 1);
+         p->intf.port_id = n;
+         err = vnet_dev_config_one_interface (vm, &sub_input, p);
          unformat_free (&sub_input);
          if (err)
            break;
@@ -165,12 +173,21 @@ vnet_dev_config_one_device (vlib_main_t *vm, unformat_input_t *input,
 
       if (rv == VNET_DEV_OK)
        {
-         vec_foreach (if_args, if_args_vec)
+         vec_foreach (p, ports)
            {
-             if_args->dev_index = args.dev_index;
-             rv = vnet_dev_api_create_port_if (vm, if_args);
+             p->intf.dev_index = args.dev_index;
+             rv = vnet_dev_api_create_port_if (vm, &p->intf);
              if (rv != VNET_DEV_OK)
                break;
+             if (p->rss_key_args.rss_key.length)
+               {
+                 vnet_dev_api_port_set_rss_key_args_t *rka = &p->rss_key_args;
+                 rka->port_id = p->intf.port_id;
+                 rka->dev_index = p->intf.dev_index;
+                 rv = vnet_dev_api_port_set_rss_key (vm, rka);
+                 if (rv != VNET_DEV_OK)
+                   break;
+               }
            }
        }
 
@@ -179,7 +196,7 @@ vnet_dev_config_one_device (vlib_main_t *vm, unformat_input_t *input,
                                 format_vnet_dev_rv, rv, device_id);
     }
 
-  vec_free (if_args_vec);
+  vec_free (ports);
   return err;
 }
 
index 2a72cb2..d70d174 100644 (file)
@@ -158,7 +158,8 @@ typedef struct
   _ (ADD_RX_FLOW)                                                             \
   _ (DEL_RX_FLOW)                                                             \
   _ (GET_RX_FLOW_COUNTER)                                                     \
-  _ (RESET_RX_FLOW_COUNTER)
+  _ (RESET_RX_FLOW_COUNTER)                                                   \
+  _ (SET_RSS_KEY)
 
 typedef enum
 {
@@ -180,6 +181,7 @@ typedef struct vnet_dev_port_cfg_change_req
     vnet_dev_hw_addr_t addr;
     u16 max_rx_frame_size;
     vnet_dev_queue_id_t queue_id;
+    vnet_dev_rss_key_t rss_key;
     struct
     {
       u32 flow_index;
@@ -393,6 +395,7 @@ typedef struct vnet_dev_port
   vnet_dev_node_t rx_node;
   vnet_dev_node_t tx_node;
   vnet_dev_port_interfaces_t *interfaces;
+  vnet_dev_rss_key_t rss_key;
 
   CLIB_CACHE_LINE_ALIGN_MARK (data0);
   u8 data[];
@@ -528,6 +531,7 @@ typedef struct
     vnet_dev_arg_t *sec_if_args;
     u16 data_size;
     void *initial_data;
+    vnet_dev_rss_key_t default_rss_key;
   } port;
 
   vnet_dev_node_t *rx_node;
@@ -755,6 +759,7 @@ format_function_t format_vnet_dev_tx_queue_info;
 format_function_t format_vnet_dev_flow;
 unformat_function_t unformat_vnet_dev_flags;
 unformat_function_t unformat_vnet_dev_port_flags;
+unformat_function_t unformat_vnet_dev_rss_key;
 
 typedef struct
 {
index ffc4a3a..eda1c7c 100644 (file)
@@ -125,6 +125,10 @@ format_vnet_dev_port_info (u8 *s, va_list *args)
          s = format (s, " %U", format_vnet_dev_hw_addr, a);
        }
     }
+  if (port->rss_key.length)
+    s = format (s, "\n%URSS Key is %U", format_white_space, indent,
+               format_hex_bytes_no_wrap, port->rss_key.key,
+               port->rss_key.length);
   s = format (s, "\n%UMax RX frame size is %u (max supported %u)",
              format_white_space, indent, port->max_rx_frame_size,
              port->attr.max_supported_rx_frame_size);
@@ -522,3 +526,25 @@ format_vnet_dev_flow (u8 *s, va_list *args)
 
   return s;
 }
+
+uword
+unformat_vnet_dev_rss_key (unformat_input_t *input, va_list *args)
+{
+  vnet_dev_rss_key_t *k = va_arg (*args, vnet_dev_rss_key_t *);
+  u8 *v;
+  u32 len;
+
+  if (!(unformat_user (input, unformat_hex_string, &v)))
+    return 0;
+
+  len = vec_len (v);
+  if (len > sizeof (k->key))
+    {
+      vec_free (v);
+      return 0;
+    }
+
+  clib_memcpy (k->key, v, len);
+  k->length = len;
+  return 1;
+}
index c03a560..a2169e9 100644 (file)
@@ -280,6 +280,9 @@ vnet_dev_port_add (vlib_main_t *vm, vnet_dev_t *dev, vnet_dev_port_id_t id,
   port->rx_node = *args->rx_node;
   port->tx_node = *args->tx_node;
 
+  if (port->attr.caps.rss && args->port.default_rss_key.length)
+    port->rss_key = args->port.default_rss_key;
+
   if (args->port.args)
     for (vnet_dev_arg_t *a = args->port.args; a->type != VNET_DEV_ARG_END; a++)
       vec_add1 (port->args, *a);
@@ -356,6 +359,11 @@ vnet_dev_port_cfg_change_req_validate (vlib_main_t *vm, vnet_dev_port_t *port,
        return VNET_DEV_ERR_NO_SUCH_ENTRY;
       break;
 
+    case VNET_DEV_PORT_CFG_SET_RSS_KEY:
+      if (!port->attr.caps.rss)
+       return VNET_DEV_ERR_NOT_SUPPORTED;
+      break;
+
     default:
       break;
     }
@@ -472,6 +480,10 @@ vnet_dev_port_cfg_change (vlib_main_t *vm, vnet_dev_port_t *port,
          }
       break;
 
+    case VNET_DEV_PORT_CFG_SET_RSS_KEY:
+      port->rss_key = req->rss_key;
+      break;
+
     default:
       break;
     }
index 0562b3a..443d595 100644 (file)
@@ -17,6 +17,11 @@ typedef struct vnet_dev vnet_dev_t;
 typedef struct vnet_dev_port vnet_dev_port_t;
 typedef struct vnet_dev_rx_queue vnet_dev_rx_queue_t;
 typedef struct vnet_dev_tx_queue vnet_dev_tx_queue_t;
+typedef struct
+{
+  u8 key[48];
+  u8 length;
+} vnet_dev_rss_key_t;
 
 typedef enum
 {