netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/4] virtio_net: Fix skb->csum_start computation
@ 2008-06-08 10:49 Rusty Russell
  2008-06-08 10:49 ` [PATCH 2/4] virtio: Fix typo in virtio_net_hdr comments Rusty Russell
  2008-06-10 22:21 ` [PATCH 1/4] virtio_net: Fix skb->csum_start computation Jeff Garzik
  0 siblings, 2 replies; 5+ messages in thread
From: Rusty Russell @ 2008-06-08 10:49 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: netdev, virtualization

From: Mark McLoughlin <markmc@redhat.com>

hdr->csum_start is the offset from the start of the ethernet
header to the transport layer checksum field. skb->csum_start
is the offset from skb->head.

skb_partial_csum_set() assumes that skb->data points to the
ethernet header - i.e. it computes skb->csum_start by adding
the headroom to hdr->csum_start.

Since eth_type_trans() skb_pull()s the ethernet header,
skb_partial_csum_set() should be called before
eth_type_trans().

(Without this patch, GSO packets from a guest to the world outside the
host are corrupted).

Signed-off-by: Mark McLoughlin <markmc@redhat.com>
Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
 drivers/net/virtio_net.c |    8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 50e6e59..503486f 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -86,9 +86,7 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb,
 	BUG_ON(len > MAX_PACKET_LEN);
 
 	skb_trim(skb, len);
-	skb->protocol = eth_type_trans(skb, dev);
-	pr_debug("Receiving skb proto 0x%04x len %i type %i\n",
-		 ntohs(skb->protocol), skb->len, skb->pkt_type);
+
 	dev->stats.rx_bytes += skb->len;
 	dev->stats.rx_packets++;
 
@@ -98,6 +96,10 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb,
 			goto frame_err;
 	}
 
+	skb->protocol = eth_type_trans(skb, dev);
+	pr_debug("Receiving skb proto 0x%04x len %i type %i\n",
+		 ntohs(skb->protocol), skb->len, skb->pkt_type);
+
 	if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
 		pr_debug("GSO!\n");
 		switch (hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/4] virtio: Fix typo in virtio_net_hdr comments
  2008-06-08 10:49 [PATCH 1/4] virtio_net: Fix skb->csum_start computation Rusty Russell
@ 2008-06-08 10:49 ` Rusty Russell
  2008-06-08 10:50   ` [PATCH 3/4] virtio: virtio_net free transmit skbs in a timer Rusty Russell
  2008-06-10 22:21 ` [PATCH 1/4] virtio_net: Fix skb->csum_start computation Jeff Garzik
  1 sibling, 1 reply; 5+ messages in thread
From: Rusty Russell @ 2008-06-08 10:49 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: netdev, virtualization, Mark McLoughlin

From: Mark McLoughlin <markmc@redhat.com>

Signed-off-by: Mark McLoughlin <markmc@redhat.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
 include/linux/virtio_net.h |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h
index 9405aa6..38c0571 100644
--- a/include/linux/virtio_net.h
+++ b/include/linux/virtio_net.h
@@ -38,7 +38,7 @@ struct virtio_net_hdr
 #define VIRTIO_NET_HDR_GSO_ECN		0x80	// TCP has ECN set
 	__u8 gso_type;
 	__u16 hdr_len;		/* Ethernet + IP + tcp/udp hdrs */
-	__u16 gso_size;		/* Bytes to append to gso_hdr_len per frame */
+	__u16 gso_size;		/* Bytes to append to hdr_len per frame */
 	__u16 csum_start;	/* Position to start checksumming from */
 	__u16 csum_offset;	/* Offset after that to place checksum */
 };

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 3/4] virtio: virtio_net free transmit skbs in a timer
  2008-06-08 10:49 ` [PATCH 2/4] virtio: Fix typo in virtio_net_hdr comments Rusty Russell
@ 2008-06-08 10:50   ` Rusty Russell
  2008-06-08 10:51     ` [PATCH 4/4] virtio: use callback on empty in virtio_net Rusty Russell
  0 siblings, 1 reply; 5+ messages in thread
From: Rusty Russell @ 2008-06-08 10:50 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: netdev, virtualization, Mark McLoughlin

From: Mark McLoughlin <markmc@redhat.com>

virtio_net currently only frees old transmit skbs just
before queueing new ones. If the queue is full, it then
enables interrupts and waits for notification that more
work has been performed.

However, a side-effect of this scheme is that there are
always xmit skbs left dangling when no new packets are
sent, against the Documentation/networking/driver.txt
guideline:

  "... it is not allowed for your TX mitigation scheme
   to let TX packets "hang out" in the TX ring unreclaimed
   forever if no new TX packets are sent."

Add a timer to ensure that any time we queue new TX
skbs, we will shortly free them again.

This fixes an easily reproduced hang at shutdown where
iptables attempts to unload nf_conntrack and nf_conntrack
waits for an skb it is tracking to be freed, but virtio_net
never frees it.

Signed-off-by: Mark McLoughlin <markmc@redhat.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
 drivers/net/virtio_net.c |   28 ++++++++++++++++++++++++++--
 1 file changed, 26 insertions(+), 2 deletions(-)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -43,6 +43,8 @@ struct virtnet_info
 
 	/* The skb we couldn't send because buffers were full. */
 	struct sk_buff *last_xmit_skb;
+
+	struct timer_list xmit_free_timer;
 
 	/* Number of input buffers, and max we've ever had. */
 	unsigned int num, max;
@@ -238,9 +240,23 @@ static void free_old_xmit_skbs(struct vi
 	}
 }
 
+static void xmit_free(unsigned long data)
+{
+	struct virtnet_info *vi = (void *)data;
+
+	netif_tx_lock(vi->dev);
+
+	free_old_xmit_skbs(vi);
+
+	if (!skb_queue_empty(&vi->send))
+		mod_timer(&vi->xmit_free_timer, jiffies + (HZ/10));
+
+	netif_tx_unlock(vi->dev);
+}
+
 static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb)
 {
-	int num;
+	int num, err;
 	struct scatterlist sg[2+MAX_SKB_FRAGS];
 	struct virtio_net_hdr *hdr;
 	const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
@@ -283,7 +299,11 @@ static int xmit_skb(struct virtnet_info 
 	vnet_hdr_to_sg(sg, skb);
 	num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1;
 
-	return vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb);
+	err = vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb);
+	if (!err)
+		mod_timer(&vi->xmit_free_timer, jiffies + (HZ/10));
+
+	return err;
 }
 
 static void xmit_tasklet(unsigned long data)
@@ -452,6 +472,8 @@ static int virtnet_probe(struct virtio_d
 
 	tasklet_init(&vi->tasklet, xmit_tasklet, (unsigned long)vi);
 
+	setup_timer(&vi->xmit_free_timer, xmit_free, (unsigned long)vi);
+
 	err = register_netdev(dev);
 	if (err) {
 		pr_debug("virtio_net: registering device failed\n");
@@ -488,6 +510,8 @@ static void virtnet_remove(struct virtio
 
 	/* Stop all the virtqueues. */
 	vdev->config->reset(vdev);
+
+	del_timer_sync(&vi->xmit_free_timer);
 
 	/* Free our skbs in send and recv queues, if any. */
 	while ((skb = __skb_dequeue(&vi->recv)) != NULL) {

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 4/4] virtio: use callback on empty in virtio_net
  2008-06-08 10:50   ` [PATCH 3/4] virtio: virtio_net free transmit skbs in a timer Rusty Russell
@ 2008-06-08 10:51     ` Rusty Russell
  0 siblings, 0 replies; 5+ messages in thread
From: Rusty Russell @ 2008-06-08 10:51 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: netdev, virtualization, Mark McLoughlin

virtio_net uses a timer to free old transmitted packets, rather than
leaving callbacks enabled all the time.  If the host promises to
always notify us when the transmit ring is empty, we can free packets
at that point and avoid the timer.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
 drivers/net/virtio_net.c |   22 +++++++++++++++++-----
 1 file changed, 17 insertions(+), 5 deletions(-)

diff -r 95a02f0e0e21 drivers/net/virtio_net.c
--- a/drivers/net/virtio_net.c	Tue May 27 12:45:17 2008 +1000
+++ b/drivers/net/virtio_net.c	Tue May 27 15:53:41 2008 +1000
@@ -44,6 +44,7 @@ struct virtnet_info
 	/* The skb we couldn't send because buffers were full. */
 	struct sk_buff *last_xmit_skb;
 
+	/* If we need to free in a timer, this is it. */
 	struct timer_list xmit_free_timer;
 
 	/* Number of input buffers, and max we've ever had. */
@@ -51,6 +52,7 @@ struct virtnet_info
 
 	/* For cleaning up after transmission. */
 	struct tasklet_struct tasklet;
+	bool free_in_tasklet;
 
 	/* Receive & send queues. */
 	struct sk_buff_head recv;
@@ -74,7 +76,7 @@ static void skb_xmit_done(struct virtque
 	/* Suppress further interrupts. */
 	svq->vq_ops->disable_cb(svq);
 
-	/* We were waiting for more output buffers. */
+	/* We were probably waiting for more output buffers. */
 	netif_wake_queue(vi->dev);
 
 	/* Make sure we re-xmit last_xmit_skb: if there are no more packets
@@ -240,6 +242,8 @@ static void free_old_xmit_skbs(struct vi
 	}
 }
 
+/* If the virtio transport doesn't always notify us when all in-flight packets
+ * are consumed, we fall back to using this function on a timer to free them. */
 static void xmit_free(unsigned long data)
 {
 	struct virtnet_info *vi = (void *)data;
@@ -300,7 +304,7 @@ static int xmit_skb(struct virtnet_info 
 	num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1;
 
 	err = vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb);
-	if (!err)
+	if (!err && !vi->free_in_tasklet)
 		mod_timer(&vi->xmit_free_timer, jiffies + (HZ/10));
 
 	return err;
@@ -315,6 +319,8 @@ static void xmit_tasklet(unsigned long d
 		vi->svq->vq_ops->kick(vi->svq);
 		vi->last_xmit_skb = NULL;
 	}
+	if (vi->free_in_tasklet)
+		free_old_xmit_skbs(vi);
 	netif_tx_unlock_bh(vi->dev);
 }
 
@@ -455,6 +461,10 @@ static int virtnet_probe(struct virtio_d
 	vi->vdev = vdev;
 	vdev->priv = vi;
 
+	/* If they give us a callback when all buffers are done, we don't need
+	 * the timer. */
+	vi->free_in_tasklet = virtio_has_feature(vdev,VIRTIO_F_NOTIFY_ON_EMPTY);
+
 	/* We expect two virtqueues, receive then send. */
 	vi->rvq = vdev->config->find_vq(vdev, 0, skb_recv_done);
 	if (IS_ERR(vi->rvq)) {
@@ -474,7 +487,8 @@ static int virtnet_probe(struct virtio_d
 
 	tasklet_init(&vi->tasklet, xmit_tasklet, (unsigned long)vi);
 
-	setup_timer(&vi->xmit_free_timer, xmit_free, (unsigned long)vi);
+	if (!vi->free_in_tasklet)
+		setup_timer(&vi->xmit_free_timer, xmit_free, (unsigned long)vi);
 
 	err = register_netdev(dev);
 	if (err) {
@@ -513,7 +527,8 @@ static void virtnet_remove(struct virtio
 	/* Stop all the virtqueues. */
 	vdev->config->reset(vdev);
 
-	del_timer_sync(&vi->xmit_free_timer);
+	if (!vi->free_in_tasklet)
+		del_timer_sync(&vi->xmit_free_timer);
 
 	/* Free our skbs in send and recv queues, if any. */
 	while ((skb = __skb_dequeue(&vi->recv)) != NULL) {
@@ -538,7 +553,7 @@ static unsigned int features[] = {
 static unsigned int features[] = {
 	VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GSO, VIRTIO_NET_F_MAC,
 	VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6,
-	VIRTIO_NET_F_HOST_ECN,
+	VIRTIO_NET_F_HOST_ECN, VIRTIO_F_NOTIFY_ON_EMPTY,
 };
 
 static struct virtio_driver virtio_net = {

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/4] virtio_net: Fix skb->csum_start computation
  2008-06-08 10:49 [PATCH 1/4] virtio_net: Fix skb->csum_start computation Rusty Russell
  2008-06-08 10:49 ` [PATCH 2/4] virtio: Fix typo in virtio_net_hdr comments Rusty Russell
@ 2008-06-10 22:21 ` Jeff Garzik
  1 sibling, 0 replies; 5+ messages in thread
From: Jeff Garzik @ 2008-06-10 22:21 UTC (permalink / raw)
  To: Rusty Russell; +Cc: netdev, virtualization

Rusty Russell wrote:
> From: Mark McLoughlin <markmc@redhat.com>
> 
> hdr->csum_start is the offset from the start of the ethernet
> header to the transport layer checksum field. skb->csum_start
> is the offset from skb->head.
> 
> skb_partial_csum_set() assumes that skb->data points to the
> ethernet header - i.e. it computes skb->csum_start by adding
> the headroom to hdr->csum_start.
> 
> Since eth_type_trans() skb_pull()s the ethernet header,
> skb_partial_csum_set() should be called before
> eth_type_trans().
> 
> (Without this patch, GSO packets from a guest to the world outside the
> host are corrupted).
> 
> Signed-off-by: Mark McLoughlin <markmc@redhat.com>
> Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
> ---
>  drivers/net/virtio_net.c |    8 +++++---
>  1 file changed, 5 insertions(+), 3 deletions(-)

applied 1-4



^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2008-06-10 22:21 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-06-08 10:49 [PATCH 1/4] virtio_net: Fix skb->csum_start computation Rusty Russell
2008-06-08 10:49 ` [PATCH 2/4] virtio: Fix typo in virtio_net_hdr comments Rusty Russell
2008-06-08 10:50   ` [PATCH 3/4] virtio: virtio_net free transmit skbs in a timer Rusty Russell
2008-06-08 10:51     ` [PATCH 4/4] virtio: use callback on empty in virtio_net Rusty Russell
2008-06-10 22:21 ` [PATCH 1/4] virtio_net: Fix skb->csum_start computation Jeff Garzik

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).