/* The unmasked key has to be the same for flow updates. */
error = -EINVAL;
if (!ovs_flow_cmp_unmasked_key(flow, &key, match.range.end)) {
- OVS_NLERR("Flow modification message rejected, unmasked key does not match.\n");
- goto err_unlock_ovs;
+ /* Look for any overlapping flow. */
+ flow = ovs_flow_lookup_exact(table, &match);
+ if (!flow) {
+ OVS_NLERR("Flow modification message rejected, unmasked key does not match.\n");
+ goto err_unlock_ovs;
+ }
}
/* Update actions. */
}
table = ovsl_dereference(dp->table);
- flow = ovs_flow_lookup_unmasked_key(table, &match);
+ flow = ovs_flow_lookup_exact(table, &match);
if (!flow) {
err = -ENOENT;
goto unlock;
goto unlock;
table = ovsl_dereference(dp->table);
- flow = ovs_flow_lookup_unmasked_key(table, &match);
+ flow = ovs_flow_lookup_exact(table, &match);
if (!flow) {
err = -ENOENT;
goto unlock;
#include <linux/jhash.h>
#include <linux/jiffies.h>
#include <linux/llc.h>
+#include <linux/list.h>
#include <linux/module.h>
#include <linux/in.h>
#include <linux/rcupdate.h>
}
-struct sw_flow *ovs_flow_lookup_unmasked_key(struct flow_table *table,
- struct sw_flow_match *match)
-{
- struct sw_flow_key *unmasked = match->key;
- int key_end = match->range.end;
- struct sw_flow *flow;
-
- flow = ovs_flow_lookup(table, unmasked);
- if (flow && (!ovs_flow_cmp_unmasked_key(flow, unmasked, key_end)))
- flow = NULL;
-
- return flow;
-}
-
static struct sw_flow *ovs_masked_flow_lookup(struct flow_table *table,
const struct sw_flow_key *unmasked,
struct sw_flow_mask *mask)
return NULL;
}
+struct sw_flow *ovs_flow_lookup_exact(struct flow_table *tbl,
+ struct sw_flow_match *match)
+{
+ struct sw_flow_key *unmasked = match->key;
+ struct sw_flow *flow;
+ struct sw_flow_mask *mask;
+ int key_end = match->range.end;
+
+ /* Always called under ovs-mutex. */
+ list_for_each_entry(mask, tbl->mask_list, list) {
+ flow = ovs_masked_flow_lookup(tbl, unmasked, mask);
+ if (flow && ovs_flow_cmp_unmasked_key(flow, unmasked, key_end)) /* Found */
+ return flow;
+ }
+
+ return NULL;
+}
+
struct sw_flow *ovs_flow_lookup(struct flow_table *tbl,
const struct sw_flow_key *key)
{
struct sw_flow *ovs_flow_lookup(struct flow_table *,
const struct sw_flow_key *);
-struct sw_flow *ovs_flow_lookup_unmasked_key(struct flow_table *table,
- struct sw_flow_match *match);
+struct sw_flow *ovs_flow_lookup_exact(struct flow_table *tbl,
+ struct sw_flow_match *match);
void ovs_flow_tbl_destroy(struct flow_table *table, bool deferred);
struct flow_table *ovs_flow_tbl_alloc(int new_size);