Skip to content

Commit b4ba873

Browse files
committed
openvswitch: Fix flow lookup to use unmasked key
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2163374 Upstream Status: linux.git commit 68bb101 Author: Eelco Chaudron <echaudro@redhat.com> Date: Thu Dec 15 15:46:33 2022 +0100 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 <echaudro@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Antoine Tenart <atenart@redhat.com>
1 parent 06c5e46 commit b4ba873

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
@@ -947,6 +947,7 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
947947
struct sw_flow_mask mask;
948948
struct sk_buff *reply;
949949
struct datapath *dp;
950+
struct sw_flow_key *key;
950951
struct sw_flow_actions *acts;
951952
struct sw_flow_match match;
952953
u32 ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]);
@@ -974,24 +975,26 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
974975
}
975976

976977
/* Extract key. */
977-
ovs_match_init(&match, &new_flow->key, false, &mask);
978+
key = kzalloc(sizeof(*key), GFP_KERNEL);
979+
if (!key) {
980+
error = -ENOMEM;
981+
goto err_kfree_key;
982+
}
983+
984+
ovs_match_init(&match, key, false, &mask);
978985
error = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY],
979986
a[OVS_FLOW_ATTR_MASK], log);
980987
if (error)
981988
goto err_kfree_flow;
982989

990+
ovs_flow_mask_key(&new_flow->key, key, true, &mask);
991+
983992
/* Extract flow identifier. */
984993
error = ovs_nla_get_identifier(&new_flow->id, a[OVS_FLOW_ATTR_UFID],
985-
&new_flow->key, log);
994+
key, log);
986995
if (error)
987996
goto err_kfree_flow;
988997

989-
/* unmasked key is needed to match when ufid is not used. */
990-
if (ovs_identifier_is_key(&new_flow->id))
991-
match.key = new_flow->id.unmasked_key;
992-
993-
ovs_flow_mask_key(&new_flow->key, &new_flow->key, true, &mask);
994-
995998
/* Validate actions. */
996999
error = ovs_nla_copy_actions(net, a[OVS_FLOW_ATTR_ACTIONS],
9971000
&new_flow->key, &acts, log);
@@ -1018,7 +1021,7 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
10181021
if (ovs_identifier_is_ufid(&new_flow->id))
10191022
flow = ovs_flow_tbl_lookup_ufid(&dp->table, &new_flow->id);
10201023
if (!flow)
1021-
flow = ovs_flow_tbl_lookup(&dp->table, &new_flow->key);
1024+
flow = ovs_flow_tbl_lookup(&dp->table, key);
10221025
if (likely(!flow)) {
10231026
rcu_assign_pointer(new_flow->sf_acts, acts);
10241027

@@ -1088,6 +1091,8 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
10881091

10891092
if (reply)
10901093
ovs_notify(&dp_flow_genl_family, reply, info);
1094+
1095+
kfree(key);
10911096
return 0;
10921097

10931098
err_unlock_ovs:
@@ -1097,6 +1102,8 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
10971102
ovs_nla_free_flow_actions(acts);
10981103
err_kfree_flow:
10991104
ovs_flow_free(new_flow, false);
1105+
err_kfree_key:
1106+
kfree(key);
11001107
error:
11011108
return error;
11021109
}

0 commit comments

Comments
 (0)