X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Fdevices%2Fvirtio%2Fpci.c;h=c7398c95fe83a24be40b4617d1b832ffc678485f;hb=ce21599c8af34a3f9da813a3c953a38a16316b4d;hp=ab21147aca96b17f4cf803b120ea7f411d5c5784;hpb=edf3b4b04cc02707cf8aafe8fafe1296904a8b66;p=vpp.git diff --git a/src/vnet/devices/virtio/pci.c b/src/vnet/devices/virtio/pci.c index ab21147aca9..c7398c95fe8 100644 --- a/src/vnet/devices/virtio/pci.c +++ b/src/vnet/devices/virtio/pci.c @@ -110,7 +110,7 @@ virtio_pci_legacy_write_config (vlib_main_t * vm, virtio_if_t * vif, } static u64 -virtio_pci_legacy_get_features (vlib_main_t * vm, virtio_if_t * vif) +virtio_pci_legacy_get_host_features (vlib_main_t * vm, virtio_if_t * vif) { u32 features; vlib_pci_read_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_HOST_FEATURES, @@ -119,8 +119,18 @@ virtio_pci_legacy_get_features (vlib_main_t * vm, virtio_if_t * vif) } static u32 -virtio_pci_legacy_set_features (vlib_main_t * vm, virtio_if_t * vif, - u64 features) +virtio_pci_legacy_get_guest_features (vlib_main_t * vm, virtio_if_t * vif) +{ + u32 feature = 0; + vlib_pci_read_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_GUEST_FEATURES, + &feature); + vif->features = feature; + return feature; +} + +static u32 +virtio_pci_legacy_set_guest_features (vlib_main_t * vm, virtio_if_t * vif, + u64 features) { if ((features >> 32) != 0) { @@ -262,7 +272,9 @@ virtio_pci_get_max_virtqueue_pairs (vlib_main_t * vm, virtio_if_t * vif) virtio_log_debug (vif, "max queue pair is %x", max_queue_pairs); if (max_queue_pairs < 1 || max_queue_pairs > 0x8000) - return clib_error_return (error, "max queue pair is %x", max_queue_pairs); + return clib_error_return (error, "max queue pair is %x," + " should be in range [1, 0x8000]", + max_queue_pairs); vif->max_queue_pairs = max_queue_pairs; return error; @@ -554,6 +566,47 @@ virtio_pci_send_ctrl_msg (vlib_main_t * vm, virtio_if_t * vif, return status; } +static int +virtio_pci_disable_offload (vlib_main_t * vm, virtio_if_t * vif) +{ + struct virtio_ctrl_msg offload_hdr; + virtio_net_ctrl_ack status = VIRTIO_NET_ERR; + + offload_hdr.ctrl.class = VIRTIO_NET_CTRL_GUEST_OFFLOADS; + offload_hdr.ctrl.cmd = VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET; + offload_hdr.status = VIRTIO_NET_ERR; + u64 offloads = 0ULL; + clib_memcpy (offload_hdr.data, &offloads, sizeof (offloads)); + + status = + virtio_pci_send_ctrl_msg (vm, vif, &offload_hdr, sizeof (offloads)); + virtio_log_debug (vif, "disable offloads"); + vif->remote_features = virtio_pci_legacy_get_host_features (vm, vif); + virtio_pci_legacy_get_guest_features (vm, vif); + return status; +} + +static int +virtio_pci_enable_checksum_offload (vlib_main_t * vm, virtio_if_t * vif) +{ + struct virtio_ctrl_msg csum_offload_hdr; + virtio_net_ctrl_ack status = VIRTIO_NET_ERR; + + csum_offload_hdr.ctrl.class = VIRTIO_NET_CTRL_GUEST_OFFLOADS; + csum_offload_hdr.ctrl.cmd = VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET; + csum_offload_hdr.status = VIRTIO_NET_ERR; + u64 offloads = 0ULL; + offloads |= VIRTIO_FEATURE (VIRTIO_NET_F_GUEST_CSUM); + clib_memcpy (csum_offload_hdr.data, &offloads, sizeof (offloads)); + + status = + virtio_pci_send_ctrl_msg (vm, vif, &csum_offload_hdr, sizeof (offloads)); + virtio_log_debug (vif, "enable checksum offload"); + vif->remote_features = virtio_pci_legacy_get_host_features (vm, vif); + virtio_pci_legacy_get_guest_features (vm, vif); + return status; +} + static int virtio_pci_enable_gso (vlib_main_t * vm, virtio_if_t * vif) { @@ -565,15 +618,77 @@ virtio_pci_enable_gso (vlib_main_t * vm, virtio_if_t * vif) gso_hdr.status = VIRTIO_NET_ERR; u64 offloads = VIRTIO_FEATURE (VIRTIO_NET_F_GUEST_CSUM) | VIRTIO_FEATURE (VIRTIO_NET_F_GUEST_TSO4) - | VIRTIO_FEATURE (VIRTIO_NET_F_GUEST_TSO6) - | VIRTIO_FEATURE (VIRTIO_NET_F_GUEST_UFO); + | VIRTIO_FEATURE (VIRTIO_NET_F_GUEST_TSO6); clib_memcpy (gso_hdr.data, &offloads, sizeof (offloads)); status = virtio_pci_send_ctrl_msg (vm, vif, &gso_hdr, sizeof (offloads)); virtio_log_debug (vif, "enable gso"); + vif->remote_features = virtio_pci_legacy_get_host_features (vm, vif); + virtio_pci_legacy_get_guest_features (vm, vif); return status; } +static int +virtio_pci_offloads (vlib_main_t * vm, virtio_if_t * vif, int gso_enabled, + int csum_offload_enabled) +{ + vnet_main_t *vnm = vnet_get_main (); + vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, vif->hw_if_index); + + if ((vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_CTRL_VQ)) && + (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_CTRL_GUEST_OFFLOADS))) + { + if (gso_enabled + && (vif->features & (VIRTIO_FEATURE (VIRTIO_NET_F_HOST_TSO4) | + VIRTIO_FEATURE (VIRTIO_NET_F_HOST_TSO6)))) + { + if (virtio_pci_enable_gso (vm, vif)) + { + virtio_log_warning (vif, "gso is not enabled"); + } + else + { + vif->gso_enabled = 1; + vif->csum_offload_enabled = 0; + hw->flags |= VNET_HW_INTERFACE_FLAG_SUPPORTS_GSO | + VNET_HW_INTERFACE_FLAG_SUPPORTS_TX_L4_CKSUM_OFFLOAD; + } + } + else if (csum_offload_enabled + && (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_CSUM))) + { + if (virtio_pci_enable_checksum_offload (vm, vif)) + { + virtio_log_warning (vif, "checksum offload is not enabled"); + } + else + { + vif->csum_offload_enabled = 1; + vif->gso_enabled = 0; + hw->flags &= ~VNET_HW_INTERFACE_FLAG_SUPPORTS_GSO; + hw->flags |= + VNET_HW_INTERFACE_FLAG_SUPPORTS_TX_L4_CKSUM_OFFLOAD; + } + } + else + { + if (virtio_pci_disable_offload (vm, vif)) + { + virtio_log_warning (vif, "offloads are not disabled"); + } + else + { + vif->csum_offload_enabled = 0; + vif->gso_enabled = 0; + hw->flags &= ~(VNET_HW_INTERFACE_FLAG_SUPPORTS_GSO | + VNET_HW_INTERFACE_FLAG_SUPPORTS_TX_L4_CKSUM_OFFLOAD); + } + } + } + + return 0; +} + static int virtio_pci_enable_multiqueue (vlib_main_t * vm, virtio_if_t * vif, u16 num_queues) @@ -710,6 +825,7 @@ virtio_pci_vring_init (vlib_main_t * vm, virtio_if_t * vif, u16 queue_num) { virtio_log_debug (vif, "tx-queue: number %u, size %u", queue_num, queue_size); + clib_memset_u32 (vring->buffers, ~0, queue_size); } else { @@ -770,13 +886,14 @@ virtio_negotiate_features (vlib_main_t * vm, virtio_if_t * vif, vif->features &= ~VIRTIO_FEATURE (VIRTIO_NET_F_MTU); } - vif->features = virtio_pci_legacy_set_features (vm, vif, vif->features); + vif->features = + virtio_pci_legacy_set_guest_features (vm, vif, vif->features); } void virtio_pci_read_device_feature (vlib_main_t * vm, virtio_if_t * vif) { - vif->remote_features = virtio_pci_legacy_get_features (vm, vif); + vif->remote_features = virtio_pci_legacy_get_host_features (vm, vif); } int @@ -919,10 +1036,15 @@ virtio_pci_device_init (vlib_main_t * vm, virtio_if_t * vif, u8 status = 0; if ((error = virtio_pci_read_caps (vm, vif))) - clib_error_return (error, "Device is not supported"); + { + args->rv = VNET_API_ERROR_UNSUPPORTED; + virtio_log_error (vif, "Device is not supported"); + clib_error_return (error, "Device is not supported"); + } if (virtio_pci_reset_device (vm, vif) < 0) { + args->rv = VNET_API_ERROR_INIT_FAILED; virtio_log_error (vif, "Failed to reset the device"); clib_error_return (error, "Failed to reset the device"); } @@ -930,6 +1052,17 @@ virtio_pci_device_init (vlib_main_t * vm, virtio_if_t * vif, * read device features and negotiate (user) requested features */ virtio_pci_read_device_feature (vm, vif); + if ((vif->remote_features & VIRTIO_FEATURE (VIRTIO_RING_F_INDIRECT_DESC)) == + 0) + { + virtio_log_warning (vif, "error encountered: vhost-net backend doesn't " + "support VIRTIO_RING_F_INDIRECT_DESC features"); + } + if ((vif->remote_features & VIRTIO_FEATURE (VIRTIO_NET_F_MRG_RXBUF)) == 0) + { + virtio_log_warning (vif, "error encountered: vhost-net backend doesn't " + "support VIRTIO_NET_F_MRG_RXBUF features"); + } virtio_negotiate_features (vm, vif, args->features); /* @@ -939,6 +1072,7 @@ virtio_pci_device_init (vlib_main_t * vm, virtio_if_t * vif, status = virtio_pci_legacy_get_status (vm, vif); if (!(status & VIRTIO_CONFIG_STATUS_FEATURES_OK)) { + args->rv = VNET_API_ERROR_UNSUPPORTED; virtio_log_error (vif, "error encountered: Device doesn't support requested features"); clib_error_return (error, "Device doesn't support requested features"); @@ -967,14 +1101,20 @@ virtio_pci_device_init (vlib_main_t * vm, virtio_if_t * vif, * Initialize the virtqueues */ if ((error = virtio_pci_get_max_virtqueue_pairs (vm, vif))) - goto err; + { + args->rv = VNET_API_ERROR_EXCEEDED_NUMBER_OF_RANGES_CAPACITY; + goto err; + } for (int i = 0; i < vif->max_queue_pairs; i++) { if ((error = virtio_pci_vring_init (vm, vif, RX_QUEUE (i)))) { - virtio_log_warning (vif, "%s (%u) %s", "error in rxq-queue", - RX_QUEUE (i), "initialization"); + args->rv = VNET_API_ERROR_INIT_FAILED; + virtio_log_error (vif, "%s (%u) %s", "error in rxq-queue", + RX_QUEUE (i), "initialization"); + clib_error_return (error, "%s (%u) %s", "error in rxq-queue", + RX_QUEUE (i), "initialization"); } else { @@ -999,8 +1139,11 @@ virtio_pci_device_init (vlib_main_t * vm, virtio_if_t * vif, if ((error = virtio_pci_vring_init (vm, vif, TX_QUEUE (i)))) { - virtio_log_warning (vif, "%s (%u) %s", "error in txq-queue", - TX_QUEUE (i), "initialization"); + args->rv = VNET_API_ERROR_INIT_FAILED; + virtio_log_error (vif, "%s (%u) %s", "error in txq-queue", + TX_QUEUE (i), "initialization"); + clib_error_return (error, "%s (%u) %s", "error in txq-queue", + TX_QUEUE (i), "initialization"); } else { @@ -1060,7 +1203,7 @@ virtio_pci_create_if (vlib_main_t * vm, virtio_pci_create_if_args_t * args) pool_foreach (vif, vim->interfaces, ({ if (vif->pci_addr.as_u32 == args->addr) { - args->rv = VNET_API_ERROR_INVALID_VALUE; + args->rv = VNET_API_ERROR_ADDRESS_IN_USE; args->error = clib_error_return (error, "PCI address in use"); vlib_log (VLIB_LOG_LEVEL_ERR, vim->log_default, "%U: %s", @@ -1112,6 +1255,7 @@ virtio_pci_create_if (vlib_main_t * vm, virtio_pci_create_if_args_t * args) if ((error = vlib_pci_register_msix_handler (vm, h, 0, 1, &virtio_pci_irq_0_handler))) { + args->rv = VNET_API_ERROR_INVALID_REGISTRATION; virtio_log_error (vif, "error encountered on pci register msix handler 0"); goto error; @@ -1119,6 +1263,7 @@ virtio_pci_create_if (vlib_main_t * vm, virtio_pci_create_if_args_t * args) if ((error = vlib_pci_register_msix_handler (vm, h, 1, 1, &virtio_pci_irq_1_handler))) { + args->rv = VNET_API_ERROR_INVALID_REGISTRATION; virtio_log_error (vif, "error encountered on pci register msix handler 1"); goto error; @@ -1177,6 +1322,7 @@ virtio_pci_create_if (vlib_main_t * vm, virtio_pci_create_if_args_t * args) if (error) { + args->rv = VNET_API_ERROR_INVALID_REGISTRATION; virtio_log_error (vif, "error encountered on ethernet register interface"); goto error; @@ -1208,33 +1354,21 @@ virtio_pci_create_if (vlib_main_t * vm, virtio_pci_create_if_args_t * args) else vnet_hw_interface_set_flags (vnm, vif->hw_if_index, 0); - if (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_CTRL_VQ)) + virtio_pci_offloads (vm, vif, args->gso_enabled, + args->checksum_offload_enabled); + + if ((vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_CTRL_VQ)) && + (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_MQ))) { - if (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_CTRL_GUEST_OFFLOADS) && - args->gso_enabled) - { - if (virtio_pci_enable_gso (vm, vif)) - { - virtio_log_warning (vif, "gso is not enabled"); - } - else - { - vif->gso_enabled = 1; - hw->flags |= VNET_HW_INTERFACE_FLAG_SUPPORTS_GSO; - } - } - if (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_MQ)) - { - if (virtio_pci_enable_multiqueue (vm, vif, vif->max_queue_pairs)) - virtio_log_warning (vif, "multiqueue is not set"); - } + if (virtio_pci_enable_multiqueue (vm, vif, vif->max_queue_pairs)) + virtio_log_warning (vif, "multiqueue is not set"); } return; - error: virtio_pci_delete_if (vm, vif); - args->rv = VNET_API_ERROR_INVALID_INTERFACE; + if (args->rv == 0) + args->rv = VNET_API_ERROR_INVALID_INTERFACE; args->error = error; } @@ -1325,6 +1459,25 @@ virtio_pci_delete_if (vlib_main_t * vm, virtio_if_t * vif) return 0; } +int +virtio_pci_enable_disable_offloads (vlib_main_t * vm, virtio_if_t * vif, + int gso_enabled, + int checksum_offload_enabled, + int offloads_disabled) +{ + if (vif->type != VIRTIO_IF_TYPE_PCI) + return VNET_API_ERROR_INVALID_INTERFACE; + + if (gso_enabled) + virtio_pci_offloads (vm, vif, 1, 0); + else if (checksum_offload_enabled) + virtio_pci_offloads (vm, vif, 0, 1); + else if (offloads_disabled) + virtio_pci_offloads (vm, vif, 0, 0); + + return 0; +} + /* * fd.io coding-style-patch-verification: ON *