aboutsummaryrefslogtreecommitdiffstats
path: root/net/openvswitch/flow_netlink.c
diff options
context:
space:
mode:
authorPravin B Shelar <pshelar@nicira.com>2014-10-17 00:55:45 -0400
committerDavid S. Miller <davem@davemloft.net>2014-10-17 16:49:34 -0400
commitf47de068f68db91b89e0d3335230d07e02da8727 (patch)
tree79aa16d0cb522b71b3ed0e73cd63a56cb1ec33ec /net/openvswitch/flow_netlink.c
parent7a9f526fc3ee49b6034af2f243676ee0a27dcaa8 (diff)
openvswitch: Create right mask with disabled megaflows
If megaflows are disabled, the userspace does not send the netlink attribute OVS_FLOW_ATTR_MASK, and the kernel must create an exact match mask. sw_flow_mask_set() sets every bytes (in 'range') of the mask to 0xff, even the bytes that represent padding for struct sw_flow, or the bytes that represent fields that may not be set during ovs_flow_extract(). This is a problem, because when we extract a flow from a packet, we do not memset() anymore the struct sw_flow to 0. This commit gets rid of sw_flow_mask_set() and introduces mask_set_nlattr(), which operates on the netlink attributes rather than on the mask key. Using this approach we are sure that only the bytes that the user provided in the flow are matched. Also, if the parse_flow_mask_nlattrs() for the mask ENCAP attribute fails, we now return with an error. This bug is introduced by commit 0714812134d7dcadeb7ecfbfeb18788aa7e1eaac ("openvswitch: Eliminate memset() from flow_extract"). Reported-by: Alex Wang <alexw@nicira.com> Signed-off-by: Daniele Di Proietto <ddiproietto@vmware.com> Signed-off-by: Andy Zhou <azhou@nicira.com> Signed-off-by: Pravin B Shelar <pshelar@nicira.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/openvswitch/flow_netlink.c')
-rw-r--r--net/openvswitch/flow_netlink.c93
1 files changed, 72 insertions, 21 deletions
diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c
index 368f23307911..939bcb32100f 100644
--- a/net/openvswitch/flow_netlink.c
+++ b/net/openvswitch/flow_netlink.c
@@ -103,10 +103,19 @@ static void update_range__(struct sw_flow_match *match,
103 SW_FLOW_KEY_MEMCPY_OFFSET(match, offsetof(struct sw_flow_key, field), \ 103 SW_FLOW_KEY_MEMCPY_OFFSET(match, offsetof(struct sw_flow_key, field), \
104 value_p, len, is_mask) 104 value_p, len, is_mask)
105 105
106static u16 range_n_bytes(const struct sw_flow_key_range *range) 106#define SW_FLOW_KEY_MEMSET_FIELD(match, field, value, is_mask) \
107{ 107 do { \
108 return range->end - range->start; 108 update_range__(match, offsetof(struct sw_flow_key, field), \
109} 109 sizeof((match)->key->field), is_mask); \
110 if (is_mask) { \
111 if ((match)->mask) \
112 memset((u8 *)&(match)->mask->key.field, value,\
113 sizeof((match)->mask->key.field)); \
114 } else { \
115 memset((u8 *)&(match)->key->field, value, \
116 sizeof((match)->key->field)); \
117 } \
118 } while (0)
110 119
111static bool match_validate(const struct sw_flow_match *match, 120static bool match_validate(const struct sw_flow_match *match,
112 u64 key_attrs, u64 mask_attrs) 121 u64 key_attrs, u64 mask_attrs)
@@ -809,13 +818,26 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs,
809 return 0; 818 return 0;
810} 819}
811 820
812static void sw_flow_mask_set(struct sw_flow_mask *mask, 821static void nlattr_set(struct nlattr *attr, u8 val, bool is_attr_mask_key)
813 struct sw_flow_key_range *range, u8 val)
814{ 822{
815 u8 *m = (u8 *)&mask->key + range->start; 823 struct nlattr *nla;
824 int rem;
825
826 /* The nlattr stream should already have been validated */
827 nla_for_each_nested(nla, attr, rem) {
828 /* We assume that ovs_key_lens[type] == -1 means that type is a
829 * nested attribute
830 */
831 if (is_attr_mask_key && ovs_key_lens[nla_type(nla)] == -1)
832 nlattr_set(nla, val, false);
833 else
834 memset(nla_data(nla), val, nla_len(nla));
835 }
836}
816 837
817 mask->range = *range; 838static void mask_set_nlattr(struct nlattr *attr, u8 val)
818 memset(m, val, range_n_bytes(range)); 839{
840 nlattr_set(attr, val, true);
819} 841}
820 842
821/** 843/**
@@ -836,6 +858,7 @@ int ovs_nla_get_match(struct sw_flow_match *match,
836{ 858{
837 const struct nlattr *a[OVS_KEY_ATTR_MAX + 1]; 859 const struct nlattr *a[OVS_KEY_ATTR_MAX + 1];
838 const struct nlattr *encap; 860 const struct nlattr *encap;
861 struct nlattr *newmask = NULL;
839 u64 key_attrs = 0; 862 u64 key_attrs = 0;
840 u64 mask_attrs = 0; 863 u64 mask_attrs = 0;
841 bool encap_valid = false; 864 bool encap_valid = false;
@@ -882,18 +905,44 @@ int ovs_nla_get_match(struct sw_flow_match *match,
882 if (err) 905 if (err)
883 return err; 906 return err;
884 907
908 if (match->mask && !mask) {
909 /* Create an exact match mask. We need to set to 0xff all the
910 * 'match->mask' fields that have been touched in 'match->key'.
911 * We cannot simply memset 'match->mask', because padding bytes
912 * and fields not specified in 'match->key' should be left to 0.
913 * Instead, we use a stream of netlink attributes, copied from
914 * 'key' and set to 0xff: ovs_key_from_nlattrs() will take care
915 * of filling 'match->mask' appropriately.
916 */
917 newmask = kmemdup(key, nla_total_size(nla_len(key)),
918 GFP_KERNEL);
919 if (!newmask)
920 return -ENOMEM;
921
922 mask_set_nlattr(newmask, 0xff);
923
924 /* The userspace does not send tunnel attributes that are 0,
925 * but we should not wildcard them nonetheless.
926 */
927 if (match->key->tun_key.ipv4_dst)
928 SW_FLOW_KEY_MEMSET_FIELD(match, tun_key, 0xff, true);
929
930 mask = newmask;
931 }
932
885 if (mask) { 933 if (mask) {
886 err = parse_flow_mask_nlattrs(mask, a, &mask_attrs); 934 err = parse_flow_mask_nlattrs(mask, a, &mask_attrs);
887 if (err) 935 if (err)
888 return err; 936 goto free_newmask;
889 937
890 if (mask_attrs & 1 << OVS_KEY_ATTR_ENCAP) { 938 if (mask_attrs & 1 << OVS_KEY_ATTR_ENCAP) {
891 __be16 eth_type = 0; 939 __be16 eth_type = 0;
892 __be16 tci = 0; 940 __be16 tci = 0;
893 941
894 if (!encap_valid) { 942 if (!encap_valid) {
895 OVS_NLERR("Encap mask attribute is set for non-VLAN frame.\n"); 943 OVS_NLERR("Encap mask attribute is set for non-VLAN frame.\n");
896 return -EINVAL; 944 err = -EINVAL;
945 goto free_newmask;
897 } 946 }
898 947
899 mask_attrs &= ~(1 << OVS_KEY_ATTR_ENCAP); 948 mask_attrs &= ~(1 << OVS_KEY_ATTR_ENCAP);
@@ -904,10 +953,13 @@ int ovs_nla_get_match(struct sw_flow_match *match,
904 mask_attrs &= ~(1 << OVS_KEY_ATTR_ETHERTYPE); 953 mask_attrs &= ~(1 << OVS_KEY_ATTR_ETHERTYPE);
905 encap = a[OVS_KEY_ATTR_ENCAP]; 954 encap = a[OVS_KEY_ATTR_ENCAP];
906 err = parse_flow_mask_nlattrs(encap, a, &mask_attrs); 955 err = parse_flow_mask_nlattrs(encap, a, &mask_attrs);
956 if (err)
957 goto free_newmask;
907 } else { 958 } else {
908 OVS_NLERR("VLAN frames must have an exact match on the TPID (mask=%x).\n", 959 OVS_NLERR("VLAN frames must have an exact match on the TPID (mask=%x).\n",
909 ntohs(eth_type)); 960 ntohs(eth_type));
910 return -EINVAL; 961 err = -EINVAL;
962 goto free_newmask;
911 } 963 }
912 964
913 if (a[OVS_KEY_ATTR_VLAN]) 965 if (a[OVS_KEY_ATTR_VLAN])
@@ -915,23 +967,22 @@ int ovs_nla_get_match(struct sw_flow_match *match,
915 967
916 if (!(tci & htons(VLAN_TAG_PRESENT))) { 968 if (!(tci & htons(VLAN_TAG_PRESENT))) {
917 OVS_NLERR("VLAN tag present bit must have an exact match (tci_mask=%x).\n", ntohs(tci)); 969 OVS_NLERR("VLAN tag present bit must have an exact match (tci_mask=%x).\n", ntohs(tci));
918 return -EINVAL; 970 err = -EINVAL;
971 goto free_newmask;
919 } 972 }
920 } 973 }
921 974
922 err = ovs_key_from_nlattrs(match, mask_attrs, a, true); 975 err = ovs_key_from_nlattrs(match, mask_attrs, a, true);
923 if (err) 976 if (err)
924 return err; 977 goto free_newmask;
925 } else {
926 /* Populate exact match flow's key mask. */
927 if (match->mask)
928 sw_flow_mask_set(match->mask, &match->range, 0xff);
929 } 978 }
930 979
931 if (!match_validate(match, key_attrs, mask_attrs)) 980 if (!match_validate(match, key_attrs, mask_attrs))
932 return -EINVAL; 981 err = -EINVAL;
933 982
934 return 0; 983free_newmask:
984 kfree(newmask);
985 return err;
935} 986}
936 987
937/** 988/**