[ovs-dev] [PATCH] netdev-linux: Skip miimon execution when disabled

Joe Stringer joestringer at nicira.com
Fri Nov 1 23:34:29 UTC 2013


When dealing with a large number of ports, one of the performance
bottlenecks is that we loop through all netdevs in the main loop. Miimon
is a contributor to this, checking all devices even if it has never been
enabled.

This patch introduces a counter for the number of netdevs with miimon
configured. If this is 0, then we skip miimon_run() and miimon_wait().
In a test environment of 5000 internal ports and 50 tunnel ports with
bfd, this reduces CPU usage from about 50% to about 45%.

Signed-off-by: Joe Stringer <joestringer at nicira.com>

---
v2: Shift netdev cleanup code from bridge.c to netdev-linux.c
    Collapse "miimon enabled" check into a new function
---
 lib/netdev-linux.c |   37 +++++++++++++++++++++++++++++++++++--
 1 file changed, 35 insertions(+), 2 deletions(-)

diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c
index 2752623..7e75144 100644
--- a/lib/netdev-linux.c
+++ b/lib/netdev-linux.c
@@ -61,6 +61,7 @@
 #include "netlink.h"
 #include "ofpbuf.h"
 #include "openflow/openflow.h"
+#include "ovs-atomic.h"
 #include "packets.h"
 #include "poll-loop.h"
 #include "rtnetlink-link.h"
@@ -402,6 +403,11 @@ struct netdev_rx_linux {
  * additional log messages. */
 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
 
+/* Polling miimon status for all ports causes performance degradation when
+ * handling a large number of ports. If there are no devices using miimon, then
+ * we skip netdev_linux_miimon_run() and netdev_linux_miimon_wait(). */
+static atomic_int miimon_cnt = ATOMIC_VAR_INIT(0);
+
 static void netdev_linux_run(void);
 
 static int netdev_linux_do_ethtool(const char *name, struct ethtool_cmd *,
@@ -423,6 +429,7 @@ static int set_etheraddr(const char *netdev_name, const uint8_t[ETH_ADDR_LEN]);
 static int get_stats_via_netlink(int ifindex, struct netdev_stats *stats);
 static int get_stats_via_proc(const char *netdev_name, struct netdev_stats *stats);
 static int af_packet_sock(void);
+static bool netdev_linux_miimon_enabled(void);
 static void netdev_linux_miimon_run(void);
 static void netdev_linux_miimon_wait(void);
 
@@ -485,13 +492,24 @@ netdev_linux_notify_sock(void)
     return sock;
 }
 
+static bool
+netdev_linux_miimon_enabled(void)
+{
+    int miimon;
+
+    atomic_read(&miimon_cnt, &miimon);
+    return miimon > 0;
+}
+
 static void
 netdev_linux_run(void)
 {
     struct nl_sock *sock;
     int error;
 
-    netdev_linux_miimon_run();
+    if (netdev_linux_miimon_enabled()) {
+        netdev_linux_miimon_run();
+    }
 
     sock = netdev_linux_notify_sock();
     if (!sock) {
@@ -553,7 +571,9 @@ netdev_linux_wait(void)
 {
     struct nl_sock *sock;
 
-    netdev_linux_miimon_wait();
+    if (netdev_linux_miimon_enabled()) {
+        netdev_linux_miimon_wait();
+    }
     sock = netdev_linux_notify_sock();
     if (sock) {
         nl_sock_wait(sock, POLLIN);
@@ -711,6 +731,11 @@ netdev_linux_destruct(struct netdev *netdev_)
         close(netdev->tap_fd);
     }
 
+    if (netdev->miimon_interval > 0) {
+        int junk;
+        atomic_sub(&miimon_cnt, 1, &junk);
+    }
+
     ovs_mutex_destroy(&netdev->mutex);
 }
 
@@ -1222,6 +1247,14 @@ netdev_linux_set_miimon_interval(struct netdev *netdev_,
     ovs_mutex_lock(&netdev->mutex);
     interval = interval > 0 ? MAX(interval, 100) : 0;
     if (netdev->miimon_interval != interval) {
+        int junk;
+
+        if (interval && !netdev->miimon_interval) {
+            atomic_add(&miimon_cnt, 1, &junk);
+        } else if (!interval && netdev->miimon_interval) {
+            atomic_sub(&miimon_cnt, 1, &junk);
+        }
+
         netdev->miimon_interval = interval;
         timer_set_expired(&netdev->miimon_timer);
     }
-- 
1.7.9.5




More information about the dev mailing list