/* 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.
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 {
}
}
+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)
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);
}
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;
+
+ /* 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;
+ }
- 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 (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;
+ }
}
}
* '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)
{
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);
}
{
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;
}
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)
{
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);
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);
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);
* 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) {
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;
{
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);
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;
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));
}