[ovs-dev] [RFC v2] datapath/flow_netlink: Create right mask with disabled megaflows
Daniele Di Proietto
ddiproietto at vmware.com
Fri Jul 11 16:32:02 UTC 2014
On Jul 10, 2014, at 5:27 PM, Pravin Shelar <pshelar at nicira.com> wrote:
> On Thu, Jul 10, 2014 at 4:29 PM, Daniele Di Proietto
> <ddiproietto at vmware.com> wrote:
>> 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 (since commit 9cef26ac6a71).
>>
>> 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.
>>
>> Reported-by: Alex Wang <alexw at nicira.com>
>> Suggested-by: Pravin B Shelar <pshelar at nicira.com>
>> Signed-off-by: Daniele Di Proietto <ddiproietto at vmware.com>
>> ---
>> v2:
>> Implemented Pravin's suggestions:
>> - fixed two memory leaks
>> - expanded the comment
>> ---
>
> I just noticed couple of issues.
>
>> datapath/flow_netlink.c | 84 +++++++++++++++++++++++++++++++++++--------------
>> 1 file changed, 61 insertions(+), 23 deletions(-)
>>
>> diff --git a/datapath/flow_netlink.c b/datapath/flow_netlink.c
>> index f0cf2ed..d7706a6 100644
>> --- a/datapath/flow_netlink.c
>> +++ b/datapath/flow_netlink.c
>> @@ -106,11 +106,6 @@ static void update_range__(struct sw_flow_match *match,
>> SW_FLOW_KEY_MEMCPY_OFFSET(match, offsetof(struct sw_flow_key, field), \
>> value_p, len, is_mask)
>>
>> -static u16 range_n_bytes(const struct sw_flow_key_range *range)
>> -{
>> - return range->end - range->start;
>> -}
>> -
>> static bool match_validate(const struct sw_flow_match *match,
>> u64 key_attrs, u64 mask_attrs)
>> {
>> @@ -732,7 +727,7 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs,
>> mpls_key->mpls_lse, is_mask);
>>
>> attrs &= ~(1ULL << OVS_KEY_ATTR_MPLS);
>> - }
>> + }
>>
>> if (attrs & (1ULL << OVS_KEY_ATTR_TCP)) {
>> const struct ovs_key_tcp *tcp_key;
>> @@ -814,13 +809,32 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs,
>> return 0;
>> }
>>
>> -static void sw_flow_mask_set(struct sw_flow_mask *mask,
>> - struct sw_flow_key_range *range, u8 val)
>> +/* We expect the nlattr stream to be already validated */
>> +static int nlattr_set(struct nlattr *attr, u8 val, bool parent)
>> {
>> - u8 *m = (u8 *)&mask->key + range->start;
>> + struct nlattr *nla;
>> + int rem;
>> +
>> + nla_for_each_nested(nla, attr, rem) {
>> + u16 type = nla_type(nla);
>>
> type should be enum ovs_key_attr
>
I’m not sure. ‘type' sometimes can contain an enum ovs_tunnel_key_attr (but in that case we’re not using the value).
Elsewhere in the code we use int to store the nla_type() return value.
If I’m using the ovs_key_lens array I might just remove the variable.
>> - mask->range = *range;
>> - memset(m, val, range_n_bytes(range));
>> + /* If we are parsing the parent attribute, we may encounter
>> + * nested attributes. To deal with them we call ourselves
>> + */
>> + if (parent && (type == OVS_KEY_ATTR_ENCAP ||
>> + type == OVS_KEY_ATTR_TUNNEL)) {
>
> These two checks looks arbitrary, can you use ovs_key_lens array
> already defined, to find nested attributes?
>
Sure, I'll do that. The reason I didn’t do it in the first place is that a value of -1 in ovs_*_key_lens means variable length attribute, not just nested attribute (e.g. ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS]).
> We can not compare type from nested attribute to enum of ovs_key_attr.
> I think that's why you have introduced parent argument. in that case
> we need to rename parent to some better name to make it cleaner.
>
Yes, that’s why I introduced parent. I’ll give it a better name
> Thanks,
> Pravin.
I’ll post a v3 with the suggested changes.
Thanks,
Daniele
>
>> + nlattr_set(nla, val, false);
>> + } else {
>> + memset(nla_data(nla), val, nla_len(nla));
>> + }
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int mask_set_nlattr(struct nlattr *attr, u8 val)
>> +{
>> + return nlattr_set(attr, val, true);
>> }
>>
>> /**
>> @@ -841,6 +855,7 @@ int ovs_nla_get_match(struct sw_flow_match *match,
>> {
>> const struct nlattr *a[OVS_KEY_ATTR_MAX + 1];
>> const struct nlattr *encap;
>> + struct nlattr *newmask = NULL;
>> u64 key_attrs = 0;
>> u64 mask_attrs = 0;
>> bool encap_valid = false;
>> @@ -887,18 +902,40 @@ int ovs_nla_get_match(struct sw_flow_match *match,
>> if (err)
>> return err;
>>
>> + if (match->mask && !mask) {
>> + /* Create an exact match mask. We need to set to 0xff all the
>> + * 'match->mask' fields that have been touched in 'match->key'.
>> + * We cannot simply memset 'match->mask', because padding bytes
>> + * and fields not specified in 'match->key' should be left to 0.
>> + * Instead, we use a stream of netlink attributes, copied from
>> + * 'key' and set to 0xff: ovs_key_from_nlattrs() will take care
>> + * of filling 'match->mask' appropriately.
>> + */
>> + newmask = kmemdup(key, nla_total_size(nla_len(key)),
>> + GFP_KERNEL);
>> + if (!newmask)
>> + return -ENOMEM;
>> +
>> + err = mask_set_nlattr(newmask, 0xff);
>> + if (err)
>> + goto free_newmask;
>> +
>> + mask = newmask;
>> + }
>> +
>> if (mask) {
>> err = parse_flow_mask_nlattrs(mask, a, &mask_attrs);
>> if (err)
>> - return err;
>> + goto free_newmask;
>>
>> - if (mask_attrs & 1ULL << OVS_KEY_ATTR_ENCAP) {
>> + if (mask_attrs & 1ULL << OVS_KEY_ATTR_ENCAP) {
>> __be16 eth_type = 0;
>> __be16 tci = 0;
>>
>> if (!encap_valid) {
>> OVS_NLERR("Encap mask attribute is set for non-VLAN frame.\n");
>> - return -EINVAL;
>> + err = -EINVAL;
>> + goto free_newmask;
>> }
>>
>> mask_attrs &= ~(1ULL << OVS_KEY_ATTR_ENCAP);
>> @@ -909,10 +946,12 @@ int ovs_nla_get_match(struct sw_flow_match *match,
>> mask_attrs &= ~(1ULL << OVS_KEY_ATTR_ETHERTYPE);
>> encap = a[OVS_KEY_ATTR_ENCAP];
>> err = parse_flow_mask_nlattrs(encap, a, &mask_attrs);
>> + goto free_newmask;
>> } else {
>> OVS_NLERR("VLAN frames must have an exact match on the TPID (mask=%x).\n",
>> ntohs(eth_type));
>> - return -EINVAL;
>> + err = -EINVAL;
>> + goto free_newmask;
>> }
>>
>> if (a[OVS_KEY_ATTR_VLAN])
>> @@ -920,23 +959,22 @@ int ovs_nla_get_match(struct sw_flow_match *match,
>>
>> if (!(tci & htons(VLAN_TAG_PRESENT))) {
>> OVS_NLERR("VLAN tag present bit must have an exact match (tci_mask=%x).\n", ntohs(tci));
>> - return -EINVAL;
>> + err = -EINVAL;
>> + goto free_newmask;
>> }
>> }
>>
>> err = ovs_key_from_nlattrs(match, mask_attrs, a, true);
>> if (err)
>> - return err;
>> - } else {
>> - /* Populate exact match flow's key mask. */
>> - if (match->mask)
>> - sw_flow_mask_set(match->mask, &match->range, 0xff);
>> + goto free_newmask;
>> }
>>
>> if (!match_validate(match, key_attrs, mask_attrs))
>> - return -EINVAL;
>> + err = -EINVAL;
>>
>> - return 0;
>> +free_newmask:
>> + kfree(newmask);
>> + return err;
>> }
>>
>> /**
>> --
>> 2.0.0
More information about the dev
mailing list