net/netvsc: fix multiple channel Rx
authorLong Li <longli@microsoft.com>
Tue, 11 Aug 2020 02:33:11 +0000 (19:33 -0700)
committerFerruh Yigit <ferruh.yigit@intel.com>
Fri, 18 Sep 2020 16:55:06 +0000 (18:55 +0200)
netvsc uses rxbuf_info buffer to track received packets attached via
rte_pktmbuf_attach_extbuf() and ack the host based on usage count. It
uses the transaction_id in the VMBus packet to locate where to use
memory in the rxbuf_info.

This is not correct in multiple channel setup, as different channels may
return identical transaction_ids at a time, and may corrupt the
rxbuf_info buffer.

Fix this by defining rxbuf_info for each queue.

Fixes: 4e9c73e96e83 ("net/netvsc: add Hyper-V network device")
Cc: stable@dpdk.org
Signed-off-by: Long Li <longli@microsoft.com>
Acked-by: Stephen Hemminger <stephen@networkplumber.org>
drivers/net/netvsc/hn_nvs.c
drivers/net/netvsc/hn_rxtx.c
drivers/net/netvsc/hn_var.h

index f88854d..eeb82ab 100644 (file)
@@ -223,9 +223,15 @@ hn_nvs_conn_rxbuf(struct hn_data *hv)
                    resp.nvs_sect[0].slotcnt);
        hv->rxbuf_section_cnt = resp.nvs_sect[0].slotcnt;
 
-       hv->rxbuf_info = rte_calloc("HN_RXBUF_INFO", hv->rxbuf_section_cnt,
-                                   sizeof(*hv->rxbuf_info), RTE_CACHE_LINE_SIZE);
-       if (!hv->rxbuf_info) {
+       /*
+        * Pimary queue's rxbuf_info is not allocated at creation time.
+        * Now we can allocate it after we figure out the slotcnt.
+        */
+       hv->primary->rxbuf_info = rte_calloc("HN_RXBUF_INFO",
+                       hv->rxbuf_section_cnt,
+                       sizeof(*hv->primary->rxbuf_info),
+                       RTE_CACHE_LINE_SIZE);
+       if (!hv->primary->rxbuf_info) {
                PMD_DRV_LOG(ERR,
                            "could not allocate rxbuf info");
                return -ENOMEM;
@@ -255,7 +261,6 @@ hn_nvs_disconn_rxbuf(struct hn_data *hv)
                            error);
        }
 
-       rte_free(hv->rxbuf_info);
        /*
         * Linger long enough for NVS to disconnect RXBUF.
         */
index 87b1184..c8c4ee1 100644 (file)
@@ -524,21 +524,21 @@ next:
 static void hn_rx_buf_free_cb(void *buf __rte_unused, void *opaque)
 {
        struct hn_rx_bufinfo *rxb = opaque;
-       struct hn_data *hv = rxb->hv;
+       struct hn_rx_queue *rxq = rxb->rxq;
 
-       rte_atomic32_dec(&hv->rxbuf_outstanding);
+       rte_atomic32_dec(&rxq->rxbuf_outstanding);
        hn_nvs_ack_rxbuf(rxb->chan, rxb->xactid);
 }
 
-static struct hn_rx_bufinfo *hn_rx_buf_init(const struct hn_rx_queue *rxq,
+static struct hn_rx_bufinfo *hn_rx_buf_init(struct hn_rx_queue *rxq,
                                            const struct vmbus_chanpkt_rxbuf *pkt)
 {
        struct hn_rx_bufinfo *rxb;
 
-       rxb = rxq->hv->rxbuf_info + pkt->hdr.xactid;
+       rxb = rxq->rxbuf_info + pkt->hdr.xactid;
        rxb->chan = rxq->chan;
        rxb->xactid = pkt->hdr.xactid;
-       rxb->hv = rxq->hv;
+       rxb->rxq = rxq;
 
        rxb->shinfo.free_cb = hn_rx_buf_free_cb;
        rxb->shinfo.fcb_opaque = rxb;
@@ -568,7 +568,7 @@ static void hn_rxpkt(struct hn_rx_queue *rxq, struct hn_rx_bufinfo *rxb,
         * some space available in receive area for later packets.
         */
        if (dlen >= HN_RXCOPY_THRESHOLD &&
-           (uint32_t)rte_atomic32_read(&hv->rxbuf_outstanding) <
+           (uint32_t)rte_atomic32_read(&rxq->rxbuf_outstanding) <
                        hv->rxbuf_section_cnt / 2) {
                struct rte_mbuf_ext_shared_info *shinfo;
                const void *rxbuf;
@@ -585,7 +585,7 @@ static void hn_rxpkt(struct hn_rx_queue *rxq, struct hn_rx_bufinfo *rxb,
 
                /* shinfo is already set to 1 by the caller */
                if (rte_mbuf_ext_refcnt_update(shinfo, 1) == 2)
-                       rte_atomic32_inc(&hv->rxbuf_outstanding);
+                       rte_atomic32_inc(&rxq->rxbuf_outstanding);
 
                rte_pktmbuf_attach_extbuf(m, data, iova,
                                          dlen + headroom, shinfo);
@@ -888,6 +888,23 @@ struct hn_rx_queue *hn_rx_queue_alloc(struct hn_data *hv,
                return NULL;
        }
 
+       /* setup rxbuf_info for non-primary queue */
+       if (queue_id) {
+               rxq->rxbuf_info = rte_calloc("HN_RXBUF_INFO",
+                                       hv->rxbuf_section_cnt,
+                                       sizeof(*rxq->rxbuf_info),
+                                       RTE_CACHE_LINE_SIZE);
+
+               if (!rxq->rxbuf_info) {
+                       PMD_DRV_LOG(ERR,
+                               "Could not allocate rxbuf info for queue %d\n",
+                               queue_id);
+                       rte_free(rxq->event_buf);
+                       rte_free(rxq);
+                       return NULL;
+               }
+       }
+
        return rxq;
 }
 
@@ -953,6 +970,7 @@ hn_dev_rx_queue_setup(struct rte_eth_dev *dev,
 
 fail:
        rte_ring_free(rxq->rx_ring);
+       rte_free(rxq->rxbuf_info);
        rte_free(rxq->event_buf);
        rte_free(rxq);
        return error;
@@ -975,6 +993,7 @@ hn_rx_queue_free(struct hn_rx_queue *rxq, bool keep_primary)
        if (keep_primary && rxq == rxq->hv->primary)
                return;
 
+       rte_free(rxq->rxbuf_info);
        rte_free(rxq->event_buf);
        rte_free(rxq);
 }
index 7cb7713..4b63f87 100644 (file)
@@ -83,13 +83,15 @@ struct hn_rx_queue {
        struct hn_stats stats;
 
        void *event_buf;
+       struct hn_rx_bufinfo *rxbuf_info;
+       rte_atomic32_t  rxbuf_outstanding;
 };
 
 
 /* multi-packet data from host */
 struct hn_rx_bufinfo {
        struct vmbus_channel *chan;
-       struct hn_data *hv;
+       struct hn_rx_queue *rxq;
        uint64_t        xactid;
        struct rte_mbuf_ext_shared_info shinfo;
 } __rte_cache_aligned;
@@ -111,9 +113,7 @@ struct hn_data {
        uint32_t        link_speed;
 
        struct rte_mem_resource *rxbuf_res;     /* UIO resource for Rx */
-       struct hn_rx_bufinfo *rxbuf_info;
        uint32_t        rxbuf_section_cnt;      /* # of Rx sections */
-       rte_atomic32_t  rxbuf_outstanding;
        uint16_t        max_queues;             /* Max available queues */
        uint16_t        num_queues;
        uint64_t        rss_offloads;