summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEthan Jackson <ethan@nicira.com>2011-04-29 13:12:19 -0700
committerBen Pfaff <blp@nicira.com>2011-05-23 09:18:31 -0700
commit1d226b37ecfb1c1e35787e313abd545a59e22011 (patch)
tree3b1131fc45408633e139180a2b8ae14c2ed450cd
parentcfcb9ff417600836d50c8aca29915381165451c2 (diff)
downloadopenvswitch-1d226b37ecfb1c1e35787e313abd545a59e22011.tar.gz
dpif-linux: Recycle leaked ports.
When ports are deleted from the datapath they need to be added to an LRU list maintained in dpif-linux so they may be reallocated. When using vswitchd to delete the ports this happens automatically. However, if a port is deleted directly from the datapath it is never reclaimed by dpif-linux. If this happens often, eventually no ports will be available for allocation and dpif-linux will fall back to using the old, kernel implemented, allocation strategy. This commit fixes the problem by automatically reclaiming ports missing from the datapath whenever the list of ports in the datapath is dumped. Bug #2140.
-rw-r--r--lib/dpif-linux.c24
1 files changed, 23 insertions, 1 deletions
diff --git a/lib/dpif-linux.c b/lib/dpif-linux.c
index fed81b747..d71e41412 100644
--- a/lib/dpif-linux.c
+++ b/lib/dpif-linux.c
@@ -472,6 +472,8 @@ dpif_linux_flow_flush(struct dpif *dpif_)
struct dpif_linux_port_state {
struct nl_dump dump;
+ unsigned long *port_bitmap; /* Ports in the datapath. */
+ bool complete; /* Dump completed without error. */
};
static int
@@ -483,6 +485,8 @@ dpif_linux_port_dump_start(const struct dpif *dpif_, void **statep)
struct ofpbuf *buf;
*statep = state = xmalloc(sizeof *state);
+ state->port_bitmap = bitmap_allocate(LRU_MAX_PORTS);
+ state->complete = false;
dpif_linux_vport_init(&request);
request.cmd = ODP_DP_CMD_GET;
@@ -506,6 +510,7 @@ dpif_linux_port_dump_next(const struct dpif *dpif OVS_UNUSED, void *state_,
int error;
if (!nl_dump_next(&state->dump, &buf)) {
+ state->complete = true;
return EOF;
}
@@ -514,6 +519,10 @@ dpif_linux_port_dump_next(const struct dpif *dpif OVS_UNUSED, void *state_,
return error;
}
+ if (vport.port_no < LRU_MAX_PORTS) {
+ bitmap_set1(state->port_bitmap, vport.port_no);
+ }
+
dpif_port->name = (char *) vport.name;
dpif_port->type = (char *) netdev_vport_get_netdev_type(&vport);
dpif_port->port_no = vport.port_no;
@@ -521,10 +530,23 @@ dpif_linux_port_dump_next(const struct dpif *dpif OVS_UNUSED, void *state_,
}
static int
-dpif_linux_port_dump_done(const struct dpif *dpif OVS_UNUSED, void *state_)
+dpif_linux_port_dump_done(const struct dpif *dpif_, void *state_)
{
+ struct dpif_linux *dpif = dpif_linux_cast(dpif_);
struct dpif_linux_port_state *state = state_;
int error = nl_dump_done(&state->dump);
+
+ if (state->complete) {
+ uint16_t i;
+
+ for (i = 0; i < LRU_MAX_PORTS; i++) {
+ if (!bitmap_is_set(state->port_bitmap, i)) {
+ dpif_linux_push_port(dpif, i);
+ }
+ }
+ }
+
+ free(state->port_bitmap);
free(state);
return error;
}