Skip to content

Commit 68bb101

Browse files
chaudrondavem330
authored andcommitted
openvswitch: Fix flow lookup to use unmasked key
The commit mentioned below causes the ovs_flow_tbl_lookup() function to be called with the masked key. However, it's supposed to be called with the unmasked key. This due to the fact that the datapath supports installing wider flows, and OVS relies on this behavior. For example if ipv4(src=1.1.1.1/192.0.0.0, dst=1.1.1.2/192.0.0.0) exists, a wider flow (smaller mask) of ipv4(src=192.1.1.1/128.0.0.0,dst=192.1.1.2/ 128.0.0.0) is allowed to be added. However, if we try to add a wildcard rule, the installation fails: $ ovs-appctl dpctl/add-flow system@myDP "in_port(1),eth_type(0x0800), \ ipv4(src=1.1.1.1/192.0.0.0,dst=1.1.1.2/192.0.0.0,frag=no)" 2 $ ovs-appctl dpctl/add-flow system@myDP "in_port(1),eth_type(0x0800), \ ipv4(src=192.1.1.1/0.0.0.0,dst=49.1.1.2/0.0.0.0,frag=no)" 2 ovs-vswitchd: updating flow table (File exists) The reason is that the key used to determine if the flow is already present in the system uses the original key ANDed with the mask. This results in the IP address not being part of the (miniflow) key, i.e., being substituted with an all-zero value. When doing the actual lookup, this results in the key wrongfully matching the first flow, and therefore the flow does not get installed. This change reverses the commit below, but rather than having the key on the stack, it's allocated. Fixes: 190aa3e ("openvswitch: Fix Frame-size larger than 1024 bytes warning.") Signed-off-by: Eelco Chaudron <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 3e31d20 commit 68bb101

File tree

1 file changed

+16
-9
lines changed

1 file changed

+16
-9
lines changed

net/openvswitch/datapath.c

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -973,6 +973,7 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
973973
struct sw_flow_mask mask;
974974
struct sk_buff *reply;
975975
struct datapath *dp;
976+
struct sw_flow_key *key;
976977
struct sw_flow_actions *acts;
977978
struct sw_flow_match match;
978979
u32 ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]);
@@ -1000,24 +1001,26 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
10001001
}
10011002

10021003
/* Extract key. */
1003-
ovs_match_init(&match, &new_flow->key, false, &mask);
1004+
key = kzalloc(sizeof(*key), GFP_KERNEL);
1005+
if (!key) {
1006+
error = -ENOMEM;
1007+
goto err_kfree_key;
1008+
}
1009+
1010+
ovs_match_init(&match, key, false, &mask);
10041011
error = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY],
10051012
a[OVS_FLOW_ATTR_MASK], log);
10061013
if (error)
10071014
goto err_kfree_flow;
10081015

1016+
ovs_flow_mask_key(&new_flow->key, key, true, &mask);
1017+
10091018
/* Extract flow identifier. */
10101019
error = ovs_nla_get_identifier(&new_flow->id, a[OVS_FLOW_ATTR_UFID],
1011-
&new_flow->key, log);
1020+
key, log);
10121021
if (error)
10131022
goto err_kfree_flow;
10141023

1015-
/* unmasked key is needed to match when ufid is not used. */
1016-
if (ovs_identifier_is_key(&new_flow->id))
1017-
match.key = new_flow->id.unmasked_key;
1018-
1019-
ovs_flow_mask_key(&new_flow->key, &new_flow->key, true, &mask);
1020-
10211024
/* Validate actions. */
10221025
error = ovs_nla_copy_actions(net, a[OVS_FLOW_ATTR_ACTIONS],
10231026
&new_flow->key, &acts, log);
@@ -1044,7 +1047,7 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
10441047
if (ovs_identifier_is_ufid(&new_flow->id))
10451048
flow = ovs_flow_tbl_lookup_ufid(&dp->table, &new_flow->id);
10461049
if (!flow)
1047-
flow = ovs_flow_tbl_lookup(&dp->table, &new_flow->key);
1050+
flow = ovs_flow_tbl_lookup(&dp->table, key);
10481051
if (likely(!flow)) {
10491052
rcu_assign_pointer(new_flow->sf_acts, acts);
10501053

@@ -1114,6 +1117,8 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
11141117

11151118
if (reply)
11161119
ovs_notify(&dp_flow_genl_family, reply, info);
1120+
1121+
kfree(key);
11171122
return 0;
11181123

11191124
err_unlock_ovs:
@@ -1123,6 +1128,8 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
11231128
ovs_nla_free_flow_actions(acts);
11241129
err_kfree_flow:
11251130
ovs_flow_free(new_flow, false);
1131+
err_kfree_key:
1132+
kfree(key);
11261133
error:
11271134
return error;
11281135
}

0 commit comments

Comments
 (0)