diff options
author | 2020-11-17 13:30:44 -0800 | |
---|---|---|
committer | 2021-01-08 13:10:58 +0000 | |
commit | 27ba5008a16eddccc0b285272de7f89fd0aa3a24 (patch) | |
tree | 3065040b62ee15ac45b1c1d77dd7421dcb558a5d /src/vnet/devices/virtio/vhost_user.c | |
parent | ed4b38e868c7cabb8e88cc0f1254c95a8f1c5939 (diff) |
vhost: Add event index for interrupt notification to driver
VPP only supports a poor man's approach for interrupt notification to the
driver. It uses a simple binary flag for "interrupt needed" or "interrupt
not needed". Most drivers support more sophisticated event index already.
This feature is to add the long due missing feature and make it configurable,
off by default.
Type: feature
Signed-off-by: Steven Luong <sluong@cisco.com>
Change-Id: I68dab7dd07045cafb49af97b7f70db9b8131ae03
Diffstat (limited to 'src/vnet/devices/virtio/vhost_user.c')
-rw-r--r-- | src/vnet/devices/virtio/vhost_user.c | 261 |
1 files changed, 128 insertions, 133 deletions
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, }; |