对于Linux 3.10,我需要做些什么更改才能使netmap / virtio_net正常工作?

时间:2014-11-21 23:18:15

标签: linux-device-driver

netmap / virtio_net驱动程序不起作用(Linux 3.10内核)。有两个问题。

在kernel.org的3.10.60内核上,virtio_net.c的补丁没有 工作,补丁的一部分被拒绝。这很容易解决。

更严重的是,virtio初始化代码不起作用,也没有 数据包接收代码。基本问题是无法初始化 正确的指数和未能保持1槽之间的分离 头/尾指数。 (同样的问题代码中的2个位置。)

通过创建带有的KVM来宾很容易看出这个问题 netmap / virtio_net驱动程序,只需从主机ping客户端即可。 使用pkt-gen工具可以轻松监控接收流量 客人。

前255个ping将正常工作,当索引达到255时,然后是 数据包接收将失败,并且每次都会在插槽255上继续失败。

1 个答案:

答案 0 :(得分:1)

我在希望源代码中包含了两个问题的补丁 将更新,其他人将不必发现这些问题。

首先是virtio_netmap_3.10.60.patch:

# patch is the whole netmap virtio driver patch for 3.10.60 (from
# kernel.org), and it applies correctly.
#
Index: linux-3.10.60/drivers/net/virtio_net.c
===================================================================
--- linux-3.10.60.orig/drivers/net/virtio_net.c 2014-11-14 11:48:23.000000000 -0500
+++ linux-3.10.60/drivers/net/virtio_net.c      2014-11-21 12:54:29.751760095 -0500
@@ -131,6 +131,10 @@
        struct notifier_block nb;
 };

+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+#include <virtio_netmap.h>
+#endif
+
 struct skb_vnet_hdr {
        union {
                struct virtio_net_hdr hdr;
@@ -210,6 +214,10 @@
        /* Suppress further interrupts. */
        virtqueue_disable_cb(vq);

+#ifdef DEV_NETMAP
+        if (netmap_tx_irq(vi->dev, vq2txq(vq)))
+               return;
+#endif
        /* We were probably waiting for more output buffers. */
        netif_wake_subqueue(vi->dev, vq2txq(vq));
 }
@@ -646,7 +654,16 @@
        struct virtnet_info *vi = rq->vq->vdev->priv;
        void *buf;
        unsigned int r, len, received = 0;
+#ifdef DEV_NETMAP
+       int work_done = 0;
+ 
+       if (netmap_rx_irq(vi->dev, vq2rxq(rq->vq), &work_done)) {
+               napi_complete(napi);
+               ND("called netmap_rx_irq");

+               return 1;
+       }
+#endif
 again:
        while (received < budget &&
               (buf = virtqueue_get_buf(rq->vq, &len)) != NULL) {
@@ -679,6 +696,16 @@
 {
        struct virtnet_info *vi = netdev_priv(dev);
        int i;
+#ifdef DEV_NETMAP
+        int ok = virtio_netmap_init_buffers(vi);
+
+        netmap_enable_all_rings(dev);
+        if (ok) {
+            for (i = 0; i < vi->max_queue_pairs; i++)
+               virtnet_napi_enable(&vi->rq[i]);
+            return 0;
+        }
+#endif

        for (i = 0; i < vi->max_queue_pairs; i++) {
                if (i < vi->curr_queue_pairs)
@@ -972,6 +999,9 @@
        struct virtnet_info *vi = netdev_priv(dev);
        int i;

+#ifdef DEV_NETMAP
+        netmap_disable_all_rings(dev);
+#endif
        /* Make sure refill_work doesn't re-enable napi! */
        cancel_delayed_work_sync(&vi->refill);

@@ -1644,6 +1674,10 @@
                goto free_recv_bufs;
        }

+#ifdef DEV_NETMAP
+        virtio_netmap_attach(vi);
+#endif
+
        /* Assume link up if device can't report link status,
           otherwise get link status from config. */
        if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
@@ -1690,6 +1724,9 @@
 {
        struct virtnet_info *vi = vdev->priv;

+#ifdef DEV_NETMAP
+        netmap_detach(vi->dev);
+#endif
        unregister_hotcpu_notifier(&vi->nb);

        /* Prevent config work handler from accessing the device. */

接下来是virtio_netmap.patch

# There is a problem with the initialization, and during read packet with
# control of the indices .
#
# This problem is easily seen by building a KVM netmap/virtio_net driver, and
# simply pinging it (host pings KVM guest). All goes well, until ring buffer
# reaches index 255, and no packet is actually received. This will fix that
# problem and resulted in a working driver.
#
Index: b/LINUX/virtio_netmap.h
===================================================================
--- a/LINUX/virtio_netmap.h     2014-11-21 16:26:03.951278021 -0500
+++ b/LINUX/virtio_netmap.h     2014-11-21 16:26:25.451386665 -0500
@@ -398,8 +398,8 @@
         * Second part: skip past packets that userspace has released.
         */
        nm_i = kring->nr_hwcur; /* netmap ring index */
-       if (nm_i != head) {
-               for (n = 0; nm_i != head; n++) {
+       if (nm_next(nm_i, lim) != head) {
+               for (n = 0; nm_next(nm_i, lim) != head; n++) {
                        struct netmap_slot *slot = &ring->slot[nm_i];
                        void *addr = NMB(slot);
                         int err;
@@ -421,7 +421,7 @@
                         virtqueue_kick(vq);
                        nm_i = nm_next(nm_i, lim);
                }
-               kring->nr_hwcur = head;
+               kring->nr_hwcur = nm_i;
        }

        /* We have finished processing used RX buffers, so we have to tell
@@ -454,6 +454,7 @@
        for (r = 0; r < na->num_rx_rings; r++) {
                COMPAT_DECL_SG
                 struct netmap_ring *ring = na->rx_rings[r].ring;
+               struct netmap_kring *kring = &na->rx_rings[r];
                struct virtqueue *vq = GET_RX_VQ(vi, r);
                struct scatterlist *sg = GET_RX_SG(vi, r);
                struct netmap_slot* slot;
@@ -485,6 +486,7 @@
                        if (VQ_FULL(vq, err))
                                break;
                }
+               kring->nr_hwcur = i;
                D("added %d inbufs on queue %d", i, r);
                virtqueue_kick(vq);
        }
相关问题