/*
- * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
return error;
}
-static int
-dpif_linux_flow_del(struct dpif *dpif_,
- const struct nlattr *key, size_t key_len,
- struct dpif_flow_stats *stats)
+static void
+dpif_linux_init_flow_del(struct dpif *dpif_, const struct dpif_flow_del *del,
+ struct dpif_linux_flow *request)
{
struct dpif_linux *dpif = dpif_linux_cast(dpif_);
+
+ dpif_linux_flow_init(request);
+ request->cmd = OVS_FLOW_CMD_DEL;
+ request->dp_ifindex = dpif->dp_ifindex;
+ request->key = del->key;
+ request->key_len = del->key_len;
+}
+
+static int
+dpif_linux_flow_del(struct dpif *dpif_, const struct dpif_flow_del *del)
+{
struct dpif_linux_flow request, reply;
struct ofpbuf *buf;
int error;
- dpif_linux_flow_init(&request);
- request.cmd = OVS_FLOW_CMD_DEL;
- request.dp_ifindex = dpif->dp_ifindex;
- request.key = key;
- request.key_len = key_len;
+ dpif_linux_init_flow_del(dpif_, del, &request);
error = dpif_linux_flow_transact(&request,
- stats ? &reply : NULL,
- stats ? &buf : NULL);
- if (!error && stats) {
- dpif_linux_flow_get_stats(&reply, stats);
+ del->stats ? &reply : NULL,
+ del->stats ? &buf : NULL);
+ if (!error && del->stats) {
+ dpif_linux_flow_get_stats(&reply, del->stats);
ofpbuf_delete(buf);
}
return error;
for (i = 0; i < n_ops; i++) {
struct nl_transaction *txn = &txns[i];
struct dpif_op *op = ops[i];
-
- if (op->type == DPIF_OP_FLOW_PUT) {
- struct dpif_flow_put *put = &op->u.flow_put;
- struct dpif_linux_flow request;
-
+ struct dpif_flow_put *put;
+ struct dpif_flow_del *del;
+ struct dpif_execute *execute;
+ struct dpif_linux_flow request;
+
+ switch (op->type) {
+ case DPIF_OP_FLOW_PUT:
+ put = &op->u.flow_put;
dpif_linux_init_flow_put(dpif_, put, &request);
if (put->stats) {
request.nlmsg_flags |= NLM_F_ECHO;
}
txn->request = ofpbuf_new(1024);
dpif_linux_flow_to_ofpbuf(&request, txn->request);
- } else if (op->type == DPIF_OP_EXECUTE) {
- struct dpif_execute *execute = &op->u.execute;
+ break;
+
+ case DPIF_OP_FLOW_DEL:
+ del = &op->u.flow_del;
+ dpif_linux_init_flow_del(dpif_, del, &request);
+ if (del->stats) {
+ request.nlmsg_flags |= NLM_F_ECHO;
+ }
+ txn->request = ofpbuf_new(1024);
+ dpif_linux_flow_to_ofpbuf(&request, txn->request);
+ break;
+ case DPIF_OP_EXECUTE:
+ execute = &op->u.execute;
txn->request = dpif_linux_encode_execute(dpif->dp_ifindex,
execute);
- } else {
+ break;
+
+ default:
NOT_REACHED();
}
}
for (i = 0; i < n_ops; i++) {
struct nl_transaction *txn = &txns[i];
struct dpif_op *op = ops[i];
+ struct dpif_flow_put *put;
+ struct dpif_flow_del *del;
- if (op->type == DPIF_OP_FLOW_PUT) {
- struct dpif_flow_put *put = &op->u.flow_put;
- int error = txn->error;
+ op->error = txn->error;
- if (!error && put->stats) {
+ switch (op->type) {
+ case DPIF_OP_FLOW_PUT:
+ put = &op->u.flow_put;
+ if (!op->error && put->stats) {
struct dpif_linux_flow reply;
- error = dpif_linux_flow_from_ofpbuf(&reply, txn->reply);
- if (!error) {
+ op->error = dpif_linux_flow_from_ofpbuf(&reply, txn->reply);
+ if (!op->error) {
dpif_linux_flow_get_stats(&reply, put->stats);
}
}
- op->error = error;
- } else if (op->type == DPIF_OP_EXECUTE) {
- op->error = txn->error;
- } else {
+ break;
+
+ case DPIF_OP_FLOW_DEL:
+ del = &op->u.flow_del;
+ if (!op->error && del->stats) {
+ struct dpif_linux_flow reply;
+
+ op->error = dpif_linux_flow_from_ofpbuf(&reply, txn->reply);
+ if (!op->error) {
+ dpif_linux_flow_get_stats(&reply, del->stats);
+ }
+ }
+ break;
+
+ case DPIF_OP_EXECUTE:
+ break;
+
+ default:
NOT_REACHED();
}
}
static int
-dpif_netdev_flow_del(struct dpif *dpif,
- const struct nlattr *nl_key, size_t nl_key_len,
- struct dpif_flow_stats *stats)
+dpif_netdev_flow_del(struct dpif *dpif, const struct dpif_flow_del *del)
{
struct dp_netdev *dp = get_dp_netdev(dpif);
struct dp_netdev_flow *flow;
struct flow key;
int error;
- error = dpif_netdev_flow_from_nlattrs(nl_key, nl_key_len, &key);
+ error = dpif_netdev_flow_from_nlattrs(del->key, del->key_len, &key);
if (error) {
return error;
}
flow = dp_netdev_lookup_flow(dp, &key);
if (flow) {
- if (stats) {
- get_dpif_flow_stats(flow, stats);
+ if (del->stats) {
+ get_dpif_flow_stats(flow, del->stats);
}
dp_netdev_free_flow(dp, flow);
return 0;
/*
- * Copyright (c) 2009, 2010, 2011 Nicira Networks.
+ * Copyright (c) 2009, 2010, 2011, 2012 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
/* Deletes a flow from 'dpif' and returns 0, or returns ENOENT if 'dpif'
* does not contain such a flow. The flow is specified by the Netlink
- * attributes with types OVS_KEY_ATTR_* in the 'key_len' bytes starting at
- * 'key'.
+ * attributes with types OVS_KEY_ATTR_* in the 'del->key_len' bytes
+ * starting at 'del->key'.
*
- * If the operation succeeds, then 'stats', if nonnull, must be set to the
- * flow's statistics before its deletion. */
- int (*flow_del)(struct dpif *dpif,
- const struct nlattr *key, size_t key_len,
- struct dpif_flow_stats *stats);
+ * If the operation succeeds, then 'del->stats', if nonnull, must be set to
+ * the flow's statistics before its deletion. */
+ int (*flow_del)(struct dpif *dpif, const struct dpif_flow_del *del);
/* Deletes all flows from 'dpif' and clears all of its queues of received
* packets. */
static bool should_log_flow_message(int error);
static void log_flow_put_message(struct dpif *, const struct dpif_flow_put *,
int error);
+static void log_flow_del_message(struct dpif *, const struct dpif_flow_del *,
+ int error);
static void log_execute_message(struct dpif *, const struct dpif_execute *,
int error);
return dpif_flow_put__(dpif, &put);
}
+static int
+dpif_flow_del__(struct dpif *dpif, struct dpif_flow_del *del)
+{
+ int error;
+
+ COVERAGE_INC(dpif_flow_del);
+
+ error = dpif->dpif_class->flow_del(dpif, del);
+ if (error && del->stats) {
+ memset(del->stats, 0, sizeof *del->stats);
+ }
+ log_flow_del_message(dpif, del, error);
+ return error;
+}
+
/* Deletes a flow from 'dpif' and returns 0, or returns ENOENT if 'dpif' does
* not contain such a flow. The flow is specified by the Netlink attributes
* with types OVS_KEY_ATTR_* in the 'key_len' bytes starting at 'key'.
const struct nlattr *key, size_t key_len,
struct dpif_flow_stats *stats)
{
- int error;
+ struct dpif_flow_del del;
- COVERAGE_INC(dpif_flow_del);
-
- error = dpif->dpif_class->flow_del(dpif, key, key_len, stats);
- if (error && stats) {
- memset(stats, 0, sizeof *stats);
- }
- if (should_log_flow_message(error)) {
- log_flow_message(dpif, error, "flow_del", key, key_len,
- !error ? stats : NULL, NULL, 0);
- }
- return error;
+ del.key = key;
+ del.key_len = key_len;
+ del.stats = stats;
+ return dpif_flow_del__(dpif, &del);
}
/* Initializes 'dump' to begin dumping the flows in a dpif.
log_flow_put_message(dpif, &op->u.flow_put, op->error);
break;
+ case DPIF_OP_FLOW_DEL:
+ log_flow_del_message(dpif, &op->u.flow_del, op->error);
+ break;
+
case DPIF_OP_EXECUTE:
log_execute_message(dpif, &op->u.execute, op->error);
break;
op->error = dpif_flow_put__(dpif, &op->u.flow_put);
break;
+ case DPIF_OP_FLOW_DEL:
+ op->error = dpif_flow_del__(dpif, &op->u.flow_del);
+ break;
+
case DPIF_OP_EXECUTE:
op->error = dpif_execute__(dpif, &op->u.execute);
break;
}
}
+static void
+log_flow_del_message(struct dpif *dpif, const struct dpif_flow_del *del,
+ int error)
+{
+ if (should_log_flow_message(error)) {
+ log_flow_message(dpif, error, "flow_del", del->key, del->key_len,
+ !error ? del->stats : NULL, NULL, 0);
+ }
+}
+
static void
log_execute_message(struct dpif *dpif, const struct dpif_execute *execute,
int error)
enum dpif_op_type {
DPIF_OP_FLOW_PUT = 1,
- DPIF_OP_EXECUTE
+ DPIF_OP_FLOW_DEL,
+ DPIF_OP_EXECUTE,
};
struct dpif_flow_put {
struct dpif_flow_stats *stats; /* Optional flow statistics. */
};
+struct dpif_flow_del {
+ /* Input. */
+ const struct nlattr *key; /* Flow to delete. */
+ size_t key_len; /* Length of 'key' in bytes. */
+
+ /* Output. */
+ struct dpif_flow_stats *stats; /* Optional flow statistics. */
+};
+
struct dpif_execute {
const struct nlattr *key; /* Partial flow key (only for metadata). */
size_t key_len; /* Length of 'key' in bytes. */
int error;
union {
struct dpif_flow_put flow_put;
+ struct dpif_flow_del flow_del;
struct dpif_execute execute;
} u;
};
op->subfacet->installed = true;
}
break;
+
+ case DPIF_OP_FLOW_DEL:
+ NOT_REACHED();
}
}
HMAP_FOR_EACH_SAFE (miss, next_miss, hmap_node, &todo) {
return bucket * BUCKET_WIDTH;
}
+enum { EXPIRE_MAX_BATCH = 50 };
+
+static void
+expire_batch(struct ofproto_dpif *ofproto, struct subfacet **subfacets, int n)
+{
+ struct odputil_keybuf keybufs[EXPIRE_MAX_BATCH];
+ struct dpif_op ops[EXPIRE_MAX_BATCH];
+ struct dpif_op *opsp[EXPIRE_MAX_BATCH];
+ struct ofpbuf keys[EXPIRE_MAX_BATCH];
+ struct dpif_flow_stats stats[EXPIRE_MAX_BATCH];
+ int i;
+
+ for (i = 0; i < n; i++) {
+ ops[i].type = DPIF_OP_FLOW_DEL;
+ subfacet_get_key(subfacets[i], &keybufs[i], &keys[i]);
+ ops[i].u.flow_del.key = keys[i].data;
+ ops[i].u.flow_del.key_len = keys[i].size;
+ ops[i].u.flow_del.stats = &stats[i];
+ opsp[i] = &ops[i];
+ }
+
+ dpif_operate(ofproto->dpif, opsp, n);
+ for (i = 0; i < n; i++) {
+ subfacet_reset_dp_stats(subfacets[i], &stats[i]);
+ subfacets[i]->installed = false;
+ subfacet_destroy(subfacets[i]);
+ }
+}
+
static void
expire_subfacets(struct ofproto_dpif *ofproto, int dp_max_idle)
{
long long int cutoff = time_msec() - dp_max_idle;
+
struct subfacet *subfacet, *next_subfacet;
+ struct subfacet *batch[EXPIRE_MAX_BATCH];
+ int n_batch;
+ n_batch = 0;
HMAP_FOR_EACH_SAFE (subfacet, next_subfacet, hmap_node,
&ofproto->subfacets) {
if (subfacet->used < cutoff) {
- subfacet_destroy(subfacet);
+ if (subfacet->installed) {
+ batch[n_batch++] = subfacet;
+ if (n_batch >= EXPIRE_MAX_BATCH) {
+ expire_batch(ofproto, batch, n_batch);
+ n_batch = 0;
+ }
+ } else {
+ subfacet_destroy(subfacet);
+ }
}
}
+
+ if (n_batch > 0) {
+ expire_batch(ofproto, batch, n_batch);
+ }
}
/* If 'rule' is an OpenFlow rule, that has expired according to OpenFlow rules,