Commit 3f93522f authored by Jason Wang's avatar Jason Wang Committed by David S. Miller

virtio-net: switch off offloads on demand if possible on XDP set

Current XDP implementation wants guest offloads feature to be disabled
on device. This is inconvenient and means guest can't benefit from
offloads if XDP is not used. This patch tries to address this
limitation by disabling the offloads on demand through control guest
offloads. Guest offloads will be disabled and enabled on demand on XDP
set.
Signed-off-by: default avatarJason Wang <jasowang@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4941d472
...@@ -57,6 +57,11 @@ DECLARE_EWMA(pkt_len, 0, 64) ...@@ -57,6 +57,11 @@ DECLARE_EWMA(pkt_len, 0, 64)
#define VIRTNET_DRIVER_VERSION "1.0.0" #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 virtnet_stats {
struct u64_stats_sync tx_syncp; struct u64_stats_sync tx_syncp;
struct u64_stats_sync rx_syncp; struct u64_stats_sync rx_syncp;
...@@ -164,10 +169,13 @@ struct virtnet_info { ...@@ -164,10 +169,13 @@ struct virtnet_info {
u8 ctrl_promisc; u8 ctrl_promisc;
u8 ctrl_allmulti; u8 ctrl_allmulti;
u16 ctrl_vid; u16 ctrl_vid;
u64 ctrl_offloads;
/* Ethtool settings */ /* Ethtool settings */
u8 duplex; u8 duplex;
u32 speed; u32 speed;
unsigned long guest_offloads;
}; };
struct padded_vnet_hdr { struct padded_vnet_hdr {
...@@ -1897,6 +1905,47 @@ static int virtnet_restore_up(struct virtio_device *vdev) ...@@ -1897,6 +1905,47 @@ static int virtnet_restore_up(struct virtio_device *vdev)
return err; 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, static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
...@@ -1906,10 +1955,11 @@ static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog, ...@@ -1906,10 +1955,11 @@ static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog,
u16 xdp_qp = 0, curr_qp; u16 xdp_qp = 0, curr_qp;
int i, err; int i, err;
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_TSO4) || 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_TSO6) ||
virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_ECN) || virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_ECN) ||
virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_UFO)) { 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"); NL_SET_ERR_MSG_MOD(extack, "Can't set XDP while host is implementing LRO, disable LRO first");
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
...@@ -1956,6 +2006,12 @@ static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog, ...@@ -1956,6 +2006,12 @@ static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog,
for (i = 0; i < vi->max_queue_pairs; i++) { for (i = 0; i < vi->max_queue_pairs; i++) {
old_prog = rtnl_dereference(vi->rq[i].xdp_prog); old_prog = rtnl_dereference(vi->rq[i].xdp_prog);
rcu_assign_pointer(vi->rq[i].xdp_prog, 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) if (old_prog)
bpf_prog_put(old_prog); bpf_prog_put(old_prog);
virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi); virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi);
...@@ -2591,6 +2647,10 @@ static int virtnet_probe(struct virtio_device *vdev) ...@@ -2591,6 +2647,10 @@ static int virtnet_probe(struct virtio_device *vdev)
netif_carrier_on(dev); 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", pr_debug("virtnet: registered device %s with %d RX and TX vq's\n",
dev->name, max_queue_pairs); dev->name, max_queue_pairs);
...@@ -2687,7 +2747,7 @@ static struct virtio_device_id id_table[] = { ...@@ -2687,7 +2747,7 @@ static struct virtio_device_id id_table[] = {
VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN, \ VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN, \
VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ, \ VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ, \
VIRTIO_NET_F_CTRL_MAC_ADDR, \ VIRTIO_NET_F_CTRL_MAC_ADDR, \
VIRTIO_NET_F_MTU VIRTIO_NET_F_MTU, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS
static unsigned int features[] = { static unsigned int features[] = {
VIRTNET_FEATURES, VIRTNET_FEATURES,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment