[ovs-dev] [PATCH] dpif-linux: Choose port numbers more prudently.

Ethan Jackson ethan at nicira.com
Tue Apr 5 01:17:19 UTC 2011


Before this patch the kernel chose the lowest available number for
newly created datapath ports.  This patch moves the port number
choosing responsibility to user space, and implements a least
recently used port number queue in an attempt to avoid reuse.

Bug #2140.
---
 lib/dpif-linux.c |   52 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 51 insertions(+), 1 deletions(-)

diff --git a/lib/dpif-linux.c b/lib/dpif-linux.c
index b5590c4..2887fc4 100644
--- a/lib/dpif-linux.c
+++ b/lib/dpif-linux.c
@@ -52,6 +52,10 @@
 
 VLOG_DEFINE_THIS_MODULE(dpif_linux);
 
+enum { DP_MAX_PORTS = 1024 };
+enum { LRU_MASK = DP_MAX_PORTS - 1};
+BUILD_ASSERT_DECL(IS_POW2(DP_MAX_PORTS));
+
 struct dpif_linux_dp {
     /* Generic Netlink header. */
     uint8_t cmd;
@@ -128,6 +132,11 @@ struct dpif_linux {
     struct sset changed_ports;  /* Ports that have changed. */
     struct rtnetlink_notifier port_notifier;
     bool change_error;
+
+    /* Queue of unused ports. */
+    uint16_t lru_ports[DP_MAX_PORTS];
+    size_t lru_head;
+    size_t lru_tail;
 };
 
 static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(9999, 5);
@@ -158,6 +167,35 @@ dpif_linux_cast(const struct dpif *dpif)
     return CONTAINER_OF(dpif, struct dpif_linux, dpif);
 }
 
+static void
+dpif_linux_push_port(struct dpif_linux *dp, uint16_t port)
+{
+    size_t i;
+
+    /* Currently this is an O(n) operation.  It could be easily optimized with
+     * a hash table, however dpif_linux_push_port() is only called at
+     * initialization and port deletion time. */
+    for (i = dp->lru_tail; i < dp->lru_head; i++) {
+        if (dp->lru_ports[i & LRU_MASK] == port) {
+            return;
+        }
+    }
+
+    assert(dp->lru_head - dp->lru_tail < DP_MAX_PORTS);
+    dp->lru_ports[dp->lru_head++ & LRU_MASK] = port;
+}
+
+static bool
+dpif_linux_pop_port(struct dpif_linux *dp, uint16_t *port)
+{
+    if (dp->lru_head == dp->lru_tail) {
+        return false;
+    }
+
+    *port = dp->lru_ports[dp->lru_tail++ & LRU_MASK];
+    return true;
+}
+
 static int
 dpif_linux_enumerate(struct sset *all_dps)
 {
@@ -235,6 +273,10 @@ open_dpif(const struct dpif_linux_dp *dp, struct dpif **dpifp)
     dpif->change_error = false;
     *dpifp = &dpif->dpif;
 
+    dpif->lru_head = dpif->lru_tail = 0;
+    for (i = 1; i < DP_MAX_PORTS; i++) {
+        dpif_linux_push_port(dpif, i);
+    }
     return 0;
 
 error_free:
@@ -336,7 +378,14 @@ dpif_linux_port_add(struct dpif *dpif_, struct netdev *netdev,
         request.options_len = options->size;
     }
 
-    error = dpif_linux_vport_transact(&request, &reply, &buf);
+    /* Loop until we find a port that isn't used. */
+    do {
+        uint16_t port;
+
+        request.port_no = dpif_linux_pop_port(dpif, &port) ? port : UINT32_MAX;
+        error = dpif_linux_vport_transact(&request, &reply, &buf);
+    } while (error == EBUSY);
+
     if (!error) {
         *port_nop = reply.port_no;
         ofpbuf_delete(buf);
@@ -355,6 +404,7 @@ dpif_linux_port_del(struct dpif *dpif_, uint16_t port_no)
     vport.cmd = ODP_VPORT_CMD_DEL;
     vport.dp_ifindex = dpif->dp_ifindex;
     vport.port_no = port_no;
+    dpif_linux_push_port(dpif, port_no);
     return dpif_linux_vport_transact(&vport, NULL, NULL);
 }
 
-- 
1.7.4.2




More information about the dev mailing list