#define VIRTNET_DRIVER_VERSION "1.0.0"
 
+const unsigned long guest_offloads[] = { VIRTIO_NET_F_GUEST_TSO4,
+                                        VIRTIO_NET_F_GUEST_TSO6,
+                                        VIRTIO_NET_F_GUEST_ECN,
+                                        VIRTIO_NET_F_GUEST_UFO };
+
 struct virtnet_stats {
        struct u64_stats_sync tx_syncp;
        struct u64_stats_sync rx_syncp;
        u8 ctrl_promisc;
        u8 ctrl_allmulti;
        u16 ctrl_vid;
+       u64 ctrl_offloads;
 
        /* Ethtool settings */
        u8 duplex;
        u32 speed;
+
+       unsigned long guest_offloads;
 };
 
 struct padded_vnet_hdr {
        return err;
 }
 
+static int virtnet_set_guest_offloads(struct virtnet_info *vi, u64 offloads)
+{
+       struct scatterlist sg;
+       vi->ctrl_offloads = cpu_to_virtio64(vi->vdev, offloads);
+
+       sg_init_one(&sg, &vi->ctrl_offloads, sizeof(vi->ctrl_offloads));
+
+       if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_GUEST_OFFLOADS,
+                                 VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET, &sg)) {
+               dev_warn(&vi->dev->dev, "Fail to set guest offload. \n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int virtnet_clear_guest_offloads(struct virtnet_info *vi)
+{
+       u64 offloads = 0;
+
+       if (!vi->guest_offloads)
+               return 0;
+
+       if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_CSUM))
+               offloads = 1ULL << VIRTIO_NET_F_GUEST_CSUM;
+
+       return virtnet_set_guest_offloads(vi, offloads);
+}
+
+static int virtnet_restore_guest_offloads(struct virtnet_info *vi)
+{
+       u64 offloads = vi->guest_offloads;
+
+       if (!vi->guest_offloads)
+               return 0;
+       if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_CSUM))
+               offloads |= 1ULL << VIRTIO_NET_F_GUEST_CSUM;
+
+       return virtnet_set_guest_offloads(vi, offloads);
+}
+
 static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog,
                           struct netlink_ext_ack *extack)
 {
        u16 xdp_qp = 0, curr_qp;
        int i, err;
 
-       if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_TSO4) ||
-           virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_TSO6) ||
-           virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_ECN) ||
-           virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_UFO)) {
+       if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)
+           && (virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_TSO4) ||
+               virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_TSO6) ||
+               virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_ECN) ||
+               virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_UFO))) {
                NL_SET_ERR_MSG_MOD(extack, "Can't set XDP while host is implementing LRO, disable LRO first");
                return -EOPNOTSUPP;
        }
        for (i = 0; i < vi->max_queue_pairs; i++) {
                old_prog = rtnl_dereference(vi->rq[i].xdp_prog);
                rcu_assign_pointer(vi->rq[i].xdp_prog, prog);
+               if (i == 0) {
+                       if (!old_prog)
+                               virtnet_clear_guest_offloads(vi);
+                       if (!prog)
+                               virtnet_restore_guest_offloads(vi);
+               }
                if (old_prog)
                        bpf_prog_put(old_prog);
                virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi);
                netif_carrier_on(dev);
        }
 
+       for (i = 0; i < ARRAY_SIZE(guest_offloads); i++)
+               if (virtio_has_feature(vi->vdev, guest_offloads[i]))
+                       set_bit(guest_offloads[i], &vi->guest_offloads);
+
        pr_debug("virtnet: registered device %s with %d RX and TX vq's\n",
                 dev->name, max_queue_pairs);
 
        VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN, \
        VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ, \
        VIRTIO_NET_F_CTRL_MAC_ADDR, \
-       VIRTIO_NET_F_MTU
+       VIRTIO_NET_F_MTU, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS
 
 static unsigned int features[] = {
        VIRTNET_FEATURES,