2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-31 06:15:47 +00:00

dpif: Index flows using unique identifiers.

This patch modifies the dpif interface to allow flows to be manipulated
using a 128-bit identifier. This allows revalidator threads to perform
datapath operations faster, as they do not need to serialise the entire
flow key for operations like flow_get and flow_delete. In conjunction
with a future patch to simplify the dump interface, this provides a
significant performance benefit for revalidation.

When handlers assemble flow_put operations, they specify a unique
identifier (UFID) for each flow as it is passed down to the datapath to
be stored with the flow. The UFID is currently provided to handlers
by the dpif during upcall processing.

When revalidators assemble flow_get or flow_del operations, they may
specify the UFID for the flow along with the key. The dpif will decide
whether to send only the UFID to the datapath, or both the UFID and flow
key. The former is preferred for newer datapaths that support UFID,
while the latter is used for backwards compatibility.

Signed-off-by: Joe Stringer <joestringer@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
This commit is contained in:
Joe Stringer
2014-09-24 16:26:35 +12:00
parent d9aa7218a2
commit 70e5ed6f39
12 changed files with 334 additions and 94 deletions

View File

@@ -304,6 +304,7 @@ struct dp_netdev_flow {
/* Hash table index by unmasked flow. */
const struct cmap_node node; /* In owning dp_netdev's 'flow_table'. */
const ovs_u128 ufid; /* Unique flow identifier. */
const struct flow flow; /* Unmasked flow that created this entry. */
/* Number of references.
@@ -327,6 +328,8 @@ struct dp_netdev_flow {
static void dp_netdev_flow_unref(struct dp_netdev_flow *);
static bool dp_netdev_flow_ref(struct dp_netdev_flow *);
static int dpif_netdev_flow_from_nlattrs(const struct nlattr *, uint32_t,
struct flow *);
/* Contained by struct dp_netdev_flow's 'stats' member. */
struct dp_netdev_flow_stats {
@@ -1156,6 +1159,12 @@ static void dp_netdev_flow_unref(struct dp_netdev_flow *flow)
}
}
static uint32_t
dp_netdev_flow_hash(const ovs_u128 *ufid)
{
return ufid->u32[0];
}
static void
dp_netdev_remove_flow(struct dp_netdev *dp, struct dp_netdev_flow *flow)
OVS_REQUIRES(dp->flow_mutex)
@@ -1163,7 +1172,7 @@ dp_netdev_remove_flow(struct dp_netdev *dp, struct dp_netdev_flow *flow)
struct cmap_node *node = CONST_CAST(struct cmap_node *, &flow->node);
dpcls_remove(&dp->cls, &flow->cr);
cmap_remove(&dp->flow_table, node, flow_hash(&flow->flow, 0));
cmap_remove(&dp->flow_table, node, dp_netdev_flow_hash(&flow->ufid));
flow->dead = true;
dp_netdev_flow_unref(flow);
@@ -1531,14 +1540,26 @@ dp_netdev_lookup_flow(const struct dp_netdev *dp,
}
static struct dp_netdev_flow *
dp_netdev_find_flow(const struct dp_netdev *dp, const struct flow *flow)
dp_netdev_find_flow(const struct dp_netdev *dp, const ovs_u128 *ufidp,
const struct nlattr *key, size_t key_len)
{
struct dp_netdev_flow *netdev_flow;
struct flow flow;
ovs_u128 ufid;
CMAP_FOR_EACH_WITH_HASH (netdev_flow, node, flow_hash(flow, 0),
&dp->flow_table) {
if (flow_equal(&netdev_flow->flow, flow)) {
return netdev_flow;
/* If a UFID is not provided, determine one based on the key. */
if (!ufidp && key && key_len
&& !dpif_netdev_flow_from_nlattrs(key, key_len, &flow)) {
dpif_flow_hash(dp->dpif, &flow, sizeof flow, &ufid);
ufidp = &ufid;
}
if (ufidp) {
CMAP_FOR_EACH_WITH_HASH (netdev_flow, node, dp_netdev_flow_hash(ufidp),
&dp->flow_table) {
if (ovs_u128_equal(&netdev_flow->ufid, ufidp)) {
return netdev_flow;
}
}
}
@@ -1568,8 +1589,7 @@ get_dpif_flow_stats(const struct dp_netdev_flow *netdev_flow,
* 'mask_buf'. Actions will be returned without copying, by relying on RCU to
* protect them. */
static void
dp_netdev_flow_to_dpif_flow(const struct dpif *dpif,
const struct dp_netdev_flow *netdev_flow,
dp_netdev_flow_to_dpif_flow(const struct dp_netdev_flow *netdev_flow,
struct ofpbuf *key_buf, struct ofpbuf *mask_buf,
struct dpif_flow *flow)
{
@@ -1599,8 +1619,8 @@ dp_netdev_flow_to_dpif_flow(const struct dpif *dpif,
flow->actions = actions->actions;
flow->actions_len = actions->size;
dpif_flow_hash(dpif, &netdev_flow->flow, sizeof netdev_flow->flow,
&flow->ufid);
flow->ufid = netdev_flow->ufid;
flow->ufid_present = true;
get_dpif_flow_stats(netdev_flow, &flow->stats);
}
@@ -1701,20 +1721,13 @@ dpif_netdev_flow_get(const struct dpif *dpif, const struct dpif_flow_get *get)
{
struct dp_netdev *dp = get_dp_netdev(dpif);
struct dp_netdev_flow *netdev_flow;
struct flow key;
int error;
error = dpif_netdev_flow_from_nlattrs(get->key, get->key_len, &key);
if (error) {
return error;
}
netdev_flow = dp_netdev_find_flow(dp, &key);
int error = 0;
netdev_flow = dp_netdev_find_flow(dp, get->ufid, get->key, get->key_len);
if (netdev_flow) {
dp_netdev_flow_to_dpif_flow(dpif, netdev_flow, get->buffer,
get->buffer, get->flow);
} else {
dp_netdev_flow_to_dpif_flow(netdev_flow, get->buffer, get->buffer,
get->flow);
} else {
error = ENOENT;
}
@@ -1723,6 +1736,7 @@ dpif_netdev_flow_get(const struct dpif *dpif, const struct dpif_flow_get *get)
static struct dp_netdev_flow *
dp_netdev_flow_add(struct dp_netdev *dp, struct match *match,
const ovs_u128 *ufid,
const struct nlattr *actions, size_t actions_len)
OVS_REQUIRES(dp->flow_mutex)
{
@@ -1737,13 +1751,14 @@ dp_netdev_flow_add(struct dp_netdev *dp, struct match *match,
flow = xmalloc(sizeof *flow - sizeof flow->cr.flow.mf + mask.len);
flow->dead = false;
*CONST_CAST(struct flow *, &flow->flow) = match->flow;
*CONST_CAST(ovs_u128 *, &flow->ufid) = *ufid;
ovs_refcount_init(&flow->ref_cnt);
ovsthread_stats_init(&flow->stats);
ovsrcu_set(&flow->actions, dp_netdev_actions_create(actions, actions_len));
cmap_insert(&dp->flow_table,
CONST_CAST(struct cmap_node *, &flow->node),
flow_hash(&flow->flow, 0));
dp_netdev_flow_hash(&flow->ufid));
netdev_flow_key_init_masked(&flow->cr.flow, &match->flow, &mask);
dpcls_insert(&dp->cls, &flow->cr, &mask);
@@ -1755,6 +1770,8 @@ dp_netdev_flow_add(struct dp_netdev *dp, struct match *match,
miniflow_expand(&flow->cr.mask->mf, &match.wc.masks);
ds_put_cstr(&ds, "flow_add: ");
odp_format_ufid(ufid, &ds);
ds_put_cstr(&ds, " ");
match_format(&match, &ds, OFP_DEFAULT_PRIORITY);
ds_put_cstr(&ds, ", actions:");
format_odp_actions(&ds, actions, actions_len);
@@ -1790,6 +1807,7 @@ dpif_netdev_flow_put(struct dpif *dpif, const struct dpif_flow_put *put)
struct dp_netdev_flow *netdev_flow;
struct netdev_flow_key key;
struct match match;
ovs_u128 ufid;
int error;
error = dpif_netdev_flow_from_nlattrs(put->key, put->key_len, &match.flow);
@@ -1808,6 +1826,12 @@ dpif_netdev_flow_put(struct dpif *dpif, const struct dpif_flow_put *put)
* for upcall processing any more. */
netdev_flow_key_from_flow(&key, &match.flow);
if (put->ufid) {
ufid = *put->ufid;
} else {
dpif_flow_hash(dpif, &match.flow, sizeof match.flow, &ufid);
}
ovs_mutex_lock(&dp->flow_mutex);
netdev_flow = dp_netdev_lookup_flow(dp, &key);
if (!netdev_flow) {
@@ -1816,7 +1840,8 @@ dpif_netdev_flow_put(struct dpif *dpif, const struct dpif_flow_put *put)
if (put->stats) {
memset(put->stats, 0, sizeof *put->stats);
}
dp_netdev_flow_add(dp, &match, put->actions, put->actions_len);
dp_netdev_flow_add(dp, &match, &ufid, put->actions,
put->actions_len);
error = 0;
} else {
error = EFBIG;
@@ -1861,16 +1886,10 @@ 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 *netdev_flow;
struct flow key;
int error;
error = dpif_netdev_flow_from_nlattrs(del->key, del->key_len, &key);
if (error) {
return error;
}
int error = 0;
ovs_mutex_lock(&dp->flow_mutex);
netdev_flow = dp_netdev_find_flow(dp, &key);
netdev_flow = dp_netdev_find_flow(dp, del->ufid, del->key, del->key_len);
if (netdev_flow) {
if (del->stats) {
get_dpif_flow_stats(netdev_flow, del->stats);
@@ -1994,7 +2013,7 @@ dpif_netdev_flow_dump_next(struct dpif_flow_dump_thread *thread_,
ofpbuf_use_stack(&key, keybuf, sizeof *keybuf);
ofpbuf_use_stack(&mask, maskbuf, sizeof *maskbuf);
dp_netdev_flow_to_dpif_flow(&dpif->dpif, netdev_flow, &key, &mask, f);
dp_netdev_flow_to_dpif_flow(netdev_flow, &key, &mask, f);
}
return n_flows;
@@ -2900,7 +2919,7 @@ fast_path_processing(struct dp_netdev_pmd_thread *pmd,
ovs_mutex_lock(&dp->flow_mutex);
netdev_flow = dp_netdev_lookup_flow(dp, &keys[i]);
if (OVS_LIKELY(!netdev_flow)) {
netdev_flow = dp_netdev_flow_add(dp, &match,
netdev_flow = dp_netdev_flow_add(dp, &match, &ufid,
ofpbuf_data(add_actions),
ofpbuf_size(add_actions));
}