diff mbox series

[ovs-dev,2/3] userspace TSO: Include UDP checksum offload.

Message ID 20200214130336.583696-3-fbl@sysclose.org
State Accepted
Delegated to: Ilya Maximets
Headers show
Series userspace-tso: Improve L4 csum offload support. | expand

Commit Message

Flavio Leitner Feb. 14, 2020, 1:03 p.m. UTC
Virtio doesn't expose flags to control which protocols checksum
offload needs to be enabled or disabled. This patch checks if the
NIC supports UDP checksum offload and active it when TSO is enabled.

Reported-by: Ilya Maximets <i.maximets@ovn.org>
Fixes: 29cf9c1b3b9c ("userspace: Add TCP Segmentation Offload support")
Signed-off-by: Flavio Leitner <fbl@sysclose.org>
---
 lib/netdev-dpdk.c     | 18 ++++++++++++------
 lib/netdev-linux.c    |  1 +
 lib/netdev-provider.h |  3 ++-
 lib/netdev.c          | 24 ++++++++++++++++++++----
 4 files changed, 35 insertions(+), 11 deletions(-)
diff mbox series

Patch

diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
index 192c174f3..ec8be64aa 100644
--- a/lib/netdev-dpdk.c
+++ b/lib/netdev-dpdk.c
@@ -152,6 +152,14 @@  typedef uint16_t dpdk_port_t;
 
 #define IF_NAME_SZ (PATH_MAX > IFNAMSIZ ? PATH_MAX : IFNAMSIZ)
 
+/* List of required flags advertised by the hardware that will be
+ * used if TSO is enabled. */
+#define DPDK_TX_TSO_OFFLOAD_FLAGS (DEV_TX_OFFLOAD_TCP_TSO        \
+                                   | DEV_TX_OFFLOAD_TCP_CKSUM    \
+                                   | DEV_TX_OFFLOAD_UDP_CKSUM    \
+                                   | DEV_TX_OFFLOAD_IPV4_CKSUM)
+
+
 static const struct rte_eth_conf port_conf = {
     .rxmode = {
         .mq_mode = ETH_MQ_RX_RSS,
@@ -997,9 +1005,7 @@  dpdk_eth_dev_port_config(struct netdev_dpdk *dev, int n_rxq, int n_txq)
     }
 
     if (dev->hw_ol_features & NETDEV_TX_TSO_OFFLOAD) {
-        conf.txmode.offloads |= DEV_TX_OFFLOAD_TCP_TSO;
-        conf.txmode.offloads |= DEV_TX_OFFLOAD_TCP_CKSUM;
-        conf.txmode.offloads |= DEV_TX_OFFLOAD_IPV4_CKSUM;
+        conf.txmode.offloads |= DPDK_TX_TSO_OFFLOAD_FLAGS;
     }
 
     /* Limit configured rss hash functions to only those supported
@@ -1100,12 +1106,10 @@  dpdk_eth_dev_init(struct netdev_dpdk *dev)
     struct rte_ether_addr eth_addr;
     int diag;
     int n_rxq, n_txq;
+    uint32_t tx_tso_offload_capa = DPDK_TX_TSO_OFFLOAD_FLAGS;
     uint32_t rx_chksm_offload_capa = DEV_RX_OFFLOAD_UDP_CKSUM |
                                      DEV_RX_OFFLOAD_TCP_CKSUM |
                                      DEV_RX_OFFLOAD_IPV4_CKSUM;
-    uint32_t tx_tso_offload_capa = DEV_TX_OFFLOAD_TCP_TSO |
-                                   DEV_TX_OFFLOAD_TCP_CKSUM |
-                                   DEV_TX_OFFLOAD_IPV4_CKSUM;
 
     rte_eth_dev_info_get(dev->port_id, &info);
 
@@ -5110,6 +5114,7 @@  netdev_dpdk_reconfigure(struct netdev *netdev)
     if (dev->hw_ol_features & NETDEV_TX_TSO_OFFLOAD) {
         netdev->ol_flags |= NETDEV_TX_OFFLOAD_TCP_TSO;
         netdev->ol_flags |= NETDEV_TX_OFFLOAD_TCP_CKSUM;
+        netdev->ol_flags |= NETDEV_TX_OFFLOAD_UDP_CKSUM;
         netdev->ol_flags |= NETDEV_TX_OFFLOAD_IPV4_CKSUM;
     }
 
@@ -5252,6 +5257,7 @@  netdev_dpdk_vhost_client_reconfigure(struct netdev *netdev)
         if (userspace_tso_enabled()) {
             netdev->ol_flags |= NETDEV_TX_OFFLOAD_TCP_TSO;
             netdev->ol_flags |= NETDEV_TX_OFFLOAD_TCP_CKSUM;
+            netdev->ol_flags |= NETDEV_TX_OFFLOAD_UDP_CKSUM;
             netdev->ol_flags |= NETDEV_TX_OFFLOAD_IPV4_CKSUM;
             vhost_unsup_flags = 1ULL << VIRTIO_NET_F_HOST_ECN
                                 | 1ULL << VIRTIO_NET_F_HOST_UFO;
diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c
index c6f3d2740..85f3a7367 100644
--- a/lib/netdev-linux.c
+++ b/lib/netdev-linux.c
@@ -923,6 +923,7 @@  netdev_linux_common_construct(struct netdev *netdev_)
     if (userspace_tso_enabled()) {
         netdev_->ol_flags |= NETDEV_TX_OFFLOAD_TCP_TSO;
         netdev_->ol_flags |= NETDEV_TX_OFFLOAD_TCP_CKSUM;
+        netdev_->ol_flags |= NETDEV_TX_OFFLOAD_UDP_CKSUM;
         netdev_->ol_flags |= NETDEV_TX_OFFLOAD_IPV4_CKSUM;
     }
 
diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h
index 22f4cde33..00677dc9d 100644
--- a/lib/netdev-provider.h
+++ b/lib/netdev-provider.h
@@ -40,7 +40,8 @@  struct netdev_tnl_build_header_params;
 enum netdev_ol_flags {
     NETDEV_TX_OFFLOAD_IPV4_CKSUM = 1 << 0,
     NETDEV_TX_OFFLOAD_TCP_CKSUM = 1 << 1,
-    NETDEV_TX_OFFLOAD_TCP_TSO = 1 << 2,
+    NETDEV_TX_OFFLOAD_UDP_CKSUM = 1 << 2,
+    NETDEV_TX_OFFLOAD_TCP_TSO = 1 << 3,
 };
 
 /* A network device (e.g. an Ethernet device).
diff --git a/lib/netdev.c b/lib/netdev.c
index f95b19af4..a55f77961 100644
--- a/lib/netdev.c
+++ b/lib/netdev.c
@@ -791,6 +791,8 @@  static bool
 netdev_send_prepare_packet(const uint64_t netdev_flags,
                            struct dp_packet *packet, char **errormsg)
 {
+    uint64_t l4_mask;
+
     if (dp_packet_hwol_is_tso(packet)
         && !(netdev_flags & NETDEV_TX_OFFLOAD_TCP_TSO)) {
             /* Fall back to GSO in software. */
@@ -798,11 +800,25 @@  netdev_send_prepare_packet(const uint64_t netdev_flags,
             return false;
     }
 
-    if (dp_packet_hwol_l4_mask(packet)
-        && !(netdev_flags & NETDEV_TX_OFFLOAD_TCP_CKSUM)) {
-            /* Fall back to L4 csum in software. */
-            VLOG_ERR_BUF(errormsg, "No L4 checksum support");
+    l4_mask = dp_packet_hwol_l4_mask(packet);
+    if (l4_mask) {
+        if (dp_packet_hwol_l4_is_tcp(packet)) {
+            if (!(netdev_flags & NETDEV_TX_OFFLOAD_TCP_CKSUM)) {
+                /* Fall back to TCP csum in software. */
+                VLOG_ERR_BUF(errormsg, "No TCP checksum support");
+                return false;
+            }
+        } else if (dp_packet_hwol_l4_is_udp(packet)) {
+            if (!(netdev_flags & NETDEV_TX_OFFLOAD_UDP_CKSUM)) {
+                /* Fall back to UDP csum in software. */
+                VLOG_ERR_BUF(errormsg, "No UDP checksum support");
+                return false;
+            }
+        } else {
+            VLOG_ERR_BUF(errormsg, "No L4 checksum support: mask: %"PRIu64,
+                         l4_mask);
             return false;
+        }
     }
 
     return true;