dev: initial set of APIs
Type: improvement
Change-Id: I9ecbf705d460a1744f36c7005b08097dc58d9522
Signed-off-by: Damjan Marion <damarion@cisco.com>
diff --git a/src/vnet/CMakeLists.txt b/src/vnet/CMakeLists.txt
index 1e4bb15..3225540 100644
--- a/src/vnet/CMakeLists.txt
+++ b/src/vnet/CMakeLists.txt
@@ -32,6 +32,7 @@
dev/config.c
dev/counters.c
dev/dev.c
+ dev/dev_api.c
dev/error.c
dev/format.c
dev/handlers.c
@@ -98,6 +99,7 @@
)
list(APPEND VNET_API_FILES
+ dev/dev.api
interface.api
interface_types.api
ip/ip_types.api
diff --git a/src/vnet/dev/api.c b/src/vnet/dev/api.c
index 72811f5..114b63d 100644
--- a/src/vnet/dev/api.c
+++ b/src/vnet/dev/api.c
@@ -115,6 +115,8 @@
if (rv != VNET_DEV_OK && dev)
vnet_dev_process_call_op_no_rv (vm, dev, vnet_dev_free);
+ else if (dev)
+ args->dev_index = dev->index;
return rv;
}
@@ -122,7 +124,7 @@
vnet_dev_rv_t
vnet_dev_api_detach (vlib_main_t *vm, vnet_dev_api_detach_args_t *args)
{
- vnet_dev_t *dev = vnet_dev_by_id (args->device_id);
+ vnet_dev_t *dev = vnet_dev_by_index (args->dev_index);
log_debug (dev, "detach");
@@ -152,16 +154,16 @@
vnet_dev_api_create_port_if (vlib_main_t *vm,
vnet_dev_api_create_port_if_args_t *args)
{
- vnet_dev_t *dev = vnet_dev_by_id (args->device_id);
+ vnet_dev_t *dev = vnet_dev_by_index (args->dev_index);
vnet_dev_port_t *port = 0;
u16 n_threads = vlib_get_n_threads ();
int default_is_intr_mode;
vnet_dev_rv_t rv;
log_debug (dev,
- "create_port_if: device '%s' port %u intf_name '%s' num_rx_q %u "
+ "create_port_if: dev_index %u port %u intf_name '%s' num_rx_q %u "
"num_tx_q %u rx_q_sz %u tx_q_sz %u, flags '%U' args '%v'",
- args->device_id, args->port_id, args->intf_name,
+ args->dev_index, args->port_id, args->intf_name,
args->num_rx_queues, args->num_tx_queues, args->rx_queue_size,
args->tx_queue_size, format_vnet_dev_port_flags, &args->flags,
args->args);
@@ -237,7 +239,10 @@
clib_memcpy (port->intf.name, args->intf_name, sizeof (port->intf.name));
port->intf.default_is_intr_mode = default_is_intr_mode;
- return vnet_dev_process_call_port_op (vm, port, vnet_dev_port_if_create);
+ rv = vnet_dev_process_call_port_op (vm, port, vnet_dev_port_if_create);
+ args->sw_if_index = (rv == VNET_DEV_OK) ? port->intf.sw_if_index : ~0;
+
+ return rv;
}
vnet_dev_rv_t
diff --git a/src/vnet/dev/api.h b/src/vnet/dev/api.h
index 69a8462..1b7bf27 100644
--- a/src/vnet/dev/api.h
+++ b/src/vnet/dev/api.h
@@ -15,6 +15,9 @@
vnet_dev_driver_name_t driver_name;
vnet_dev_flags_t flags;
u8 *args;
+
+ /* return */
+ u32 dev_index;
} vnet_dev_api_attach_args_t;
vnet_dev_rv_t vnet_dev_api_attach (vlib_main_t *,
@@ -22,7 +25,7 @@
typedef struct
{
- vnet_dev_device_id_t device_id;
+ u32 dev_index;
} vnet_dev_api_detach_args_t;
vnet_dev_rv_t vnet_dev_api_detach (vlib_main_t *,
vnet_dev_api_detach_args_t *);
@@ -35,7 +38,7 @@
typedef struct
{
- vnet_dev_device_id_t device_id;
+ u32 dev_index;
vnet_dev_if_name_t intf_name;
u16 num_rx_queues;
u16 num_tx_queues;
@@ -44,6 +47,9 @@
vnet_dev_port_id_t port_id;
vnet_dev_port_flags_t flags;
u8 *args;
+
+ /* return */
+ u32 sw_if_index;
} vnet_dev_api_create_port_if_args_t;
vnet_dev_rv_t
diff --git a/src/vnet/dev/cli.c b/src/vnet/dev/cli.c
index d478f1d..53be448 100644
--- a/src/vnet/dev/cli.c
+++ b/src/vnet/dev/cli.c
@@ -56,17 +56,26 @@
device_detach_cmd_fn (vlib_main_t *vm, unformat_input_t *input,
vlib_cli_command_t *cmd)
{
- vnet_dev_api_detach_args_t a = {};
vnet_dev_rv_t rv;
+ vnet_dev_device_id_t device_id = {};
+ vnet_dev_t *dev;
- if (!unformat_user (input, unformat_c_string_array, a.device_id,
- sizeof (a.device_id)))
+ if (!unformat_user (input, unformat_c_string_array, device_id,
+ sizeof (device_id)))
return clib_error_return (0, "please specify valid device id");
- rv = vnet_dev_api_detach (vm, &a);
+ dev = vnet_dev_by_id (device_id);
+
+ if (dev)
+ {
+ vnet_dev_api_detach_args_t a = { .dev_index = dev->index };
+ rv = vnet_dev_api_detach (vm, &a);
+ }
+ else
+ rv = VNET_DEV_ERR_UNKNOWN_DEVICE;
if (rv != VNET_DEV_OK)
- return clib_error_return (0, "unable to detach '%s': %U", a.device_id,
+ return clib_error_return (0, "unable to detach '%s': %U", device_id,
format_vnet_dev_rv, rv);
return 0;
@@ -112,12 +121,19 @@
{
vnet_dev_api_create_port_if_args_t a = {};
vnet_dev_rv_t rv;
+ vnet_dev_device_id_t device_id = {};
+ vnet_dev_t *dev = 0;
u32 n;
- if (!unformat_user (input, unformat_c_string_array, a.device_id,
- sizeof (a.device_id)))
+ if (unformat_user (input, unformat_c_string_array, device_id,
+ sizeof (device_id)))
+ dev = vnet_dev_by_id (device_id);
+
+ if (!dev)
return clib_error_return (0, "please specify valid device id");
+ a.dev_index = dev->index;
+
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
{
if (!a.intf_name[0] &&
@@ -153,7 +169,7 @@
vec_free (a.args);
if (rv != VNET_DEV_OK)
- return clib_error_return (0, "unable to create_if '%s': %U", a.device_id,
+ return clib_error_return (0, "unable to create_if '%s': %U", device_id,
format_vnet_dev_rv, rv);
return 0;
diff --git a/src/vnet/dev/config.c b/src/vnet/dev/config.c
index 6523871..8883e72 100644
--- a/src/vnet/dev/config.c
+++ b/src/vnet/dev/config.c
@@ -107,8 +107,7 @@
{
vec_foreach (if_args, if_args_vec)
{
- clib_memcpy (if_args->device_id, device_id,
- sizeof (if_args->device_id));
+ if_args->dev_index = args.dev_index;
rv = vnet_dev_api_create_port_if (vm, if_args);
if (rv != VNET_DEV_OK)
break;
diff --git a/src/vnet/dev/dev.api b/src/vnet/dev/dev.api
new file mode 100644
index 0000000..552b778
--- /dev/null
+++ b/src/vnet/dev/dev.api
@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright(c) 2022 Cisco Systems, Inc.
+ */
+
+option version = "0.0.1";
+
+enumflag dev_flags : u32
+{
+ VL_API_DEV_FLAG_NO_STATS = 0x1,
+};
+
+enumflag dev_port_flags : u32
+{
+ VL_API_DEV_PORT_FLAG_INTERRUPT_MODE = 0x1,
+};
+
+autoendian define dev_attach
+{
+ u32 client_index;
+ u32 context;
+ string device_id[48];
+ string driver_name[16];
+ vl_api_dev_flags_t flags;
+ string args[];
+};
+
+autoendian define dev_attach_reply
+{
+ u32 context;
+ u32 dev_index;
+ i32 retval;
+ string error_string[];
+};
+
+autoendian define dev_detach
+{
+ u32 client_index;
+ u32 context;
+ u32 dev_index;
+};
+
+autoendian define dev_detach_reply
+{
+ u32 context;
+ i32 retval;
+ string error_string[];
+};
+
+autoendian define dev_create_port_if
+{
+ u32 client_index;
+ u32 context;
+ u32 dev_index;
+ string intf_name[32];
+ u16 num_rx_queues;
+ u16 num_tx_queues;
+ u16 rx_queue_size;
+ u16 tx_queue_size;
+ u16 port_id;
+ vl_api_dev_port_flags_t flags;
+ string args[];
+};
+
+autoendian define dev_create_port_if_reply
+{
+ u32 client_index;
+ u32 context;
+ u32 sw_if_index;
+ i32 retval;
+ string error_string[];
+};
+
+autoendian define dev_remove_port_if
+{
+ u32 client_index;
+ u32 context;
+ u32 sw_if_index;
+};
+
+autoendian define dev_remove_port_if_reply
+{
+ u32 context;
+ i32 retval;
+ string error_string[];
+};
+
diff --git a/src/vnet/dev/dev.h b/src/vnet/dev/dev.h
index c18d29a..59e1003 100644
--- a/src/vnet/dev/dev.h
+++ b/src/vnet/dev/dev.h
@@ -18,8 +18,6 @@
_ (0, UNKNOWN) \
_ (1, ETHERNET)
-typedef char vnet_dev_device_id_t[32];
-
typedef enum
{
#define _(b, n) VNET_DEV_PORT_TYPE_##n = (1U << (b)),
diff --git a/src/vnet/dev/dev_api.c b/src/vnet/dev/dev_api.c
new file mode 100644
index 0000000..4161c32
--- /dev/null
+++ b/src/vnet/dev/dev_api.c
@@ -0,0 +1,191 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright (c) 2023 Cisco Systems, Inc.
+ */
+
+#include <vnet/vnet.h>
+#include <vnet/dev/dev.h>
+#include <vnet/dev/api.h>
+
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+
+/* define message IDs */
+#include <dev/dev.api_enum.h>
+#include <dev/dev.api_types.h>
+
+static u16 vnet_dev_api_msg_id_base;
+
+#define REPLY_MSG_ID_BASE (vnet_dev_api_msg_id_base)
+#include <vlibapi/api_helper_macros.h>
+
+#define _(b, n, d) \
+ STATIC_ASSERT ((int) VL_API_DEV_FLAG_##n == (int) VNET_DEV_F_##n, "");
+foreach_vnet_dev_flag;
+#undef _
+
+#define _(b, n, d) \
+ STATIC_ASSERT ((int) VL_API_DEV_PORT_FLAG_##n == (int) VNET_DEV_PORT_F_##n, \
+ "");
+foreach_vnet_dev_port_flag;
+#undef _
+
+static void
+vl_api_dev_attach_t_handler (vl_api_dev_attach_t *mp)
+{
+ vlib_main_t *vm = vlib_get_main ();
+ vl_api_dev_attach_reply_t *rmp;
+ vnet_dev_api_attach_args_t a = {};
+ vnet_dev_rv_t rv;
+ u8 *error_string = 0;
+
+ STATIC_ASSERT (sizeof (mp->device_id) == sizeof (a.device_id), "");
+ STATIC_ASSERT (sizeof (mp->driver_name) == sizeof (a.driver_name), "");
+ STATIC_ASSERT (sizeof (mp->flags) == sizeof (a.flags), "");
+
+ a.flags.n = mp->flags;
+ strncpy (a.device_id, (char *) mp->device_id, sizeof (a.device_id));
+ strncpy (a.driver_name, (char *) mp->driver_name, sizeof (a.driver_name));
+ vec_add (a.args, mp->args.buf, mp->args.length);
+
+ rv = vnet_dev_api_attach (vm, &a);
+
+ if (rv != VNET_DEV_OK)
+ error_string = format (0, "%U", format_vnet_dev_rv, rv);
+
+ vec_free (a.args);
+
+ REPLY_MACRO3 (VL_API_DEV_ATTACH_REPLY, vec_len (error_string), ({
+ rmp->retval = rv;
+ if (error_string)
+ {
+ rmp->dev_index = ~0;
+ vl_api_vec_to_api_string (error_string,
+ &rmp->error_string);
+ }
+ else
+ rmp->dev_index = a.dev_index;
+ }));
+
+ vec_free (a.args);
+ vec_free (error_string);
+}
+
+static void
+vl_api_dev_detach_t_handler (vl_api_dev_detach_t *mp)
+{
+ vlib_main_t *vm = vlib_get_main ();
+ vl_api_dev_detach_reply_t *rmp;
+ vnet_dev_api_detach_args_t a = {};
+ vnet_dev_rv_t rv;
+ u8 *error_string = 0;
+
+ a.dev_index = mp->dev_index;
+
+ rv = vnet_dev_api_detach (vm, &a);
+
+ if (rv != VNET_DEV_OK)
+ error_string = format (0, "%U", format_vnet_dev_rv, rv);
+
+ REPLY_MACRO3 (VL_API_DEV_DETACH_REPLY, vec_len (error_string), ({
+ rmp->retval = rv;
+ if (error_string)
+ vl_api_vec_to_api_string (error_string,
+ &rmp->error_string);
+ }));
+
+ vec_free (error_string);
+}
+
+static void
+vl_api_dev_create_port_if_t_handler (vl_api_dev_create_port_if_t *mp)
+{
+ vlib_main_t *vm = vlib_get_main ();
+ vl_api_dev_create_port_if_reply_t *rmp;
+ vnet_dev_api_create_port_if_args_t a = {};
+ vnet_dev_rv_t rv;
+ u8 *error_string = 0;
+
+ STATIC_ASSERT (sizeof (mp->intf_name) == sizeof (a.intf_name), "");
+ STATIC_ASSERT (sizeof (mp->flags) == sizeof (a.flags), "");
+
+ a.flags.n = mp->flags;
+#define _(n) a.n = mp->n;
+ _ (dev_index)
+ _ (port_id)
+ _ (num_rx_queues)
+ _ (num_tx_queues)
+ _ (rx_queue_size)
+ _ (tx_queue_size)
+#undef _
+
+ strncpy (a.intf_name, (char *) mp->intf_name, sizeof (a.intf_name));
+ vec_add (a.args, mp->args.buf, mp->args.length);
+
+ rv = vnet_dev_api_create_port_if (vm, &a);
+
+ if (rv != VNET_DEV_OK)
+ error_string = format (0, "%U", format_vnet_dev_rv, rv);
+
+ vec_free (a.args);
+
+ REPLY_MACRO3 (VL_API_DEV_CREATE_PORT_IF_REPLY, vec_len (error_string), ({
+ rmp->retval = rv;
+ if (error_string)
+ {
+ rmp->sw_if_index = ~0;
+ vl_api_vec_to_api_string (error_string,
+ &rmp->error_string);
+ }
+ else
+ rmp->sw_if_index = a.sw_if_index;
+ }));
+
+ vec_free (a.args);
+ vec_free (error_string);
+}
+
+static void
+vl_api_dev_remove_port_if_t_handler (vl_api_dev_remove_port_if_t *mp)
+{
+ vlib_main_t *vm = vlib_get_main ();
+ vl_api_dev_remove_port_if_reply_t *rmp;
+ vnet_dev_api_remove_port_if_args_t a = {};
+ vnet_dev_rv_t rv;
+ u8 *error_string = 0;
+
+ a.sw_if_index = mp->sw_if_index;
+
+ rv = vnet_dev_api_remove_port_if (vm, &a);
+
+ if (rv != VNET_DEV_OK)
+ error_string = format (0, "%U", format_vnet_dev_rv, rv);
+
+ REPLY_MACRO3 (VL_API_DEV_REMOVE_PORT_IF_REPLY, vec_len (error_string), ({
+ rmp->retval = rv;
+ if (error_string)
+ vl_api_vec_to_api_string (error_string,
+ &rmp->error_string);
+ }));
+
+ vec_free (error_string);
+}
+
+/* set tup the API message handling tables */
+
+#include <dev/dev.api.c>
+
+static clib_error_t *
+vnet_dev_api_hookup (vlib_main_t *vm)
+{
+ api_main_t *am = vlibapi_get_main ();
+
+ /* ask for a correctly-sized block of API message decode slots */
+ vnet_dev_api_msg_id_base = setup_message_id_table ();
+
+ vl_api_set_msg_thread_safe (am, vnet_dev_api_msg_id_base + VL_API_DEV_ATTACH,
+ 1);
+
+ return 0;
+}
+
+VLIB_API_INIT_FUNCTION (vnet_dev_api_hookup);
diff --git a/src/vnet/dev/dev_funcs.h b/src/vnet/dev/dev_funcs.h
index a74d339..521157a 100644
--- a/src/vnet/dev/dev_funcs.h
+++ b/src/vnet/dev/dev_funcs.h
@@ -75,6 +75,16 @@
}
static_always_inline vnet_dev_t *
+vnet_dev_by_index (u32 index)
+{
+ vnet_dev_main_t *dm = &vnet_dev_main;
+ if (pool_is_free_index (dm->devices, index))
+ return 0;
+
+ return *pool_elt_at_index (dm->devices, index);
+}
+
+static_always_inline vnet_dev_t *
vnet_dev_by_id (char *id)
{
vnet_dev_main_t *dm = &vnet_dev_main;
diff --git a/src/vnet/dev/errors.h b/src/vnet/dev/errors.h
index 1f45ce2..47e7295 100644
--- a/src/vnet/dev/errors.h
+++ b/src/vnet/dev/errors.h
@@ -35,6 +35,7 @@
_ (PROCESS_REPLY, "dev process reply error") \
_ (RESOURCE_NOT_AVAILABLE, "resource not available") \
_ (TIMEOUT, "timeout") \
+ _ (UNKNOWN_DEVICE, "unknown device") \
_ (UNKNOWN_INTERFACE, "unknown interface") \
_ (UNSUPPORTED_CONFIG, "unsupported config") \
_ (UNSUPPORTED_DEVICE, "unsupported device") \
diff --git a/src/vnet/dev/types.h b/src/vnet/dev/types.h
index 1a82c97..006d18e 100644
--- a/src/vnet/dev/types.h
+++ b/src/vnet/dev/types.h
@@ -8,7 +8,7 @@
#include <vppinfra/types.h>
#include <vnet/dev/errors.h>
-typedef char vnet_dev_device_id_t[32];
+typedef char vnet_dev_device_id_t[48];
typedef char vnet_dev_if_name_t[32];
typedef char vnet_dev_driver_name_t[16];
typedef char vnet_dev_bus_name_t[8];
@@ -35,7 +35,7 @@
} vnet_dev_rv_t;
/* do not change bit assignments - API dependency */
-#define foreach_vnet_dev_flag _ (3, NO_STATS, "don't poll device stats")
+#define foreach_vnet_dev_flag _ (0, NO_STATS, "don't poll device stats")
typedef union
{
@@ -45,12 +45,12 @@
foreach_vnet_dev_flag
#undef _
} e;
- u64 n;
+ u32 n;
} vnet_dev_flags_t;
/* do not change bit assignments - API dependency */
#define foreach_vnet_dev_port_flag \
- _ (3, INTERRUPT_MODE, "enable interrupt mode")
+ _ (0, INTERRUPT_MODE, "enable interrupt mode")
typedef union
{
@@ -60,7 +60,7 @@
foreach_vnet_dev_port_flag
#undef _
} e;
- u64 n;
+ u32 n;
} vnet_dev_port_flags_t;
#endif /* _VNET_DEV_TYPES_H_ */