3e5111
From 40bd6c3ac6e183b504b38192938d0178438d3966 Mon Sep 17 00:00:00 2001
3e5111
Message-Id: <40bd6c3ac6e183b504b38192938d0178438d3966@dist-git>
3e5111
From: Martin Kletzander <mkletzan@redhat.com>
3e5111
Date: Tue, 25 Apr 2017 13:41:15 +0200
3e5111
Subject: [PATCH] util: Add virNetDevSetCoalesce function
3e5111
3e5111
https://bugzilla.redhat.com/show_bug.cgi?id=1414627
3e5111
3e5111
That function is able to configure coalesce settings for an interface,
3e5111
similarly to 'ethtool -C'.  This function also updates back the
3e5111
structure so that it contains actual data on the device (if the device
3e5111
doesn't support some settings kernel might just return 0 and not set
3e5111
whatever is not supported), so this way we'll have up-to-date
3e5111
information in the live domain XML.
3e5111
3e5111
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
3e5111
(cherry picked from commit 652ef9bc8c72a7118436a8c95c5742ec6a6d12a3)
3e5111
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
3e5111
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
3e5111
---
3e5111
 configure.ac             |  3 +-
3e5111
 src/libvirt_private.syms |  1 +
3e5111
 src/util/virnetdev.c     | 83 ++++++++++++++++++++++++++++++++++++++++++++++++
3e5111
 src/util/virnetdev.h     | 34 ++++++++++++++++++++
3e5111
 4 files changed, 120 insertions(+), 1 deletion(-)
3e5111
3e5111
diff --git a/configure.ac b/configure.ac
3e5111
index 08051d53a..d9dc21aa9 100644
3e5111
--- a/configure.ac
3e5111
+++ b/configure.ac
3e5111
@@ -347,7 +347,8 @@ AC_CHECK_TYPE([struct sockpeercred],
3e5111
   ]])
3e5111
 
3e5111
 AC_CHECK_DECLS([ETH_FLAG_TXVLAN, ETH_FLAG_NTUPLE, ETH_FLAG_RXHASH, ETH_FLAG_LRO,
3e5111
-                ETHTOOL_GGSO, ETHTOOL_GGRO, ETHTOOL_GFLAGS, ETHTOOL_GFEATURES],
3e5111
+                ETHTOOL_GGSO, ETHTOOL_GGRO, ETHTOOL_GFLAGS, ETHTOOL_GFEATURES,
3e5111
+                ETHTOOL_SCOALESCE, ETHTOOL_GCOALESCE],
3e5111
   [], [], [[#include <linux/ethtool.h>
3e5111
   ]])
3e5111
 
3e5111
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
3e5111
index d802e7598..134d4a832 100644
3e5111
--- a/src/libvirt_private.syms
3e5111
+++ b/src/libvirt_private.syms
3e5111
@@ -2064,6 +2064,7 @@ virNetDevRxFilterModeTypeFromString;
3e5111
 virNetDevRxFilterModeTypeToString;
3e5111
 virNetDevRxFilterNew;
3e5111
 virNetDevSaveNetConfig;
3e5111
+virNetDevSetCoalesce;
3e5111
 virNetDevSetMAC;
3e5111
 virNetDevSetMTU;
3e5111
 virNetDevSetMTUFromDevice;
3e5111
diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c
3e5111
index 9aa9c9f88..f14286f62 100644
3e5111
--- a/src/util/virnetdev.c
3e5111
+++ b/src/util/virnetdev.c
3e5111
@@ -3082,6 +3082,89 @@ virNetDevGetEthtoolGFeatures(virBitmapPtr bitmap ATTRIBUTE_UNUSED,
3e5111
 # endif
3e5111
 
3e5111
 
3e5111
+# if HAVE_DECL_ETHTOOL_SCOALESCE && HAVE_DECL_ETHTOOL_GCOALESCE
3e5111
+/**
3e5111
+ * virNetDevSetCoalesce:
3e5111
+ * @ifname: interface name to modify
3e5111
+ * @coalesce: Coalesce settings to set and update
3e5111
+ *
3e5111
+ * This function sets the various coalesce settings for a given interface
3e5111
+ * @ifname and updates them back into @coalesce.
3e5111
+ *
3e5111
+ * Returns 0 in case of success or -1 on failure
3e5111
+ */
3e5111
+int virNetDevSetCoalesce(const char *ifname,
3e5111
+                         virNetDevCoalescePtr coalesce)
3e5111
+{
3e5111
+    int fd = -1;
3e5111
+    int ret = -1;
3e5111
+    struct ifreq ifr;
3e5111
+    struct ethtool_coalesce coal = {0};
3e5111
+
3e5111
+    if (!coalesce)
3e5111
+        return 0;
3e5111
+
3e5111
+    coal = (struct ethtool_coalesce) {
3e5111
+        .cmd = ETHTOOL_SCOALESCE,
3e5111
+        .rx_max_coalesced_frames = coalesce->rx_max_coalesced_frames,
3e5111
+        .rx_coalesce_usecs_irq = coalesce->rx_coalesce_usecs_irq,
3e5111
+        .rx_max_coalesced_frames_irq = coalesce->rx_max_coalesced_frames_irq,
3e5111
+        .tx_coalesce_usecs = coalesce->tx_coalesce_usecs,
3e5111
+        .tx_max_coalesced_frames = coalesce->tx_max_coalesced_frames,
3e5111
+        .tx_coalesce_usecs_irq = coalesce->tx_coalesce_usecs_irq,
3e5111
+        .tx_max_coalesced_frames_irq = coalesce->tx_max_coalesced_frames_irq,
3e5111
+        .stats_block_coalesce_usecs = coalesce->stats_block_coalesce_usecs,
3e5111
+        .use_adaptive_rx_coalesce = coalesce->use_adaptive_rx_coalesce,
3e5111
+        .use_adaptive_tx_coalesce = coalesce->use_adaptive_tx_coalesce,
3e5111
+        .pkt_rate_low = coalesce->pkt_rate_low,
3e5111
+        .rx_coalesce_usecs_low = coalesce->rx_coalesce_usecs_low,
3e5111
+        .rx_max_coalesced_frames_low = coalesce->rx_max_coalesced_frames_low,
3e5111
+        .tx_coalesce_usecs_low = coalesce->tx_coalesce_usecs_low,
3e5111
+        .tx_max_coalesced_frames_low = coalesce->tx_max_coalesced_frames_low,
3e5111
+        .pkt_rate_high = coalesce->pkt_rate_high,
3e5111
+        .rx_coalesce_usecs_high = coalesce->rx_coalesce_usecs_high,
3e5111
+        .rx_max_coalesced_frames_high = coalesce->rx_max_coalesced_frames_high,
3e5111
+        .tx_coalesce_usecs_high = coalesce->tx_coalesce_usecs_high,
3e5111
+        .tx_max_coalesced_frames_high = coalesce->tx_max_coalesced_frames_high,
3e5111
+        .rate_sample_interval = coalesce->rate_sample_interval,
3e5111
+    };
3e5111
+
3e5111
+    if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
3e5111
+        return -1;
3e5111
+
3e5111
+    ifr.ifr_data = (void *) &coa;;
3e5111
+
3e5111
+    if (virNetDevSendEthtoolIoctl(fd, &ifr) < 0) {
3e5111
+        virReportSystemError(errno,
3e5111
+                             _("Cannot set coalesce info on '%s'"),
3e5111
+                             ifname);
3e5111
+        goto cleanup;
3e5111
+    }
3e5111
+
3e5111
+    coal = (struct ethtool_coalesce) {
3e5111
+        .cmd = ETHTOOL_GCOALESCE,
3e5111
+    };
3e5111
+
3e5111
+    /* Don't fail if the update itself fails */
3e5111
+    virNetDevSendEthtoolIoctl(fd, &ifr);
3e5111
+
3e5111
+    ret = 0;
3e5111
+ cleanup:
3e5111
+    VIR_FORCE_CLOSE(fd);
3e5111
+    return ret;
3e5111
+}
3e5111
+# else
3e5111
+int virNetDevSetCoalesce(const char *ifname,
3e5111
+                         virNetDevCoalescePtr coalesce ATTRIBUTE_UNUSED)
3e5111
+{
3e5111
+    virReportSystemError(ENOSYS,
3e5111
+                         _("Cannot set coalesce info on interface '%s'"),
3e5111
+                         ifname);
3e5111
+    return -1;
3e5111
+}
3e5111
+# endif
3e5111
+
3e5111
+
3e5111
 /**
3e5111
  * virNetDevGetFeatures:
3e5111
  * This function gets the nic offloads features available for ifname
3e5111
diff --git a/src/util/virnetdev.h b/src/util/virnetdev.h
3e5111
index 437a77625..cff8cb51c 100644
3e5111
--- a/src/util/virnetdev.h
3e5111
+++ b/src/util/virnetdev.h
3e5111
@@ -112,6 +112,36 @@ typedef enum {
3e5111
 
3e5111
 VIR_ENUM_DECL(virNetDevFeature)
3e5111
 
3e5111
+/* Modeled after struct ethtool_coalesce, see linux/ethtool.h for explanations
3e5111
+ * of particular fields */
3e5111
+typedef struct _virNetDevCoalesce virNetDevCoalesce;
3e5111
+typedef virNetDevCoalesce *virNetDevCoalescePtr;
3e5111
+struct _virNetDevCoalesce {
3e5111
+    uint32_t rx_coalesce_usecs;
3e5111
+    uint32_t rx_max_coalesced_frames;
3e5111
+    uint32_t rx_coalesce_usecs_irq;
3e5111
+    uint32_t rx_max_coalesced_frames_irq;
3e5111
+    uint32_t tx_coalesce_usecs;
3e5111
+    uint32_t tx_max_coalesced_frames;
3e5111
+    uint32_t tx_coalesce_usecs_irq;
3e5111
+    uint32_t tx_max_coalesced_frames_irq;
3e5111
+    uint32_t stats_block_coalesce_usecs;
3e5111
+    uint32_t use_adaptive_rx_coalesce;
3e5111
+    uint32_t use_adaptive_tx_coalesce;
3e5111
+    uint32_t pkt_rate_low;
3e5111
+    uint32_t rx_coalesce_usecs_low;
3e5111
+    uint32_t rx_max_coalesced_frames_low;
3e5111
+    uint32_t tx_coalesce_usecs_low;
3e5111
+    uint32_t tx_max_coalesced_frames_low;
3e5111
+    uint32_t pkt_rate_high;
3e5111
+    uint32_t rx_coalesce_usecs_high;
3e5111
+    uint32_t rx_max_coalesced_frames_high;
3e5111
+    uint32_t tx_coalesce_usecs_high;
3e5111
+    uint32_t tx_max_coalesced_frames_high;
3e5111
+    uint32_t rate_sample_interval;
3e5111
+};
3e5111
+
3e5111
+
3e5111
 int virNetDevSetupControl(const char *ifname,
3e5111
                           virIfreq *ifr)
3e5111
     ATTRIBUTE_RETURN_CHECK;
3e5111
@@ -144,6 +174,10 @@ int virNetDevRestoreMacAddress(const char *linkdev,
3e5111
                                const char *stateDir)
3e5111
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
3e5111
 
3e5111
+int virNetDevSetCoalesce(const char *ifname,
3e5111
+                         virNetDevCoalescePtr coalesce)
3e5111
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
3e5111
+
3e5111
 int virNetDevSetMTU(const char *ifname,
3e5111
                     int mtu)
3e5111
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
3e5111
-- 
3e5111
2.12.2
3e5111