From 8389fb9112bcf96def69539fa1de13a7a08923f5 Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Fri, 13 Oct 2017 18:29:53 +0200 Subject: virtio: fast TAP interfaces with vhost-net backend Change-Id: Ided667356d5c6fb9648eb34685aabd6b16a598b7 Signed-off-by: Damjan Marion Signed-off-by: Steven Luong --- src/vnet/devices/virtio/cli.c | 300 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 300 insertions(+) create mode 100644 src/vnet/devices/virtio/cli.c (limited to 'src/vnet/devices/virtio/cli.c') diff --git a/src/vnet/devices/virtio/cli.c b/src/vnet/devices/virtio/cli.c new file mode 100644 index 00000000000..0c1b75f8c4e --- /dev/null +++ b/src/vnet/devices/virtio/cli.c @@ -0,0 +1,300 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------ + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static clib_error_t * +tap_create_command_fn (vlib_main_t * vm, unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + unformat_input_t _line_input, *line_input = &_line_input; + int rv; + tap_create_if_args_t args = { 0 }; + + /* Get a line of input. */ + if (!unformat_user (input, unformat_line_input, line_input)) + return clib_error_return (0, "Missing name "); + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "name %s", &args.name)) + ; + else if (unformat (line_input, "host-ns %s", &args.net_ns)) + ; + else if (unformat (line_input, "rx-ring-size %d", &args.rx_ring_sz)) + ; + else if (unformat (line_input, "tx-ring-size %d", &args.tx_ring_sz)) + ; + else if (unformat (line_input, "hw-addr %U", + unformat_ethernet_address, args.hw_addr)) + args.hw_addr_set = 1; + else + return clib_error_return (0, "unknown input `%U'", + format_unformat_error, input); + } + unformat_free (line_input); + + rv = tap_create_if (vm, &args); + + vec_free (args.name); + + if (rv == VNET_API_ERROR_SYSCALL_ERROR_1) + return clib_error_return_unix (0, "open '/dev/vhost-net'"); + else if (rv == VNET_API_ERROR_SYSCALL_ERROR_2) + return clib_error_return_unix (0, "open '/dev/net/tun'"); + else if (rv == VNET_API_ERROR_UNSUPPORTED) + return clib_error_return (0, "vhost-net backend doesn't support needed" + " features"); + else if (rv == VNET_API_ERROR_NAMESPACE_CREATE) + return clib_error_return (0, "failed to create netlink namespace"); + else if (rv == VNET_API_ERROR_VIRTIO_INIT) + return clib_error_return (0, "failed to init virtio ring"); + else if (rv == VNET_API_ERROR_INVALID_REGISTRATION) + return clib_error_return (0, "failed to register interface"); + else if (rv != 0) + return clib_error_return (0, "error on creating tap interface"); + + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (tap_create_command, static) = { + .path = "create tap", + .short_help = "create tap {name } [hw-addr ]" + "[rx-ring-size ] [tx-ring-size ] [host-ns ]", + .function = tap_create_command_fn, +}; +/* *INDENT-ON* */ + +static clib_error_t * +tap_delete_command_fn (vlib_main_t * vm, unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + unformat_input_t _line_input, *line_input = &_line_input; + u32 sw_if_index = ~0; + vnet_main_t *vnm = vnet_get_main (); + int rv; + + /* Get a line of input. */ + if (!unformat_user (input, unformat_line_input, line_input)) + return clib_error_return (0, "Missing "); + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "sw_if_index %d", &sw_if_index)) + ; + else if (unformat (line_input, "%U", unformat_vnet_sw_interface, + vnm, &sw_if_index)) + ; + else + return clib_error_return (0, "unknown input `%U'", + format_unformat_error, input); + } + unformat_free (line_input); + + if (sw_if_index == ~0) + return clib_error_return (0, + "please specify interface name or sw_if_index"); + + rv = tap_delete_if (vm, sw_if_index); + if (rv == VNET_API_ERROR_INVALID_SW_IF_INDEX) + return clib_error_return (0, "not a tap interface"); + else if (rv != 0) + return clib_error_return (0, "error on deleting tap interface"); + + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (tap_delete__command, static) = +{ + .path = "delete tap", + .short_help = "delete tap { | sw_if_index }", + .function = tap_delete_command_fn, +}; +/* *INDENT-ON* */ + +static clib_error_t * +tap_show_command_fn (vlib_main_t * vm, unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + virtio_main_t *mm = &virtio_main; + virtio_if_t *vif; + vnet_main_t *vnm = vnet_get_main (); + int show_descr = 0; + clib_error_t *error = 0; + u32 hw_if_index, *hw_if_indices = 0; + virtio_vring_t *vring; + int i, j; + struct feat_struct + { + u8 bit; + char *str; + }; + struct feat_struct *feat_entry; + + static struct feat_struct feat_array[] = { +#define _(s,b) { .str = #s, .bit = b, }, + foreach_virtio_net_features +#undef _ + {.str = NULL} + }; + + struct feat_struct *flag_entry; + static struct feat_struct flags_array[] = { +#define _(b,e,s) { .bit = b, .str = s, }, + foreach_virtio_if_flag +#undef _ + {.str = NULL} + }; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat + (input, "%U", unformat_vnet_hw_interface, vnm, &hw_if_index)) + vec_add1 (hw_if_indices, hw_if_index); + else if (unformat (input, "descriptors")) + show_descr = 1; + else + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, input); + goto done; + } + } + + if (vec_len (hw_if_indices) == 0) + { + /* *INDENT-OFF* */ + pool_foreach (vif, mm->interfaces, + vec_add1 (hw_if_indices, vif->hw_if_index); + ); + /* *INDENT-ON* */ + } + + for (hw_if_index = 0; hw_if_index < vec_len (hw_if_indices); hw_if_index++) + { + vnet_hw_interface_t *hi = + vnet_get_hw_interface (vnm, hw_if_indices[hw_if_index]); + vif = pool_elt_at_index (mm->interfaces, hi->dev_instance); + vlib_cli_output (vm, "interface %U", format_vnet_sw_if_index_name, + vnm, vif->sw_if_index); + if (vif->name) + vlib_cli_output (vm, " name \"%s\"", vif->name); + if (vif->net_ns) + vlib_cli_output (vm, " host-ns \"%s\"", vif->net_ns); + vlib_cli_output (vm, " flags 0x%x", vif->flags); + flag_entry = (struct feat_struct *) &flags_array; + while (flag_entry->str) + { + if (vif->flags & (1ULL << flag_entry->bit)) + vlib_cli_output (vm, " %s (%d)", flag_entry->str, + flag_entry->bit); + flag_entry++; + } + vlib_cli_output (vm, " fd %d", vif->fd); + vlib_cli_output (vm, " tap-fd %d", vif->tap_fd); + vlib_cli_output (vm, " features 0x%lx", vif->features); + feat_entry = (struct feat_struct *) &feat_array; + while (feat_entry->str) + { + if (vif->features & (1ULL << feat_entry->bit)) + vlib_cli_output (vm, " %s (%d)", feat_entry->str, + feat_entry->bit); + feat_entry++; + } + vlib_cli_output (vm, " remote-features 0x%lx", vif->remote_features); + feat_entry = (struct feat_struct *) &feat_array; + while (feat_entry->str) + { + if (vif->remote_features & (1ULL << feat_entry->bit)) + vlib_cli_output (vm, " %s (%d)", feat_entry->str, + feat_entry->bit); + feat_entry++; + } + vec_foreach_index (i, vif->vrings) + { + // RX = 0, TX = 1 + vring = vec_elt_at_index (vif->vrings, i); + vlib_cli_output (vm, " Virtqueue (%s)", (i & 1) ? "TX" : "RX"); + vlib_cli_output (vm, " qsz %d, last_used_idx %d, desc_in_use %d", + vring->size, vring->last_used_idx, + vring->desc_in_use); + vlib_cli_output (vm, + " avail.flags 0x%x avail.idx %d used.flags 0x%x used.idx %d", + vring->avail->flags, vring->avail->idx, + vring->used->flags, vring->used->idx); + vlib_cli_output (vm, " kickfd %d, callfd %d", vring->kick_fd, + vring->call_fd); + if (show_descr) + { + vlib_cli_output (vm, "\n descriptor table:\n"); + vlib_cli_output (vm, + " id addr len flags next user_addr\n"); + vlib_cli_output (vm, + " ===== ================== ===== ====== ===== ==================\n"); + vring = vif->vrings; + for (j = 0; j < vring->size; j++) + { + struct vring_desc *desc = &vring->desc[j]; + vlib_cli_output (vm, + " %-5d 0x%016lx %-5d 0x%04x %-5d 0x%016lx\n", + j, desc->addr, + desc->len, + desc->flags, desc->next, desc->addr); + } + } + } + } +done: + vec_free (hw_if_indices); + return error; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (tap_show_command, static) = { + .path = "show tap", + .short_help = "show tap {] [descriptors]", + .function = tap_show_command_fn, +}; +/* *INDENT-ON* */ + +clib_error_t * +tap_cli_init (vlib_main_t * vm) +{ + return 0; +} + +VLIB_INIT_FUNCTION (tap_cli_init); + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ -- cgit 1.2.3-korg