net/vmxnet3: guess MSS if not provided in LRO mode
authorDidier Pallard <didier.pallard@6wind.com>
Wed, 28 Mar 2018 15:43:47 +0000 (17:43 +0200)
committerFerruh Yigit <ferruh.yigit@intel.com>
Fri, 27 Apr 2018 16:34:41 +0000 (17:34 +0100)
Not so old variants of vmxnet3 do not provide MSS value along with
LRO packet. When this case happens, try to guess MSS value with
information at hand.

Signed-off-by: Didier Pallard <didier.pallard@6wind.com>
Acked-by: Yong Wang <yongwang@vmware.com>
drivers/net/vmxnet3/Makefile
drivers/net/vmxnet3/vmxnet3_ethdev.c
drivers/net/vmxnet3/vmxnet3_ethdev.h
drivers/net/vmxnet3/vmxnet3_rxtx.c

index 9118501..f1141da 100644 (file)
@@ -8,6 +8,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 #
 LIB = librte_pmd_vmxnet3_uio.a
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 
index 19f0325..b5fb39e 100644 (file)
@@ -570,6 +570,8 @@ vmxnet3_setup_driver_shared(struct rte_eth_dev *dev)
        uint32_t i;
        int ret;
 
+       hw->mtu = mtu;
+
        shared->magic = VMXNET3_REV1_MAGIC;
        devRead->misc.driverInfo.version = VMXNET3_DRIVER_VERSION_NUM;
 
index b2a8cf3..d3f2b35 100644 (file)
@@ -87,6 +87,7 @@ struct vmxnet3_hw {
 
        uint64_t              queueDescPA;
        uint16_t              queue_desc_len;
+       uint16_t              mtu;
 
        VMXNET3_RSSConf       *rss_conf;
        uint64_t              rss_confPA;
index 5693c51..02840fe 100644 (file)
@@ -646,6 +646,59 @@ vmxnet3_post_rx_bufs(vmxnet3_rx_queue_t *rxq, uint8_t ring_id)
                return i;
 }
 
+/* MSS not provided by vmxnet3, guess one with available information */
+static uint16_t
+vmxnet3_guess_mss(struct vmxnet3_hw *hw, const Vmxnet3_RxCompDesc *rcd,
+               struct rte_mbuf *rxm)
+{
+       uint32_t hlen, slen;
+       struct ipv4_hdr *ipv4_hdr;
+       struct ipv6_hdr *ipv6_hdr;
+       struct tcp_hdr *tcp_hdr;
+       char *ptr;
+
+       RTE_ASSERT(rcd->tcp);
+
+       ptr = rte_pktmbuf_mtod(rxm, char *);
+       slen = rte_pktmbuf_data_len(rxm);
+       hlen = sizeof(struct ether_hdr);
+
+       if (rcd->v4) {
+               if (unlikely(slen < hlen + sizeof(struct ipv4_hdr)))
+                       return hw->mtu - sizeof(struct ipv4_hdr)
+                                       - sizeof(struct tcp_hdr);
+
+               ipv4_hdr = (struct ipv4_hdr *)(ptr + hlen);
+               hlen += (ipv4_hdr->version_ihl & IPV4_HDR_IHL_MASK) *
+                               IPV4_IHL_MULTIPLIER;
+       } else if (rcd->v6) {
+               if (unlikely(slen < hlen + sizeof(struct ipv6_hdr)))
+                       return hw->mtu - sizeof(struct ipv6_hdr) -
+                                       sizeof(struct tcp_hdr);
+
+               ipv6_hdr = (struct ipv6_hdr *)(ptr + hlen);
+               hlen += sizeof(struct ipv6_hdr);
+               if (unlikely(ipv6_hdr->proto != IPPROTO_TCP)) {
+                       int frag;
+
+                       rte_net_skip_ip6_ext(ipv6_hdr->proto, rxm,
+                                       &hlen, &frag);
+               }
+       }
+
+       if (unlikely(slen < hlen + sizeof(struct tcp_hdr)))
+               return hw->mtu - hlen - sizeof(struct tcp_hdr) +
+                               sizeof(struct ether_hdr);
+
+       tcp_hdr = (struct tcp_hdr *)(ptr + hlen);
+       hlen += (tcp_hdr->data_off & 0xf0) >> 2;
+
+       if (rxm->udata64 > 1)
+               return (rte_pktmbuf_pkt_len(rxm) - hlen +
+                               rxm->udata64 - 1) / rxm->udata64;
+       else
+               return hw->mtu - hlen + sizeof(struct ether_hdr);
+}
 
 /* Receive side checksum and other offloads */
 static inline void
@@ -667,6 +720,7 @@ vmxnet3_rx_offload(struct vmxnet3_hw *hw, const Vmxnet3_RxCompDesc *rcd,
                                        (const Vmxnet3_RxCompDescExt *)rcd;
 
                        rxm->tso_segsz = rcde->mss;
+                       rxm->udata64 = rcde->segCnt;
                        ol_flags |= PKT_RX_LRO;
                }
        } else { /* Offloads set in eop */
@@ -730,6 +784,11 @@ vmxnet3_rx_offload(struct vmxnet3_hw *hw, const Vmxnet3_RxCompDesc *rcd,
                        } else {
                                packet_type |= RTE_PTYPE_UNKNOWN;
                        }
+
+                       /* Old variants of vmxnet3 do not provide MSS */
+                       if ((ol_flags & PKT_RX_LRO) && rxm->tso_segsz == 0)
+                               rxm->tso_segsz = vmxnet3_guess_mss(hw,
+                                               rcd, rxm);
                }
        }