aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/openvswitch/flow_netlink.c107
1 files changed, 53 insertions, 54 deletions
diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c
index 482a0cbb22e8..ed3109761827 100644
--- a/net/openvswitch/flow_netlink.c
+++ b/net/openvswitch/flow_netlink.c
@@ -50,21 +50,18 @@
50 50
51#include "flow_netlink.h" 51#include "flow_netlink.h"
52 52
53static void update_range__(struct sw_flow_match *match, 53static void update_range(struct sw_flow_match *match,
54 size_t offset, size_t size, bool is_mask) 54 size_t offset, size_t size, bool is_mask)
55{ 55{
56 struct sw_flow_key_range *range = NULL; 56 struct sw_flow_key_range *range;
57 size_t start = rounddown(offset, sizeof(long)); 57 size_t start = rounddown(offset, sizeof(long));
58 size_t end = roundup(offset + size, sizeof(long)); 58 size_t end = roundup(offset + size, sizeof(long));
59 59
60 if (!is_mask) 60 if (!is_mask)
61 range = &match->range; 61 range = &match->range;
62 else if (match->mask) 62 else
63 range = &match->mask->range; 63 range = &match->mask->range;
64 64
65 if (!range)
66 return;
67
68 if (range->start == range->end) { 65 if (range->start == range->end) {
69 range->start = start; 66 range->start = start;
70 range->end = end; 67 range->end = end;
@@ -80,22 +77,20 @@ static void update_range__(struct sw_flow_match *match,
80 77
81#define SW_FLOW_KEY_PUT(match, field, value, is_mask) \ 78#define SW_FLOW_KEY_PUT(match, field, value, is_mask) \
82 do { \ 79 do { \
83 update_range__(match, offsetof(struct sw_flow_key, field), \ 80 update_range(match, offsetof(struct sw_flow_key, field), \
84 sizeof((match)->key->field), is_mask); \ 81 sizeof((match)->key->field), is_mask); \
85 if (is_mask) { \ 82 if (is_mask) \
86 if ((match)->mask) \ 83 (match)->mask->key.field = value; \
87 (match)->mask->key.field = value; \ 84 else \
88 } else { \
89 (match)->key->field = value; \ 85 (match)->key->field = value; \
90 } \
91 } while (0) 86 } while (0)
92 87
93#define SW_FLOW_KEY_MEMCPY_OFFSET(match, offset, value_p, len, is_mask) \ 88#define SW_FLOW_KEY_MEMCPY_OFFSET(match, offset, value_p, len, is_mask) \
94 do { \ 89 do { \
95 update_range__(match, offset, len, is_mask); \ 90 update_range(match, offset, len, is_mask); \
96 if (is_mask) \ 91 if (is_mask) \
97 memcpy((u8 *)&(match)->mask->key + offset, value_p, \ 92 memcpy((u8 *)&(match)->mask->key + offset, value_p, \
98 len); \ 93 len); \
99 else \ 94 else \
100 memcpy((u8 *)(match)->key + offset, value_p, len); \ 95 memcpy((u8 *)(match)->key + offset, value_p, len); \
101 } while (0) 96 } while (0)
@@ -104,18 +99,16 @@ static void update_range__(struct sw_flow_match *match,
104 SW_FLOW_KEY_MEMCPY_OFFSET(match, offsetof(struct sw_flow_key, field), \ 99 SW_FLOW_KEY_MEMCPY_OFFSET(match, offsetof(struct sw_flow_key, field), \
105 value_p, len, is_mask) 100 value_p, len, is_mask)
106 101
107#define SW_FLOW_KEY_MEMSET_FIELD(match, field, value, is_mask) \ 102#define SW_FLOW_KEY_MEMSET_FIELD(match, field, value, is_mask) \
108 do { \ 103 do { \
109 update_range__(match, offsetof(struct sw_flow_key, field), \ 104 update_range(match, offsetof(struct sw_flow_key, field), \
110 sizeof((match)->key->field), is_mask); \ 105 sizeof((match)->key->field), is_mask); \
111 if (is_mask) { \ 106 if (is_mask) \
112 if ((match)->mask) \ 107 memset((u8 *)&(match)->mask->key.field, value, \
113 memset((u8 *)&(match)->mask->key.field, value,\ 108 sizeof((match)->mask->key.field)); \
114 sizeof((match)->mask->key.field)); \ 109 else \
115 } else { \
116 memset((u8 *)&(match)->key->field, value, \ 110 memset((u8 *)&(match)->key->field, value, \
117 sizeof((match)->key->field)); \ 111 sizeof((match)->key->field)); \
118 } \
119 } while (0) 112 } while (0)
120 113
121static bool match_validate(const struct sw_flow_match *match, 114static bool match_validate(const struct sw_flow_match *match,
@@ -677,8 +670,7 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs,
677 670
678 SW_FLOW_KEY_PUT(match, eth.tci, tci, is_mask); 671 SW_FLOW_KEY_PUT(match, eth.tci, tci, is_mask);
679 attrs &= ~(1 << OVS_KEY_ATTR_VLAN); 672 attrs &= ~(1 << OVS_KEY_ATTR_VLAN);
680 } else if (!is_mask) 673 }
681 SW_FLOW_KEY_PUT(match, eth.tci, htons(0xffff), true);
682 674
683 if (attrs & (1 << OVS_KEY_ATTR_ETHERTYPE)) { 675 if (attrs & (1 << OVS_KEY_ATTR_ETHERTYPE)) {
684 __be16 eth_type; 676 __be16 eth_type;
@@ -903,8 +895,8 @@ static void mask_set_nlattr(struct nlattr *attr, u8 val)
903 * attribute specifies the mask field of the wildcarded flow. 895 * attribute specifies the mask field of the wildcarded flow.
904 */ 896 */
905int ovs_nla_get_match(struct sw_flow_match *match, 897int ovs_nla_get_match(struct sw_flow_match *match,
906 const struct nlattr *key, 898 const struct nlattr *nla_key,
907 const struct nlattr *mask) 899 const struct nlattr *nla_mask)
908{ 900{
909 const struct nlattr *a[OVS_KEY_ATTR_MAX + 1]; 901 const struct nlattr *a[OVS_KEY_ATTR_MAX + 1];
910 const struct nlattr *encap; 902 const struct nlattr *encap;
@@ -914,7 +906,7 @@ int ovs_nla_get_match(struct sw_flow_match *match,
914 bool encap_valid = false; 906 bool encap_valid = false;
915 int err; 907 int err;
916 908
917 err = parse_flow_nlattrs(key, a, &key_attrs); 909 err = parse_flow_nlattrs(nla_key, a, &key_attrs);
918 if (err) 910 if (err)
919 return err; 911 return err;
920 912
@@ -955,36 +947,43 @@ int ovs_nla_get_match(struct sw_flow_match *match,
955 if (err) 947 if (err)
956 return err; 948 return err;
957 949
958 if (match->mask && !mask) { 950 if (match->mask) {
959 /* Create an exact match mask. We need to set to 0xff all the 951 if (!nla_mask) {
960 * 'match->mask' fields that have been touched in 'match->key'. 952 /* Create an exact match mask. We need to set to 0xff
961 * We cannot simply memset 'match->mask', because padding bytes 953 * all the 'match->mask' fields that have been touched
962 * and fields not specified in 'match->key' should be left to 0. 954 * in 'match->key'. We cannot simply memset
963 * Instead, we use a stream of netlink attributes, copied from 955 * 'match->mask', because padding bytes and fields not
964 * 'key' and set to 0xff: ovs_key_from_nlattrs() will take care 956 * specified in 'match->key' should be left to 0.
965 * of filling 'match->mask' appropriately. 957 * Instead, we use a stream of netlink attributes,
966 */ 958 * copied from 'key' and set to 0xff.
967 newmask = kmemdup(key, nla_total_size(nla_len(key)), 959 * ovs_key_from_nlattrs() will take care of filling
968 GFP_KERNEL); 960 * 'match->mask' appropriately.
969 if (!newmask) 961 */
970 return -ENOMEM; 962 newmask = kmemdup(nla_key,
963 nla_total_size(nla_len(nla_key)),
964 GFP_KERNEL);
965 if (!newmask)
966 return -ENOMEM;
971 967
972 mask_set_nlattr(newmask, 0xff); 968 mask_set_nlattr(newmask, 0xff);
973 969
974 /* The userspace does not send tunnel attributes that are 0, 970 /* The userspace does not send tunnel attributes that
975 * but we should not wildcard them nonetheless. 971 * are 0, but we should not wildcard them nonetheless.
976 */ 972 */
977 if (match->key->tun_key.ipv4_dst) 973 if (match->key->tun_key.ipv4_dst)
978 SW_FLOW_KEY_MEMSET_FIELD(match, tun_key, 0xff, true); 974 SW_FLOW_KEY_MEMSET_FIELD(match, tun_key,
975 0xff, true);
979 976
980 mask = newmask; 977 nla_mask = newmask;
981 } 978 }
982 979
983 if (mask) { 980 err = parse_flow_mask_nlattrs(nla_mask, a, &mask_attrs);
984 err = parse_flow_mask_nlattrs(mask, a, &mask_attrs);
985 if (err) 981 if (err)
986 goto free_newmask; 982 goto free_newmask;
987 983
984 /* Always match on tci. */
985 SW_FLOW_KEY_PUT(match, eth.tci, htons(0xffff), true);
986
988 if (mask_attrs & 1 << OVS_KEY_ATTR_ENCAP) { 987 if (mask_attrs & 1 << OVS_KEY_ATTR_ENCAP) {
989 __be16 eth_type = 0; 988 __be16 eth_type = 0;
990 __be16 tci = 0; 989 __be16 tci = 0;