aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS6
-rw-r--r--src/vat/api_format.c218
-rw-r--r--src/vnet/devices/virtio/vhost_user.api73
-rw-r--r--src/vnet/devices/virtio/vhost_user.c261
-rw-r--r--src/vnet/devices/virtio/vhost_user.h31
-rw-r--r--src/vnet/devices/virtio/vhost_user_api.c158
-rw-r--r--src/vnet/devices/virtio/vhost_user_inline.h133
-rw-r--r--src/vnet/devices/virtio/vhost_user_input.c15
-rw-r--r--src/vnet/devices/virtio/vhost_user_output.c13
-rw-r--r--src/vnet/devices/virtio/virtio_std.h14
-rw-r--r--src/vpp/api/custom_dump.c53
-rw-r--r--test/vpp_vhost_interface.py33
12 files changed, 795 insertions, 213 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index a3d582ff414..d99bc4c33cb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -113,6 +113,12 @@ M: Steven Luong <sluong@cisco.com>
M: Mohsin Kazmi <sykazmi@cisco.com>
F: src/vnet/devices/tap/
+VNET Vhost User Driver
+I: vhost
+Y: src/vnet/devices/virtio/FEATURE.yaml
+M: Steven Luong <sluong@cisco.com>
+F: src/vnet/devices/virtio/vhost_user*
+
VNET Native Virtio Drivers
I: virtio
Y: src/vnet/devices/virtio/FEATURE.yaml
diff --git a/src/vat/api_format.c b/src/vat/api_format.c
index d9e5b5b8b21..90f79079fbe 100644
--- a/src/vat/api_format.c
+++ b/src/vat/api_format.c
@@ -2431,6 +2431,41 @@ static void vl_api_create_vhost_user_if_reply_t_handler_json
vam->result_ready = 1;
}
+static void vl_api_create_vhost_user_if_v2_reply_t_handler
+ (vl_api_create_vhost_user_if_v2_reply_t * mp)
+{
+ vat_main_t *vam = &vat_main;
+ i32 retval = ntohl (mp->retval);
+ if (vam->async_mode)
+ {
+ vam->async_errors += (retval < 0);
+ }
+ else
+ {
+ vam->retval = retval;
+ vam->sw_if_index = ntohl (mp->sw_if_index);
+ vam->result_ready = 1;
+ }
+ vam->regenerate_interface_table = 1;
+}
+
+static void vl_api_create_vhost_user_if_v2_reply_t_handler_json
+ (vl_api_create_vhost_user_if_v2_reply_t * mp)
+{
+ vat_main_t *vam = &vat_main;
+ vat_json_node_t node;
+
+ vat_json_init_object (&node);
+ vat_json_object_add_int (&node, "retval", ntohl (mp->retval));
+ vat_json_object_add_uint (&node, "sw_if_index", ntohl (mp->sw_if_index));
+
+ vat_json_print (vam->ofp, &node);
+ vat_json_free (&node);
+
+ vam->retval = ntohl (mp->retval);
+ vam->result_ready = 1;
+}
+
static void vl_api_ip_address_details_t_handler
(vl_api_ip_address_details_t * mp)
{
@@ -3249,6 +3284,7 @@ _(l2_fib_clear_table_reply) \
_(l2_interface_efp_filter_reply) \
_(l2_interface_vlan_tag_rewrite_reply) \
_(modify_vhost_user_if_reply) \
+_(modify_vhost_user_if_v2_reply) \
_(delete_vhost_user_if_reply) \
_(want_l2_macs_events_reply) \
_(input_acl_set_interface_reply) \
@@ -3420,6 +3456,8 @@ _(L2_INTERFACE_VLAN_TAG_REWRITE_REPLY, l2_interface_vlan_tag_rewrite_reply) \
_(SW_INTERFACE_VHOST_USER_DETAILS, sw_interface_vhost_user_details) \
_(CREATE_VHOST_USER_IF_REPLY, create_vhost_user_if_reply) \
_(MODIFY_VHOST_USER_IF_REPLY, modify_vhost_user_if_reply) \
+_(CREATE_VHOST_USER_IF_V2_REPLY, create_vhost_user_if_v2_reply) \
+_(MODIFY_VHOST_USER_IF_V2_REPLY, modify_vhost_user_if_v2_reply) \
_(DELETE_VHOST_USER_IF_REPLY, delete_vhost_user_if_reply) \
_(SHOW_VERSION_REPLY, show_version_reply) \
_(SHOW_THREADS_REPLY, show_threads_reply) \
@@ -9859,13 +9897,11 @@ api_create_vhost_user_if (vat_main_t * vam)
mp->disable_indirect_desc = disable_indirect_desc;
mp->enable_gso = enable_gso;
mp->enable_packed = enable_packed;
+ mp->custom_dev_instance = ntohl (custom_dev_instance);
clib_memcpy (mp->sock_filename, file_name, vec_len (file_name));
vec_free (file_name);
if (custom_dev_instance != ~0)
- {
- mp->renumber = 1;
- mp->custom_dev_instance = ntohl (custom_dev_instance);
- }
+ mp->renumber = 1;
mp->use_custom_mac = use_custom_mac;
clib_memcpy (mp->mac_address, hwaddr, 6);
@@ -9940,14 +9976,177 @@ api_modify_vhost_user_if (vat_main_t * vam)
mp->is_server = is_server;
mp->enable_gso = enable_gso;
mp->enable_packed = enable_packed;
+ mp->custom_dev_instance = ntohl (custom_dev_instance);
clib_memcpy (mp->sock_filename, file_name, vec_len (file_name));
vec_free (file_name);
if (custom_dev_instance != ~0)
+ mp->renumber = 1;
+
+ S (mp);
+ W (ret);
+ return ret;
+}
+
+static int
+api_create_vhost_user_if_v2 (vat_main_t * vam)
+{
+ unformat_input_t *i = vam->input;
+ vl_api_create_vhost_user_if_v2_t *mp;
+ u8 *file_name;
+ u8 is_server = 0;
+ u8 file_name_set = 0;
+ u32 custom_dev_instance = ~0;
+ u8 hwaddr[6];
+ u8 use_custom_mac = 0;
+ u8 disable_mrg_rxbuf = 0;
+ u8 disable_indirect_desc = 0;
+ u8 *tag = 0;
+ u8 enable_gso = 0;
+ u8 enable_packed = 0;
+ u8 enable_event_idx = 0;
+ int ret;
+
+ /* Shut up coverity */
+ clib_memset (hwaddr, 0, sizeof (hwaddr));
+
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
{
- mp->renumber = 1;
- mp->custom_dev_instance = ntohl (custom_dev_instance);
+ if (unformat (i, "socket %s", &file_name))
+ {
+ file_name_set = 1;
+ }
+ else if (unformat (i, "renumber %" PRIu32, &custom_dev_instance))
+ ;
+ else if (unformat (i, "mac %U", unformat_ethernet_address, hwaddr))
+ use_custom_mac = 1;
+ else if (unformat (i, "server"))
+ is_server = 1;
+ else if (unformat (i, "disable_mrg_rxbuf"))
+ disable_mrg_rxbuf = 1;
+ else if (unformat (i, "disable_indirect_desc"))
+ disable_indirect_desc = 1;
+ else if (unformat (i, "gso"))
+ enable_gso = 1;
+ else if (unformat (i, "packed"))
+ enable_packed = 1;
+ else if (unformat (i, "event-idx"))
+ enable_event_idx = 1;
+ else if (unformat (i, "tag %s", &tag))
+ ;
+ else
+ break;
}
+ if (file_name_set == 0)
+ {
+ errmsg ("missing socket file name");
+ return -99;
+ }
+
+ if (vec_len (file_name) > 255)
+ {
+ errmsg ("socket file name too long");
+ return -99;
+ }
+ vec_add1 (file_name, 0);
+
+ M (CREATE_VHOST_USER_IF_V2, mp);
+
+ mp->is_server = is_server;
+ mp->disable_mrg_rxbuf = disable_mrg_rxbuf;
+ mp->disable_indirect_desc = disable_indirect_desc;
+ mp->enable_gso = enable_gso;
+ mp->enable_packed = enable_packed;
+ mp->enable_event_idx = enable_event_idx;
+ mp->custom_dev_instance = ntohl (custom_dev_instance);
+ clib_memcpy (mp->sock_filename, file_name, vec_len (file_name));
+ vec_free (file_name);
+ if (custom_dev_instance != ~0)
+ mp->renumber = 1;
+
+ mp->use_custom_mac = use_custom_mac;
+ clib_memcpy (mp->mac_address, hwaddr, 6);
+ if (tag)
+ strncpy ((char *) mp->tag, (char *) tag, ARRAY_LEN (mp->tag) - 1);
+ vec_free (tag);
+
+ S (mp);
+ W (ret);
+ return ret;
+}
+
+static int
+api_modify_vhost_user_if_v2 (vat_main_t * vam)
+{
+ unformat_input_t *i = vam->input;
+ vl_api_modify_vhost_user_if_v2_t *mp;
+ u8 *file_name;
+ u8 is_server = 0;
+ u8 file_name_set = 0;
+ u32 custom_dev_instance = ~0;
+ u8 sw_if_index_set = 0;
+ u32 sw_if_index = (u32) ~ 0;
+ u8 enable_gso = 0;
+ u8 enable_packed = 0;
+ u8 enable_event_idx = 0;
+ int ret;
+
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index))
+ sw_if_index_set = 1;
+ else if (unformat (i, "sw_if_index %d", &sw_if_index))
+ sw_if_index_set = 1;
+ else if (unformat (i, "socket %s", &file_name))
+ {
+ file_name_set = 1;
+ }
+ else if (unformat (i, "renumber %" PRIu32, &custom_dev_instance))
+ ;
+ else if (unformat (i, "server"))
+ is_server = 1;
+ else if (unformat (i, "gso"))
+ enable_gso = 1;
+ else if (unformat (i, "packed"))
+ enable_packed = 1;
+ else if (unformat (i, "event-idx"))
+ enable_event_idx = 1;
+ else
+ break;
+ }
+
+ if (sw_if_index_set == 0)
+ {
+ errmsg ("missing sw_if_index or interface name");
+ return -99;
+ }
+
+ if (file_name_set == 0)
+ {
+ errmsg ("missing socket file name");
+ return -99;
+ }
+
+ if (vec_len (file_name) > 255)
+ {
+ errmsg ("socket file name too long");
+ return -99;
+ }
+ vec_add1 (file_name, 0);
+
+ M (MODIFY_VHOST_USER_IF_V2, mp);
+
+ mp->sw_if_index = ntohl (sw_if_index);
+ mp->is_server = is_server;
+ mp->enable_gso = enable_gso;
+ mp->enable_packed = enable_packed;
+ mp->enable_event_idx = enable_event_idx;
+ mp->custom_dev_instance = ntohl (custom_dev_instance);
+ clib_memcpy (mp->sock_filename, file_name, vec_len (file_name));
+ vec_free (file_name);
+ if (custom_dev_instance != ~0)
+ mp->renumber = 1;
+
S (mp);
W (ret);
return ret;
@@ -14780,6 +14979,13 @@ _(create_vhost_user_if, \
_(modify_vhost_user_if, \
"<intfc> | sw_if_index <nn> socket <filename>\n" \
"[server] [renumber <dev_instance>] [gso] [packed]") \
+_(create_vhost_user_if_v2, \
+ "socket <filename> [server] [renumber <dev_instance>] " \
+ "[disable_mrg_rxbuf] [disable_indirect_desc] [gso] " \
+ "[mac <mac_address>] [packed] [event-idx]") \
+_(modify_vhost_user_if_v2, \
+ "<intfc> | sw_if_index <nn> socket <filename>\n" \
+ "[server] [renumber <dev_instance>] [gso] [packed] [event-idx]")\
_(delete_vhost_user_if, "<intfc> | sw_if_index <nn>") \
_(sw_interface_vhost_user_dump, "<intfc> | sw_if_index <nn>") \
_(show_version, "") \
diff --git a/src/vnet/devices/virtio/vhost_user.api b/src/vnet/devices/virtio/vhost_user.api
index 338fd710bc0..b026ba768a9 100644
--- a/src/vnet/devices/virtio/vhost_user.api
+++ b/src/vnet/devices/virtio/vhost_user.api
@@ -13,7 +13,7 @@
* limitations under the License.
*/
-option version = "4.0.1";
+option version = "4.1.1";
import "vnet/interface_types.api";
import "vnet/ethernet/ethernet_types.api";
@@ -32,6 +32,7 @@ import "vnet/devices/virtio/virtio_types.api";
*/
define create_vhost_user_if
{
+ option deprecated;
u32 client_index;
u32 context;
bool is_server;
@@ -54,6 +55,7 @@ define create_vhost_user_if
*/
define create_vhost_user_if_reply
{
+ option deprecated;
u32 context;
i32 retval;
vl_api_interface_index_t sw_if_index;
@@ -68,6 +70,7 @@ define create_vhost_user_if_reply
*/
autoreply define modify_vhost_user_if
{
+ option deprecated;
u32 client_index;
u32 context;
vl_api_interface_index_t sw_if_index;
@@ -79,6 +82,74 @@ autoreply define modify_vhost_user_if
u32 custom_dev_instance;
};
+/** \brief vhost-user interface create request
+ @param client_index - opaque cookie to identify the sender
+ @param is_server - our side is socket server
+ @param sock_filename - unix socket filename, used to speak with frontend
+ @param use_custom_mac - enable or disable the use of the provided hardware address
+ @param disable_mrg_rxbuf - disable the use of merge receive buffers
+ @param disable_indirect_desc - disable the use of indirect descriptors which driver can use
+ @param enable_gso - enable gso support (default 0)
+ @param enable_packed - enable packed ring support (default 0)
+ @param enable_event_idx - enable event_idx support (default 0)
+ @param mac_address - hardware address to use if 'use_custom_mac' is set
+ @param renumber - if true, use custom_dev_instance is valid
+ @param custom_dev_instance - custom device instance number
+*/
+define create_vhost_user_if_v2
+{
+ u32 client_index;
+ u32 context;
+ bool is_server;
+ string sock_filename[256];
+ bool renumber;
+ bool disable_mrg_rxbuf;
+ bool disable_indirect_desc;
+ bool enable_gso;
+ bool enable_packed;
+ bool enable_event_idx;
+ u32 custom_dev_instance;
+ bool use_custom_mac;
+ vl_api_mac_address_t mac_address;
+ string tag[64];
+};
+
+/** \brief vhost-user interface create response
+ @param context - sender context, to match reply w/ request
+ @param retval - return code for the request
+ @param sw_if_index - interface the operation is applied to
+*/
+define create_vhost_user_if_v2_reply
+{
+ u32 context;
+ i32 retval;
+ vl_api_interface_index_t sw_if_index;
+};
+
+/** \brief vhost-user interface modify request
+ @param client_index - opaque cookie to identify the sender
+ @param is_server - our side is socket server
+ @param sock_filename - unix socket filename, used to speak with frontend
+ @param enable_gso - enable gso support (default 0)
+ @param enable_packed - enable packed ring support (default 0)
+ @param enable_event_idx - enable event idx support (default 0)
+ @param renumber - if true, use custom_dev_instance is valid
+ @param custom_dev_instance - custom device instance number
+*/
+autoreply define modify_vhost_user_if_v2
+{
+ u32 client_index;
+ u32 context;
+ vl_api_interface_index_t sw_if_index;
+ bool is_server;
+ string sock_filename[256];
+ bool renumber;
+ bool enable_gso;
+ bool enable_packed;
+ bool enable_event_idx;
+ u32 custom_dev_instance;
+};
+
/** \brief vhost-user interface delete request
@param client_index - opaque cookie to identify the sender
*/
diff --git a/src/vnet/devices/virtio/vhost_user.c b/src/vnet/devices/virtio/vhost_user.c
index 573d6579cea..daa126064c5 100644
--- a/src/vnet/devices/virtio/vhost_user.c
+++ b/src/vnet/devices/virtio/vhost_user.c
@@ -467,6 +467,8 @@ vhost_user_socket_read (clib_file_t * uf)
VIRTIO_FEATURE (VIRTIO_F_VERSION_1);
msg.u64 &= vui->feature_mask;
+ if (vui->enable_event_idx)
+ msg.u64 |= VIRTIO_FEATURE (VIRTIO_RING_F_EVENT_IDX);
if (vui->enable_gso)
msg.u64 |= FEATURE_VIRTIO_NET_F_HOST_GUEST_TSO_FEATURE_BITS;
if (vui->enable_packed)
@@ -664,6 +666,8 @@ vhost_user_socket_read (clib_file_t * uf)
vui->vrings[msg.state.index].last_used_idx =
vui->vrings[msg.state.index].last_avail_idx =
vui->vrings[msg.state.index].used->idx;
+ vui->vrings[msg.state.index].last_kick =
+ vui->vrings[msg.state.index].last_used_idx;
/* tell driver that we don't want interrupts */
if (vhost_user_is_packed_ring_supported (vui))
@@ -865,6 +869,8 @@ vhost_user_socket_read (clib_file_t * uf)
*/
vui->vrings[msg.state.index].last_used_idx =
vui->vrings[msg.state.index].last_avail_idx;
+ vui->vrings[msg.state.index].last_kick =
+ vui->vrings[msg.state.index].last_used_idx;
vui->vrings[msg.state.index].used_wrap_counter =
vui->vrings[msg.state.index].avail_wrap_counter;
@@ -1196,7 +1202,7 @@ vhost_user_send_interrupt_process (vlib_main_t * vm,
if (txvq->n_since_last_int)
{
if (now >= txvq->int_deadline)
- vhost_user_send_call (vm, txvq);
+ vhost_user_send_call (vm, vui, txvq);
else
next_timeout = txvq->int_deadline - now;
}
@@ -1204,7 +1210,7 @@ vhost_user_send_interrupt_process (vlib_main_t * vm,
if (rxvq->n_since_last_int)
{
if (now >= rxvq->int_deadline)
- vhost_user_send_call (vm, rxvq);
+ vhost_user_send_call (vm, vui, rxvq);
else
next_timeout = rxvq->int_deadline - now;
}
@@ -1560,12 +1566,9 @@ vhost_user_create_ethernet (vnet_main_t * vnm, vlib_main_t * vm,
* Initialize vui with specified attributes
*/
static void
-vhost_user_vui_init (vnet_main_t * vnm,
- vhost_user_intf_t * vui,
- int server_sock_fd,
- const char *sock_filename,
- u64 feature_mask, u32 * sw_if_index, u8 enable_gso,
- u8 enable_packed)
+vhost_user_vui_init (vnet_main_t * vnm, vhost_user_intf_t * vui,
+ int server_sock_fd, vhost_user_create_if_args_t * args,
+ u32 * sw_if_index)
{
vnet_sw_interface_t *sw;
int q;
@@ -1589,16 +1592,17 @@ vhost_user_vui_init (vnet_main_t * vnm,
}
vui->sw_if_index = sw->sw_if_index;
- strncpy (vui->sock_filename, sock_filename,
+ strncpy (vui->sock_filename, args->sock_filename,
ARRAY_LEN (vui->sock_filename) - 1);
vui->sock_errno = 0;
vui->is_ready = 0;
- vui->feature_mask = feature_mask;
+ vui->feature_mask = args->feature_mask;
vui->clib_file_index = ~0;
vui->log_base_addr = 0;
vui->if_index = vui - vum->vhost_user_interfaces;
- vui->enable_gso = enable_gso;
- vui->enable_packed = enable_packed;
+ vui->enable_gso = args->enable_gso;
+ vui->enable_event_idx = args->enable_event_idx;
+ vui->enable_packed = args->enable_packed;
/*
* enable_gso takes precedence over configurable feature mask if there
* is a clash.
@@ -1611,8 +1615,8 @@ vhost_user_vui_init (vnet_main_t * vnm,
* gso feature mask, we don't support one sided GSO or partial GSO.
*/
if ((vui->enable_gso == 0) &&
- ((feature_mask & FEATURE_VIRTIO_NET_F_HOST_GUEST_TSO_FEATURE_BITS) ==
- (FEATURE_VIRTIO_NET_F_HOST_GUEST_TSO_FEATURE_BITS)))
+ ((args->feature_mask & FEATURE_VIRTIO_NET_F_HOST_GUEST_TSO_FEATURE_BITS)
+ == (FEATURE_VIRTIO_NET_F_HOST_GUEST_TSO_FEATURE_BITS)))
vui->enable_gso = 1;
vhost_user_update_gso_interface_count (vui, 1 /* add */ );
mhash_set_mem (&vum->if_index_by_sock_name, vui->sock_filename,
@@ -1637,12 +1641,7 @@ vhost_user_vui_init (vnet_main_t * vnm,
int
vhost_user_create_if (vnet_main_t * vnm, vlib_main_t * vm,
- const char *sock_filename,
- u8 is_server,
- u32 * sw_if_index,
- u64 feature_mask,
- u8 renumber, u32 custom_dev_instance, u8 * hwaddr,
- u8 enable_gso, u8 enable_packed)
+ vhost_user_create_if_args_t * args)
{
vhost_user_intf_t *vui = NULL;
u32 sw_if_idx = ~0;
@@ -1651,26 +1650,25 @@ vhost_user_create_if (vnet_main_t * vnm, vlib_main_t * vm,
vhost_user_main_t *vum = &vhost_user_main;
uword *if_index;
- if (sock_filename == NULL || !(strlen (sock_filename) > 0))
+ if (args->sock_filename == NULL || !(strlen (args->sock_filename) > 0))
{
return VNET_API_ERROR_INVALID_ARGUMENT;
}
- if_index = mhash_get (&vum->if_index_by_sock_name, (void *) sock_filename);
+ if_index = mhash_get (&vum->if_index_by_sock_name,
+ (void *) args->sock_filename);
if (if_index)
{
- if (sw_if_index)
- {
- vui = &vum->vhost_user_interfaces[*if_index];
- *sw_if_index = vui->sw_if_index;
- }
+ vui = &vum->vhost_user_interfaces[*if_index];
+ args->sw_if_index = vui->sw_if_index;
return VNET_API_ERROR_IF_ALREADY_EXISTS;
}
- if (is_server)
+ if (args->is_server)
{
if ((rv =
- vhost_user_init_server_sock (sock_filename, &server_sock_fd)) != 0)
+ vhost_user_init_server_sock (args->sock_filename,
+ &server_sock_fd)) != 0)
{
return rv;
}
@@ -1679,19 +1677,17 @@ vhost_user_create_if (vnet_main_t * vnm, vlib_main_t * vm,
/* Protect the uninitialized vui from being dispatched by rx/tx */
vlib_worker_thread_barrier_sync (vm);
pool_get (vhost_user_main.vhost_user_interfaces, vui);
- vhost_user_create_ethernet (vnm, vm, vui, hwaddr);
+ vhost_user_create_ethernet (vnm, vm, vui, args->hwaddr);
vlib_worker_thread_barrier_release (vm);
- vhost_user_vui_init (vnm, vui, server_sock_fd, sock_filename,
- feature_mask, &sw_if_idx, enable_gso, enable_packed);
+ vhost_user_vui_init (vnm, vui, server_sock_fd, args, &sw_if_idx);
vnet_sw_interface_set_mtu (vnm, vui->sw_if_index, 9000);
vhost_user_rx_thread_placement (vui, 1);
- if (renumber)
- vnet_interface_name_renumber (sw_if_idx, custom_dev_instance);
+ if (args->renumber)
+ vnet_interface_name_renumber (sw_if_idx, args->custom_dev_instance);
- if (sw_if_index)
- *sw_if_index = sw_if_idx;
+ args->sw_if_index = sw_if_idx;
// Process node must connect
vlib_process_signal_event (vm, vhost_user_process_node.index, 0, 0);
@@ -1701,11 +1697,7 @@ vhost_user_create_if (vnet_main_t * vnm, vlib_main_t * vm,
int
vhost_user_modify_if (vnet_main_t * vnm, vlib_main_t * vm,
- const char *sock_filename,
- u8 is_server,
- u32 sw_if_index,
- u64 feature_mask, u8 renumber, u32 custom_dev_instance,
- u8 enable_gso, u8 enable_packed)
+ vhost_user_create_if_args_t * args)
{
vhost_user_main_t *vum = &vhost_user_main;
vhost_user_intf_t *vui = NULL;
@@ -1715,13 +1707,12 @@ vhost_user_modify_if (vnet_main_t * vnm, vlib_main_t * vm,
vnet_hw_interface_t *hwif;
uword *if_index;
- if (!
- (hwif =
- vnet_get_sup_hw_interface_api_visible_or_null (vnm, sw_if_index))
+ if (!(hwif = vnet_get_sup_hw_interface_api_visible_or_null (vnm,
+ args->sw_if_index))
|| hwif->dev_class_index != vhost_user_device_class.index)
return VNET_API_ERROR_INVALID_SW_IF_INDEX;
- if (sock_filename == NULL || !(strlen (sock_filename) > 0))
+ if (args->sock_filename == NULL || !(strlen (args->sock_filename) > 0))
return VNET_API_ERROR_INVALID_ARGUMENT;
vui = vec_elt_at_index (vum->vhost_user_interfaces, hwif->dev_instance);
@@ -1730,23 +1721,22 @@ vhost_user_modify_if (vnet_main_t * vnm, vlib_main_t * vm,
* Disallow changing the interface to have the same path name
* as other interface
*/
- if_index = mhash_get (&vum->if_index_by_sock_name, (void *) sock_filename);
+ if_index = mhash_get (&vum->if_index_by_sock_name,
+ (void *) args->sock_filename);
if (if_index && (*if_index != vui->if_index))
return VNET_API_ERROR_IF_ALREADY_EXISTS;
// First try to open server socket
- if (is_server)
- if ((rv = vhost_user_init_server_sock (sock_filename,
+ if (args->is_server)
+ if ((rv = vhost_user_init_server_sock (args->sock_filename,
&server_sock_fd)) != 0)
return rv;
vhost_user_term_if (vui);
- vhost_user_vui_init (vnm, vui, server_sock_fd,
- sock_filename, feature_mask, &sw_if_idx, enable_gso,
- enable_packed);
+ vhost_user_vui_init (vnm, vui, server_sock_fd, args, &sw_if_idx);
- if (renumber)
- vnet_interface_name_renumber (sw_if_idx, custom_dev_instance);
+ if (args->renumber)
+ vnet_interface_name_renumber (sw_if_idx, args->custom_dev_instance);
// Process node must connect
vlib_process_signal_event (vm, vhost_user_process_node.index, 0, 0);
@@ -1759,46 +1749,46 @@ vhost_user_connect_command_fn (vlib_main_t * vm,
unformat_input_t * input,
vlib_cli_command_t * cmd)
{
+ vnet_main_t *vnm = vnet_get_main ();
unformat_input_t _line_input, *line_input = &_line_input;
- u8 *sock_filename = NULL;
- u32 sw_if_index;
- u8 is_server = 0;
- u64 feature_mask = (u64) ~ (0ULL);
- u8 renumber = 0;
- u32 custom_dev_instance = ~0;
- u8 hwaddr[6];
- u8 *hw = NULL;
clib_error_t *error = NULL;
- u8 enable_gso = 0, enable_packed = 0;
+ vhost_user_create_if_args_t args = { 0 };
+ int rv;
/* Get a line of input. */
if (!unformat_user (input, unformat_line_input, line_input))
return 0;
+ args.feature_mask = (u64) ~ (0ULL);
+ args.custom_dev_instance = ~0;
/* GSO feature is disable by default */
- feature_mask &= ~FEATURE_VIRTIO_NET_F_HOST_GUEST_TSO_FEATURE_BITS;
+ args.feature_mask &= ~FEATURE_VIRTIO_NET_F_HOST_GUEST_TSO_FEATURE_BITS;
/* packed-ring feature is disable by default */
- feature_mask &= ~VIRTIO_FEATURE (VIRTIO_F_RING_PACKED);
+ args.feature_mask &= ~VIRTIO_FEATURE (VIRTIO_F_RING_PACKED);
+ /* event_idx feature is disable by default */
+ args.feature_mask &= ~VIRTIO_FEATURE (VIRTIO_RING_F_EVENT_IDX);
+
while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
{
- if (unformat (line_input, "socket %s", &sock_filename))
+ if (unformat (line_input, "socket %s", &args.sock_filename))
;
else if (unformat (line_input, "server"))
- is_server = 1;
+ args.is_server = 1;
else if (unformat (line_input, "gso"))
- enable_gso = 1;
+ args.enable_gso = 1;
else if (unformat (line_input, "packed"))
- enable_packed = 1;
- else if (unformat (line_input, "feature-mask 0x%llx", &feature_mask))
+ args.enable_packed = 1;
+ else if (unformat (line_input, "event-idx"))
+ args.enable_event_idx = 1;
+ else if (unformat (line_input, "feature-mask 0x%llx",
+ &args.feature_mask))
;
- else
- if (unformat
- (line_input, "hwaddr %U", unformat_ethernet_address, hwaddr))
- hw = hwaddr;
- else if (unformat (line_input, "renumber %d", &custom_dev_instance))
- {
- renumber = 1;
- }
+ else if (unformat (line_input, "hwaddr %U", unformat_ethernet_address,
+ args.hwaddr))
+ ;
+ else if (unformat (line_input, "renumber %d",
+ &args.custom_dev_instance))
+ args.renumber = 1;
else
{
error = clib_error_return (0, "unknown input `%U'",
@@ -1807,23 +1797,17 @@ vhost_user_connect_command_fn (vlib_main_t * vm,
}
}
- vnet_main_t *vnm = vnet_get_main ();
-
- int rv;
- if ((rv = vhost_user_create_if (vnm, vm, (char *) sock_filename,
- is_server, &sw_if_index, feature_mask,
- renumber, custom_dev_instance, hw,
- enable_gso, enable_packed)))
+ if ((rv = vhost_user_create_if (vnm, vm, &args)))
{
error = clib_error_return (0, "vhost_user_create_if returned %d", rv);
goto done;
}
- vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main (),
- sw_if_index);
+ vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, vnm,
+ args.sw_if_index);
done:
- vec_free (sock_filename);
+ vec_free (args.sock_filename);
unformat_free (line_input);
return error;
@@ -1937,26 +1921,14 @@ format_vhost_user_desc (u8 * s, va_list * args)
return s;
}
-static u8 *
-format_vhost_user_vring (u8 * s, va_list * args)
-{
- char *fmt = va_arg (*args, char *);
- vhost_user_intf_t *vui = va_arg (*args, vhost_user_intf_t *);
- int q = va_arg (*args, int);
-
- s = format (s, fmt, vui->vrings[q].avail->flags, vui->vrings[q].avail->idx,
- vui->vrings[q].used->flags, vui->vrings[q].used->idx);
- return s;
-}
-
static void
-vhost_user_show_fds (vlib_main_t * vm, vhost_user_intf_t * vui, int q)
+vhost_user_show_fds (vlib_main_t * vm, vhost_user_vring_t * vq)
{
- int kickfd = UNIX_GET_FD (vui->vrings[q].kickfd_idx);
- int callfd = UNIX_GET_FD (vui->vrings[q].callfd_idx);
+ int kickfd = UNIX_GET_FD (vq->kickfd_idx);
+ int callfd = UNIX_GET_FD (vq->callfd_idx);
vlib_cli_output (vm, " kickfd %d callfd %d errfd %d\n", kickfd, callfd,
- vui->vrings[q].errfd);
+ vq->errfd);
}
static void
@@ -1968,13 +1940,15 @@ vhost_user_show_desc (vlib_main_t * vm, vhost_user_intf_t * vui, int q,
u32 idx;
u32 n_entries;
vring_desc_t *desc_table;
+ vhost_user_vring_t *vq = &vui->vrings[q];
- if (vui->vrings[q].avail && vui->vrings[q].used)
- vlib_cli_output (vm, "%U", format_vhost_user_vring,
- " avail.flags %x avail.idx %d used.flags %x used.idx %d\n",
- vui, q);
+ if (vq->avail && vq->used)
+ vlib_cli_output (vm, " avail.flags %x avail event idx %u avail.idx %d "
+ "used event idx %u used.idx %d\n", vq->avail->flags,
+ vhost_user_avail_event_idx (vq), vq->avail->idx,
+ vhost_user_used_event_idx (vq), vq->used->idx);
- vhost_user_show_fds (vm, vui, q);
+ vhost_user_show_fds (vm, vq);
if (show_descr)
{
@@ -1985,9 +1959,9 @@ vhost_user_show_desc (vlib_main_t * vm, vhost_user_intf_t * vui, int q,
vlib_cli_output (vm,
" ===== ================== ===== ====== ===== "
"==================\n");
- for (j = 0; j < vui->vrings[q].qsz_mask + 1; j++)
+ for (j = 0; j < vq->qsz_mask + 1; j++)
{
- desc_table = vui->vrings[q].desc;
+ desc_table = vq->desc;
vlib_cli_output (vm, "%U", format_vhost_user_desc,
" %-5d 0x%016lx %-5d 0x%04x %-5d 0x%016lx\n", vui,
desc_table, j, &mem_hint);
@@ -2030,18 +2004,25 @@ format_vhost_user_packed_desc (u8 * s, va_list * args)
}
static u8 *
-format_vhost_user_vring_packed (u8 * s, va_list * args)
+format_vhost_user_event_idx_flags (u8 * s, va_list * args)
{
- char *fmt = va_arg (*args, char *);
- vhost_user_intf_t *vui = va_arg (*args, vhost_user_intf_t *);
- int q = va_arg (*args, int);
-
- s = format (s, fmt, vui->vrings[q].avail_event->flags,
- vui->vrings[q].avail_event->off_wrap,
- vui->vrings[q].used_event->flags,
- vui->vrings[q].used_event->off_wrap,
- vui->vrings[q].avail_wrap_counter,
- vui->vrings[q].used_wrap_counter);
+ u32 flags = va_arg (*args, u32);
+ typedef struct
+ {
+ u8 value;
+ char *str;
+ } event_idx_flags;
+ static event_idx_flags event_idx_array[] = {
+#define _(s,v) { .str = #s, .value = v, },
+ foreach_virtio_event_idx_flags
+#undef _
+ };
+ u32 num_entries = sizeof (event_idx_array) / sizeof (event_idx_flags);
+
+ if (flags < num_entries)
+ s = format (s, "%s", event_idx_array[flags].str);
+ else
+ s = format (s, "%u", flags);
return s;
}
@@ -2054,15 +2035,25 @@ vhost_user_show_desc_packed (vlib_main_t * vm, vhost_user_intf_t * vui, int q,
u32 idx;
u32 n_entries;
vring_packed_desc_t *desc_table;
+ vhost_user_vring_t *vq = &vui->vrings[q];
+ u16 off_wrap, event_idx;
+
+ off_wrap = vq->avail_event->off_wrap;
+ event_idx = off_wrap & 0x7fff;
+ vlib_cli_output (vm, " avail_event.flags %U avail_event.off_wrap %u "
+ "avail event idx %u\n", format_vhost_user_event_idx_flags,
+ (u32) vq->avail_event->flags, off_wrap, event_idx);
+
+ off_wrap = vq->used_event->off_wrap;
+ event_idx = off_wrap & 0x7fff;
+ vlib_cli_output (vm, " used_event.flags %U used_event.off_wrap %u "
+ "used event idx %u\n", format_vhost_user_event_idx_flags,
+ (u32) vq->used_event->flags, off_wrap, event_idx);
- if (vui->vrings[q].avail_event && vui->vrings[q].used_event)
- vlib_cli_output (vm, "%U", format_vhost_user_vring_packed,
- " avail_event.flags %x avail_event.off_wrap %u "
- "used_event.flags %x used_event.off_wrap %u\n"
- " avail wrap counter %u, used wrap counter %u\n",
- vui, q);
+ vlib_cli_output (vm, " avail wrap counter %u, used wrap counter %u\n",
+ vq->avail_wrap_counter, vq->used_wrap_counter);
- vhost_user_show_fds (vm, vui, q);
+ vhost_user_show_fds (vm, vq);
if (show_descr)
{
@@ -2073,9 +2064,9 @@ vhost_user_show_desc_packed (vlib_main_t * vm, vhost_user_intf_t * vui, int q,
vlib_cli_output (vm,
" ===== ================== ===== ====== ===== "
"==================\n");
- for (j = 0; j < vui->vrings[q].qsz_mask + 1; j++)
+ for (j = 0; j < vq->qsz_mask + 1; j++)
{
- desc_table = vui->vrings[q].packed_desc;
+ desc_table = vq->packed_desc;
vlib_cli_output (vm, "%U", format_vhost_user_packed_desc,
" %-5u 0x%016lx %-5u 0x%04x %-5u 0x%016lx\n", vui,
desc_table, j, &mem_hint);
@@ -2191,6 +2182,8 @@ show_vhost_user_command_fn (vlib_main_t * vm,
vlib_cli_output (vm, " GSO enable");
if (vui->enable_packed)
vlib_cli_output (vm, " Packed ring enable");
+ if (vui->enable_event_idx)
+ vlib_cli_output (vm, " Event index enable");
vlib_cli_output (vm, "virtio_net_hdr_sz %d\n"
" features mask (0x%llx): \n"
@@ -2287,10 +2280,12 @@ show_vhost_user_command_fn (vlib_main_t * vm,
vui->vrings[q].enabled ? "" : " disabled");
vlib_cli_output (vm,
- " qsz %d last_avail_idx %d last_used_idx %d\n",
+ " qsz %d last_avail_idx %d last_used_idx %d"
+ " last_kick %u\n",
vui->vrings[q].qsz_mask + 1,
vui->vrings[q].last_avail_idx,
- vui->vrings[q].last_used_idx);
+ vui->vrings[q].last_used_idx,
+ vui->vrings[q].last_kick);
if (vhost_user_is_packed_ring_supported (vui))
vhost_user_show_desc_packed (vm, vui, q, show_descr,
@@ -2368,7 +2363,7 @@ VLIB_CLI_COMMAND (vhost_user_connect_command, static) = {
.path = "create vhost-user",
.short_help = "create vhost-user socket <socket-filename> [server] "
"[feature-mask <hex>] [hwaddr <mac-addr>] [renumber <dev_instance>] [gso] "
- "[packed]",
+ "[packed] [event-idx]",
.function = vhost_user_connect_command_fn,
.is_mp_safe = 1,
};
diff --git a/src/vnet/devices/virtio/vhost_user.h b/src/vnet/devices/virtio/vhost_user.h
index eecfd2d60e5..604e5571141 100644
--- a/src/vnet/devices/virtio/vhost_user.h
+++ b/src/vnet/devices/virtio/vhost_user.h
@@ -97,16 +97,27 @@ typedef enum
(FEATURE_VIRTIO_NET_F_HOST_TSO_FEATURE_BITS | \
FEATURE_VIRTIO_NET_F_GUEST_TSO_FEATURE_BITS)
+
+typedef struct
+{
+ char *sock_filename;
+ u64 feature_mask;
+ u32 custom_dev_instance;
+ u8 hwaddr[6];
+ u8 renumber;
+ u8 is_server;
+ u8 enable_gso;
+ u8 enable_packed;
+ u8 enable_event_idx;
+
+ /* return */
+ u32 sw_if_index;
+} vhost_user_create_if_args_t;
+
int vhost_user_create_if (vnet_main_t * vnm, vlib_main_t * vm,
- const char *sock_filename, u8 is_server,
- u32 * sw_if_index, u64 feature_mask,
- u8 renumber, u32 custom_dev_instance, u8 * hwaddr,
- u8 enable_gso, u8 enable_packed);
+ vhost_user_create_if_args_t * args);
int vhost_user_modify_if (vnet_main_t * vnm, vlib_main_t * vm,
- const char *sock_filename, u8 is_server,
- u32 sw_if_index, u64 feature_mask,
- u8 renumber, u32 custom_dev_instance,
- u8 enable_gso, u8 enable_packed);
+ vhost_user_create_if_args_t * args);
int vhost_user_delete_if (vnet_main_t * vnm, vlib_main_t * vm,
u32 sw_if_index);
@@ -216,6 +227,9 @@ typedef struct
u16 used_wrap_counter;
u16 avail_wrap_counter;
+
+ u16 last_kick;
+ u8 first_kick;
} vhost_user_vring_t;
#define VHOST_USER_EVENT_START_TIMER 1
@@ -272,6 +286,7 @@ typedef struct
/* Packed ring configured */
u8 enable_packed;
+ u8 enable_event_idx;
} vhost_user_intf_t;
typedef struct
diff --git a/src/vnet/devices/virtio/vhost_user_api.c b/src/vnet/devices/virtio/vhost_user_api.c
index ec335c529f2..a4e027f214e 100644
--- a/src/vnet/devices/virtio/vhost_user_api.c
+++ b/src/vnet/devices/virtio/vhost_user_api.c
@@ -48,6 +48,8 @@
#define foreach_vpe_api_msg \
_(CREATE_VHOST_USER_IF, create_vhost_user_if) \
_(MODIFY_VHOST_USER_IF, modify_vhost_user_if) \
+_(CREATE_VHOST_USER_IF_V2, create_vhost_user_if_v2) \
+_(MODIFY_VHOST_USER_IF_V2, modify_vhost_user_if_v2) \
_(DELETE_VHOST_USER_IF, delete_vhost_user_if) \
_(SW_INTERFACE_VHOST_USER_DUMP, sw_interface_vhost_user_dump)
@@ -56,14 +58,13 @@ vl_api_create_vhost_user_if_t_handler (vl_api_create_vhost_user_if_t * mp)
{
int rv = 0;
vl_api_create_vhost_user_if_reply_t *rmp;
- u32 sw_if_index = (u32) ~ 0;
vnet_main_t *vnm = vnet_get_main ();
vlib_main_t *vm = vlib_get_main ();
- u64 features = (u64) ~ (0ULL);
u64 disabled_features = (u64) (0ULL);
- mac_address_t mac;
- u8 *mac_p = NULL;
+ vhost_user_create_if_args_t args = { 0 };
+ args.sw_if_index = (u32) ~ 0;
+ args.feature_mask = (u64) ~ (0ULL);
if (mp->disable_mrg_rxbuf)
disabled_features = VIRTIO_FEATURE (VIRTIO_NET_F_MRG_RXBUF);
@@ -77,18 +78,21 @@ vl_api_create_vhost_user_if_t_handler (vl_api_create_vhost_user_if_t * mp)
*/
disabled_features |= FEATURE_VIRTIO_NET_F_HOST_GUEST_TSO_FEATURE_BITS |
VIRTIO_FEATURE (VIRTIO_F_RING_PACKED);
- features &= ~disabled_features;
+
+ /* EVENT_IDX is disabled by default */
+ disabled_features |= VIRTIO_FEATURE (VIRTIO_RING_F_EVENT_IDX);
+ args.feature_mask &= ~disabled_features;
if (mp->use_custom_mac)
- {
- mac_address_decode (mp->mac_address, &mac);
- mac_p = (u8 *) & mac;
- }
+ mac_address_decode (mp->mac_address, (mac_address_t *) args.hwaddr);
- rv = vhost_user_create_if (vnm, vm, (char *) mp->sock_filename,
- mp->is_server, &sw_if_index, features,
- mp->renumber, ntohl (mp->custom_dev_instance),
- mac_p, mp->enable_gso, mp->enable_packed);
+ args.is_server = mp->is_server;
+ args.sock_filename = (char *) mp->sock_filename;
+ args.renumber = mp->renumber;
+ args.custom_dev_instance = ntohl (mp->custom_dev_instance);
+ args.enable_gso = mp->enable_gso;
+ args.enable_packed = mp->enable_packed;
+ rv = vhost_user_create_if (vnm, vm, &args);
/* Remember an interface tag for the new interface */
if (rv == 0)
@@ -99,14 +103,14 @@ vl_api_create_vhost_user_if_t_handler (vl_api_create_vhost_user_if_t * mp)
/* Make sure it's a proper C-string */
mp->tag[ARRAY_LEN (mp->tag) - 1] = 0;
u8 *tag = format (0, "%s%c", mp->tag, 0);
- vnet_set_sw_interface_tag (vnm, tag, sw_if_index);
+ vnet_set_sw_interface_tag (vnm, tag, args.sw_if_index);
}
}
/* *INDENT-OFF* */
REPLY_MACRO2(VL_API_CREATE_VHOST_USER_IF_REPLY,
({
- rmp->sw_if_index = ntohl (sw_if_index);
+ rmp->sw_if_index = ntohl (args.sw_if_index);
}));
/* *INDENT-ON* */
}
@@ -116,13 +120,12 @@ vl_api_modify_vhost_user_if_t_handler (vl_api_modify_vhost_user_if_t * mp)
{
int rv = 0;
vl_api_modify_vhost_user_if_reply_t *rmp;
- u32 sw_if_index = ntohl (mp->sw_if_index);
- u64 features = (u64) ~ (0ULL);
u64 disabled_features = (u64) (0ULL);
-
+ vhost_user_create_if_args_t args = { 0 };
vnet_main_t *vnm = vnet_get_main ();
vlib_main_t *vm = vlib_get_main ();
+ args.feature_mask = (u64) ~ (0ULL);
/*
* GSO and PACKED are not supported by feature mask via binary API. We
* disable GSO and PACKED feature in the feature mask. They may be enabled
@@ -130,17 +133,125 @@ vl_api_modify_vhost_user_if_t_handler (vl_api_modify_vhost_user_if_t * mp)
*/
disabled_features |= FEATURE_VIRTIO_NET_F_HOST_GUEST_TSO_FEATURE_BITS |
VIRTIO_FEATURE (VIRTIO_F_RING_PACKED);
- features &= ~disabled_features;
- rv = vhost_user_modify_if (vnm, vm, (char *) mp->sock_filename,
- mp->is_server, sw_if_index, features,
- mp->renumber, ntohl (mp->custom_dev_instance),
- mp->enable_gso, mp->enable_packed);
+ /* EVENT_IDX is disabled by default */
+ disabled_features |= VIRTIO_FEATURE (VIRTIO_RING_F_EVENT_IDX);
+ args.feature_mask &= ~disabled_features;
+
+ args.sw_if_index = ntohl (mp->sw_if_index);
+ args.sock_filename = (char *) mp->sock_filename;
+ args.is_server = mp->is_server;
+ args.renumber = mp->renumber;
+ args.custom_dev_instance = ntohl (mp->custom_dev_instance);
+ args.enable_gso = mp->enable_gso;
+ args.enable_packed = mp->enable_packed;
+ rv = vhost_user_modify_if (vnm, vm, &args);
REPLY_MACRO (VL_API_MODIFY_VHOST_USER_IF_REPLY);
}
static void
+vl_api_create_vhost_user_if_v2_t_handler (vl_api_create_vhost_user_if_v2_t *
+ mp)
+{
+ int rv = 0;
+ vl_api_create_vhost_user_if_v2_reply_t *rmp;
+ vnet_main_t *vnm = vnet_get_main ();
+ vlib_main_t *vm = vlib_get_main ();
+ u64 disabled_features = (u64) (0ULL);
+ vhost_user_create_if_args_t args = { 0 };
+
+ args.sw_if_index = (u32) ~ 0;
+ args.feature_mask = (u64) ~ (0ULL);
+ if (mp->disable_mrg_rxbuf)
+ disabled_features = VIRTIO_FEATURE (VIRTIO_NET_F_MRG_RXBUF);
+
+ if (mp->disable_indirect_desc)
+ disabled_features |= VIRTIO_FEATURE (VIRTIO_RING_F_INDIRECT_DESC);
+
+ /*
+ * GSO and PACKED are not supported by feature mask via binary API. We
+ * disable GSO and PACKED feature in the feature mask. They may be enabled
+ * explicitly via enable_gso and enable_packed argument
+ */
+ disabled_features |= FEATURE_VIRTIO_NET_F_HOST_GUEST_TSO_FEATURE_BITS |
+ VIRTIO_FEATURE (VIRTIO_F_RING_PACKED);
+
+ /* EVENT_IDX is disabled by default */
+ disabled_features |= VIRTIO_FEATURE (VIRTIO_RING_F_EVENT_IDX);
+ args.feature_mask &= ~disabled_features;
+
+ if (mp->use_custom_mac)
+ mac_address_decode (mp->mac_address, (mac_address_t *) args.hwaddr);
+
+ args.is_server = mp->is_server;
+ args.sock_filename = (char *) mp->sock_filename;
+ args.renumber = mp->renumber;
+ args.custom_dev_instance = ntohl (mp->custom_dev_instance);
+ args.enable_gso = mp->enable_gso;
+ args.enable_packed = mp->enable_packed;
+ args.enable_event_idx = mp->enable_event_idx;
+ rv = vhost_user_create_if (vnm, vm, &args);
+
+ /* Remember an interface tag for the new interface */
+ if (rv == 0)
+ {
+ /* If a tag was supplied... */
+ if (mp->tag[0])
+ {
+ /* Make sure it's a proper C-string */
+ mp->tag[ARRAY_LEN (mp->tag) - 1] = 0;
+ u8 *tag = format (0, "%s%c", mp->tag, 0);
+ vnet_set_sw_interface_tag (vnm, tag, args.sw_if_index);
+ }
+ }
+
+ /* *INDENT-OFF* */
+ REPLY_MACRO2(VL_API_CREATE_VHOST_USER_IF_V2_REPLY,
+ ({
+ rmp->sw_if_index = ntohl (args.sw_if_index);
+ }));
+ /* *INDENT-ON* */
+}
+
+static void
+vl_api_modify_vhost_user_if_v2_t_handler (vl_api_modify_vhost_user_if_v2_t *
+ mp)
+{
+ int rv = 0;
+ vl_api_modify_vhost_user_if_v2_reply_t *rmp;
+ u64 disabled_features = (u64) (0ULL);
+ vhost_user_create_if_args_t args = { 0 };
+ vnet_main_t *vnm = vnet_get_main ();
+ vlib_main_t *vm = vlib_get_main ();
+
+ args.feature_mask = (u64) ~ (0ULL);
+ /*
+ * GSO and PACKED are not supported by feature mask via binary API. We
+ * disable GSO and PACKED feature in the feature mask. They may be enabled
+ * explicitly via enable_gso and enable_packed argument
+ */
+ disabled_features |= FEATURE_VIRTIO_NET_F_HOST_GUEST_TSO_FEATURE_BITS |
+ VIRTIO_FEATURE (VIRTIO_F_RING_PACKED);
+
+ /* EVENT_IDX is disabled by default */
+ disabled_features |= VIRTIO_FEATURE (VIRTIO_RING_F_EVENT_IDX);
+ args.feature_mask &= ~disabled_features;
+
+ args.sw_if_index = ntohl (mp->sw_if_index);
+ args.sock_filename = (char *) mp->sock_filename;
+ args.is_server = mp->is_server;
+ args.renumber = mp->renumber;
+ args.custom_dev_instance = ntohl (mp->custom_dev_instance);
+ args.enable_gso = mp->enable_gso;
+ args.enable_packed = mp->enable_packed;
+ args.enable_event_idx = mp->enable_event_idx;
+ rv = vhost_user_modify_if (vnm, vm, &args);
+
+ REPLY_MACRO (VL_API_MODIFY_VHOST_USER_IF_V2_REPLY);
+}
+
+static void
vl_api_delete_vhost_user_if_t_handler (vl_api_delete_vhost_user_if_t * mp)
{
int rv = 0;
@@ -263,6 +374,7 @@ vhost_user_api_hookup (vlib_main_t * vm)
/* Mark CREATE_VHOST_USER_IF as mp safe */
am->is_mp_safe[VL_API_CREATE_VHOST_USER_IF] = 1;
+ am->is_mp_safe[VL_API_CREATE_VHOST_USER_IF_V2] = 1;
/*
* Set up the (msg_name, crc, message-id) table
diff --git a/src/vnet/devices/virtio/vhost_user_inline.h b/src/vnet/devices/virtio/vhost_user_inline.h
index 17b6a90618f..5297453c317 100644
--- a/src/vnet/devices/virtio/vhost_user_inline.h
+++ b/src/vnet/devices/virtio/vhost_user_inline.h
@@ -248,8 +248,20 @@ format_vhost_trace (u8 * s, va_list * va)
return s;
}
+static_always_inline u64
+vhost_user_is_packed_ring_supported (vhost_user_intf_t * vui)
+{
+ return (vui->features & VIRTIO_FEATURE (VIRTIO_F_RING_PACKED));
+}
+
+static_always_inline u64
+vhost_user_is_event_idx_supported (vhost_user_intf_t * vui)
+{
+ return (vui->features & VIRTIO_FEATURE (VIRTIO_RING_F_EVENT_IDX));
+}
+
static_always_inline void
-vhost_user_send_call (vlib_main_t * vm, vhost_user_vring_t * vq)
+vhost_user_kick (vlib_main_t * vm, vhost_user_vring_t * vq)
{
vhost_user_main_t *vum = &vhost_user_main;
u64 x = 1;
@@ -257,7 +269,7 @@ vhost_user_send_call (vlib_main_t * vm, vhost_user_vring_t * vq)
int rv;
rv = write (fd, &x, sizeof (x));
- if (rv <= 0)
+ if (PREDICT_FALSE (rv <= 0))
{
clib_unix_warning
("Error: Could not write to unix socket for callfd %d", fd);
@@ -268,6 +280,101 @@ vhost_user_send_call (vlib_main_t * vm, vhost_user_vring_t * vq)
vq->int_deadline = vlib_time_now (vm) + vum->coalesce_time;
}
+static_always_inline u16
+vhost_user_avail_event_idx (vhost_user_vring_t * vq)
+{
+ volatile u16 *event_idx = (u16 *) & (vq->used->ring[vq->qsz_mask + 1]);
+
+ return *event_idx;
+}
+
+static_always_inline u16
+vhost_user_used_event_idx (vhost_user_vring_t * vq)
+{
+ volatile u16 *event_idx = (u16 *) & (vq->avail->ring[vq->qsz_mask + 1]);
+
+ return *event_idx;
+}
+
+static_always_inline u16
+vhost_user_need_event (u16 event_idx, u16 new_idx, u16 old_idx)
+{
+ return ((u16) (new_idx - event_idx - 1) < (u16) (new_idx - old_idx));
+}
+
+static_always_inline void
+vhost_user_send_call_event_idx (vlib_main_t * vm, vhost_user_vring_t * vq)
+{
+ vhost_user_main_t *vum = &vhost_user_main;
+ u8 first_kick = vq->first_kick;
+ u16 event_idx = vhost_user_used_event_idx (vq);
+
+ vq->first_kick = 1;
+ if (vhost_user_need_event (event_idx, vq->last_used_idx, vq->last_kick) ||
+ PREDICT_FALSE (!first_kick))
+ {
+ vhost_user_kick (vm, vq);
+ vq->last_kick = event_idx;
+ }
+ else
+ {
+ vq->n_since_last_int = 0;
+ vq->int_deadline = vlib_time_now (vm) + vum->coalesce_time;
+ }
+}
+
+static_always_inline void
+vhost_user_send_call_event_idx_packed (vlib_main_t * vm,
+ vhost_user_vring_t * vq)
+{
+ vhost_user_main_t *vum = &vhost_user_main;
+ u8 first_kick = vq->first_kick;
+ u16 off_wrap;
+ u16 event_idx;
+ u16 new_idx = vq->last_used_idx;
+ u16 old_idx = vq->last_kick;
+
+ if (PREDICT_TRUE (vq->avail_event->flags == VRING_EVENT_F_DESC))
+ {
+ CLIB_COMPILER_BARRIER ();
+ off_wrap = vq->avail_event->off_wrap;
+ event_idx = off_wrap & 0x7fff;
+ if (vq->used_wrap_counter != (off_wrap >> 15))
+ event_idx -= (vq->qsz_mask + 1);
+
+ if (new_idx <= old_idx)
+ old_idx -= (vq->qsz_mask + 1);
+
+ vq->first_kick = 1;
+ vq->last_kick = event_idx;
+ if (vhost_user_need_event (event_idx, new_idx, old_idx) ||
+ PREDICT_FALSE (!first_kick))
+ vhost_user_kick (vm, vq);
+ else
+ {
+ vq->n_since_last_int = 0;
+ vq->int_deadline = vlib_time_now (vm) + vum->coalesce_time;
+ }
+ }
+ else
+ vhost_user_kick (vm, vq);
+}
+
+static_always_inline void
+vhost_user_send_call (vlib_main_t * vm, vhost_user_intf_t * vui,
+ vhost_user_vring_t * vq)
+{
+ if (vhost_user_is_event_idx_supported (vui))
+ {
+ if (vhost_user_is_packed_ring_supported (vui))
+ vhost_user_send_call_event_idx_packed (vm, vq);
+ else
+ vhost_user_send_call_event_idx (vm, vq);
+ }
+ else
+ vhost_user_kick (vm, vq);
+}
+
static_always_inline u8
vui_is_link_up (vhost_user_intf_t * vui)
{
@@ -305,7 +412,10 @@ vhost_user_advance_last_avail_idx (vhost_user_vring_t * vring)
{
vring->last_avail_idx++;
if (PREDICT_FALSE ((vring->last_avail_idx & vring->qsz_mask) == 0))
- vring->avail_wrap_counter ^= VRING_DESC_F_AVAIL;
+ {
+ vring->avail_wrap_counter ^= VRING_DESC_F_AVAIL;
+ vring->last_avail_idx = 0;
+ }
}
static_always_inline void
@@ -331,7 +441,11 @@ vhost_user_undo_advanced_last_avail_idx (vhost_user_vring_t * vring)
{
if (PREDICT_FALSE ((vring->last_avail_idx & vring->qsz_mask) == 0))
vring->avail_wrap_counter ^= VRING_DESC_F_AVAIL;
- vring->last_avail_idx--;
+
+ if (PREDICT_FALSE (vring->last_avail_idx == 0))
+ vring->last_avail_idx = vring->qsz_mask;
+ else
+ vring->last_avail_idx--;
}
static_always_inline void
@@ -362,13 +476,10 @@ vhost_user_advance_last_used_idx (vhost_user_vring_t * vring)
{
vring->last_used_idx++;
if (PREDICT_FALSE ((vring->last_used_idx & vring->qsz_mask) == 0))
- vring->used_wrap_counter ^= 1;
-}
-
-static_always_inline u64
-vhost_user_is_packed_ring_supported (vhost_user_intf_t * vui)
-{
- return (vui->features & VIRTIO_FEATURE (VIRTIO_F_RING_PACKED));
+ {
+ vring->used_wrap_counter ^= 1;
+ vring->last_used_idx = 0;
+ }
}
#endif
diff --git a/src/vnet/devices/virtio/vhost_user_input.c b/src/vnet/devices/virtio/vhost_user_input.c
index 53230a61bc7..7ea70c629f8 100644
--- a/src/vnet/devices/virtio/vhost_user_input.c
+++ b/src/vnet/devices/virtio/vhost_user_input.c
@@ -320,16 +320,17 @@ vhost_user_handle_rx_offload (vlib_buffer_t * b0, u8 * b0_data,
}
static_always_inline void
-vhost_user_input_do_interrupt (vlib_main_t * vm, vhost_user_vring_t * txvq,
+vhost_user_input_do_interrupt (vlib_main_t * vm, vhost_user_intf_t * vui,
+ vhost_user_vring_t * txvq,
vhost_user_vring_t * rxvq)
{
f64 now = vlib_time_now (vm);
if ((txvq->n_since_last_int) && (txvq->int_deadline < now))
- vhost_user_send_call (vm, txvq);
+ vhost_user_send_call (vm, vui, txvq);
if ((rxvq->n_since_last_int) && (rxvq->int_deadline < now))
- vhost_user_send_call (vm, rxvq);
+ vhost_user_send_call (vm, vui, rxvq);
}
static_always_inline void
@@ -400,7 +401,7 @@ vhost_user_if_input (vlib_main_t * vm,
{
/* do we have pending interrupts ? */
vhost_user_vring_t *rxvq = &vui->vrings[VHOST_VRING_IDX_RX (qid)];
- vhost_user_input_do_interrupt (vm, txvq, rxvq);
+ vhost_user_input_do_interrupt (vm, vui, txvq, rxvq);
}
/*
@@ -742,7 +743,7 @@ stop:
txvq->n_since_last_int += n_rx_packets;
if (txvq->n_since_last_int > vum->coalesce_frames)
- vhost_user_send_call (vm, txvq);
+ vhost_user_send_call (vm, vui, txvq);
}
/* increase rx counters */
@@ -1116,7 +1117,7 @@ vhost_user_if_input_packed (vlib_main_t * vm, vhost_user_main_t * vum,
/* do we have pending interrupts ? */
vhost_user_vring_t *rxvq = &vui->vrings[VHOST_VRING_IDX_RX (qid)];
- vhost_user_input_do_interrupt (vm, txvq, rxvq);
+ vhost_user_input_do_interrupt (vm, vui, txvq, rxvq);
/*
* For adaptive mode, it is optimized to reduce interrupts.
@@ -1389,7 +1390,7 @@ vhost_user_if_input_packed (vlib_main_t * vm, vhost_user_main_t * vum,
{
txvq->n_since_last_int += n_rx_packets;
if (txvq->n_since_last_int > vum->coalesce_frames)
- vhost_user_send_call (vm, txvq);
+ vhost_user_send_call (vm, vui, txvq);
}
/* increase rx counters */
diff --git a/src/vnet/devices/virtio/vhost_user_output.c b/src/vnet/devices/virtio/vhost_user_output.c
index 80eefa6d9ed..465c0ea0903 100644
--- a/src/vnet/devices/virtio/vhost_user_output.c
+++ b/src/vnet/devices/virtio/vhost_user_output.c
@@ -279,7 +279,8 @@ vhost_user_handle_tx_offload (vhost_user_intf_t * vui, vlib_buffer_t * b,
}
static_always_inline void
-vhost_user_mark_desc_available (vlib_main_t * vm, vhost_user_vring_t * rxvq,
+vhost_user_mark_desc_available (vlib_main_t * vm, vhost_user_intf_t * vui,
+ vhost_user_vring_t * rxvq,
u16 * n_descs_processed, u8 chained,
vlib_frame_t * frame, u32 n_left)
{
@@ -334,7 +335,7 @@ vhost_user_mark_desc_available (vlib_main_t * vm, vhost_user_vring_t * rxvq,
rxvq->n_since_last_int += frame->n_vectors - n_left;
if (rxvq->n_since_last_int > vum->coalesce_frames)
- vhost_user_send_call (vm, rxvq);
+ vhost_user_send_call (vm, vui, rxvq);
}
}
@@ -645,7 +646,7 @@ retry:
copy_len = 0;
/* give buffers back to driver */
- vhost_user_mark_desc_available (vm, rxvq, &n_descs_processed,
+ vhost_user_mark_desc_available (vm, vui, rxvq, &n_descs_processed,
chained, frame, n_left);
}
@@ -660,8 +661,8 @@ done:
vlib_error_count (vm, node->node_index,
VHOST_USER_TX_FUNC_ERROR_MMAP_FAIL, 1);
- vhost_user_mark_desc_available (vm, rxvq, &n_descs_processed, chained,
- frame, n_left);
+ vhost_user_mark_desc_available (vm, vui, rxvq, &n_descs_processed,
+ chained, frame, n_left);
}
/*
@@ -1019,7 +1020,7 @@ done:
rxvq->n_since_last_int += frame->n_vectors - n_left;
if (rxvq->n_since_last_int > vum->coalesce_frames)
- vhost_user_send_call (vm, rxvq);
+ vhost_user_send_call (vm, vui, rxvq);
}
vhost_user_vring_unlock (vui, qid);
diff --git a/src/vnet/devices/virtio/virtio_std.h b/src/vnet/devices/virtio/virtio_std.h
index 98befb5c820..619dd66d5ed 100644
--- a/src/vnet/devices/virtio/virtio_std.h
+++ b/src/vnet/devices/virtio/virtio_std.h
@@ -77,9 +77,17 @@ typedef enum
#define VRING_DESC_F_AVAIL (1 << 7)
#define VRING_DESC_F_USED (1 << 15)
-#define VRING_EVENT_F_ENABLE 0x0
-#define VRING_EVENT_F_DISABLE 0x1
-#define VRING_EVENT_F_DESC 0x2
+#define foreach_virtio_event_idx_flags \
+ _ (VRING_EVENT_F_ENABLE, 0) \
+ _ (VRING_EVENT_F_DISABLE, 1) \
+ _ (VRING_EVENT_F_DESC, 2)
+
+typedef enum
+{
+#define _(f,n) f = n,
+ foreach_virtio_event_idx_flags
+#undef _
+} virtio_event_idx_flags_t;
#define VRING_USED_F_NO_NOTIFY 1
#define VRING_AVAIL_F_NO_INTERRUPT 1
diff --git a/src/vpp/api/custom_dump.c b/src/vpp/api/custom_dump.c
index 1bc4cde900d..cd81a722b99 100644
--- a/src/vpp/api/custom_dump.c
+++ b/src/vpp/api/custom_dump.c
@@ -1627,6 +1627,57 @@ static void *vl_api_modify_vhost_user_if_t_print
FINISH;
}
+static void *vl_api_create_vhost_user_if_v2_t_print
+ (vl_api_create_vhost_user_if_v2_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: create_vhost_user_if_v2 ");
+
+ s = format (s, "socket %s ", mp->sock_filename);
+ if (mp->is_server)
+ s = format (s, "server ");
+ if (mp->renumber)
+ s = format (s, "renumber %d ", (mp->custom_dev_instance));
+ if (mp->disable_mrg_rxbuf)
+ s = format (s, "disable_mrg_rxbuf ");
+ if (mp->disable_indirect_desc)
+ s = format (s, "disable_indirect_desc ");
+ if (mp->tag[0])
+ s = format (s, "tag %s ", mp->tag);
+ if (mp->enable_gso)
+ s = format (s, "gso ");
+ if (mp->enable_event_idx)
+ s = format (s, "event-idx ");
+ if (mp->enable_packed)
+ s = format (s, "packed");
+
+ FINISH;
+}
+
+static void *vl_api_modify_vhost_user_if_v2_t_print
+ (vl_api_modify_vhost_user_if_v2_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: modify_vhost_user_if_v2 ");
+
+ s = format (s, "sw_if_index %d ", (mp->sw_if_index));
+ s = format (s, "socket %s ", mp->sock_filename);
+ if (mp->is_server)
+ s = format (s, "server ");
+ if (mp->renumber)
+ s = format (s, "renumber %d ", (mp->custom_dev_instance));
+ if (mp->enable_gso)
+ s = format (s, "gso ");
+ if (mp->enable_event_idx)
+ s = format (s, "event-idx ");
+ if (mp->enable_packed)
+ s = format (s, "packed");
+
+ FINISH;
+}
+
static void *vl_api_delete_vhost_user_if_t_print
(vl_api_delete_vhost_user_if_t * mp, void *handle)
{
@@ -2995,6 +3046,8 @@ _(L2_INTERFACE_EFP_FILTER, l2_interface_efp_filter) \
_(L2_INTERFACE_VLAN_TAG_REWRITE, l2_interface_vlan_tag_rewrite) \
_(CREATE_VHOST_USER_IF, create_vhost_user_if) \
_(MODIFY_VHOST_USER_IF, modify_vhost_user_if) \
+_(CREATE_VHOST_USER_IF_V2, create_vhost_user_if_v2) \
+_(MODIFY_VHOST_USER_IF_V2, modify_vhost_user_if_v2) \
_(DELETE_VHOST_USER_IF, delete_vhost_user_if) \
_(SW_INTERFACE_DUMP, sw_interface_dump) \
_(CONTROL_PING, control_ping) \
diff --git a/test/vpp_vhost_interface.py b/test/vpp_vhost_interface.py
index fd2928eac1d..8fa2d7172f1 100644
--- a/test/vpp_vhost_interface.py
+++ b/test/vpp_vhost_interface.py
@@ -5,8 +5,9 @@ class VppVhostInterface(VppInterface):
"""VPP vhost interface."""
def __init__(self, test, sock_filename, is_server=0, renumber=0,
- disable_mrg_rxbuf=0, disable_indirect_desc=0, gso=0,
- packed_ring=0, custom_dev_instance=0, use_custom_mac=0,
+ disable_mrg_rxbuf=0, disable_indirect_desc=0, enable_gso=0,
+ enable_packed_ring=0, enable_event_idx=0,
+ custom_dev_instance=0xFFFFFFFF, use_custom_mac=0,
mac_address='', tag=''):
""" Create VPP Vhost interface """
@@ -16,25 +17,27 @@ class VppVhostInterface(VppInterface):
self.renumber = renumber
self.disable_mrg_rxbuf = disable_mrg_rxbuf
self.disable_indirect_desc = disable_indirect_desc
- self.gso = gso
- self.packed_ring = packed_ring
+ self.enable_gso = enable_gso
+ self.enable_packed_ring = enable_packed_ring
+ self.enable_event_idx = enable_event_idx
self.custom_dev_instance = custom_dev_instance
self.use_custom_mac = use_custom_mac
self.mac_address = mac_address
self.tag = tag
def add_vpp_config(self):
- r = self.test.vapi.create_vhost_user_if(self.is_server,
- self.sock_filename,
- self.renumber,
- self.disable_mrg_rxbuf,
- self.disable_indirect_desc,
- self.gso,
- self.packed_ring,
- self.custom_dev_instance,
- self.use_custom_mac,
- self.mac_address,
- self.tag)
+ r = self.test.vapi.create_vhost_user_if_v2(self.is_server,
+ self.sock_filename,
+ self.renumber,
+ self.disable_mrg_rxbuf,
+ self.disable_indirect_desc,
+ self.enable_gso,
+ self.enable_packed_ring,
+ self.enable_event_idx,
+ self.custom_dev_instance,
+ self.use_custom_mac,
+ self.mac_address,
+ self.tag)
self.set_sw_if_index(r.sw_if_index)
def remove_vpp_config(self):