[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