+#include "../virtio_pci.h"
+
+int
+vhost_kernel_tap_set_offload(int fd, uint64_t features)
+{
+ unsigned int offload = 0;
+
+ if (features & (1ULL << VIRTIO_NET_F_GUEST_CSUM)) {
+ offload |= TUN_F_CSUM;
+ if (features & (1ULL << VIRTIO_NET_F_GUEST_TSO4))
+ offload |= TUN_F_TSO4;
+ if (features & (1ULL << VIRTIO_NET_F_GUEST_TSO6))
+ offload |= TUN_F_TSO6;
+ if (features & ((1ULL << VIRTIO_NET_F_GUEST_TSO4) |
+ (1ULL << VIRTIO_NET_F_GUEST_TSO6)) &&
+ (features & (1ULL << VIRTIO_NET_F_GUEST_ECN)))
+ offload |= TUN_F_TSO_ECN;
+ if (features & (1ULL << VIRTIO_NET_F_GUEST_UFO))
+ offload |= TUN_F_UFO;
+ }
+
+ /* Check if our kernel supports TUNSETOFFLOAD */
+ if (ioctl(fd, TUNSETOFFLOAD, 0) != 0 && errno == EINVAL) {
+ PMD_DRV_LOG(ERR, "Kernel does't support TUNSETOFFLOAD\n");
+ return -ENOTSUP;
+ }
+
+ if (ioctl(fd, TUNSETOFFLOAD, offload) != 0) {
+ offload &= ~TUN_F_UFO;
+ if (ioctl(fd, TUNSETOFFLOAD, offload) != 0) {
+ PMD_DRV_LOG(ERR, "TUNSETOFFLOAD ioctl() failed: %s\n",
+ strerror(errno));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int
+vhost_kernel_tap_set_queue(int fd, bool attach)
+{
+ struct ifreq ifr = {
+ .ifr_flags = attach ? IFF_ATTACH_QUEUE : IFF_DETACH_QUEUE,
+ };
+
+ return ioctl(fd, TUNSETQUEUE, &ifr);
+}