+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)
+{
+ struct virtio_ctrl_msg gso_hdr;
+ virtio_net_ctrl_ack status = VIRTIO_NET_ERR;
+
+ gso_hdr.ctrl.class = VIRTIO_NET_CTRL_GUEST_OFFLOADS;
+ gso_hdr.ctrl.cmd = VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET;
+ 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);
+ 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)
+{
+ struct virtio_ctrl_msg mq_hdr;
+ virtio_net_ctrl_ack status = VIRTIO_NET_ERR;
+
+ mq_hdr.ctrl.class = VIRTIO_NET_CTRL_MQ;
+ mq_hdr.ctrl.cmd = VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET;
+ mq_hdr.status = VIRTIO_NET_ERR;
+ clib_memcpy (mq_hdr.data, &num_queues, sizeof (num_queues));
+
+ status = virtio_pci_send_ctrl_msg (vm, vif, &mq_hdr, sizeof (num_queues));
+ virtio_log_debug (vif, "multi-queue enable %u queues", num_queues);
+ return status;
+}
+