On Mon, Oct 16, 2017 at 10:49 AM, Pravin Shelar <pshe...@ovn.org> wrote:
> On Mon, Oct 16, 2017 at 12:05 AM, Andy Zhou <az...@ovn.org> wrote:
>> On Fri, Oct 13, 2017 at 5:12 PM, Pravin Shelar <pshe...@ovn.org> wrote:
>>> On Thu, Oct 12, 2017 at 3:38 PM, Andy Zhou <az...@ovn.org> wrote:
>>>> OVS kernel datapath so far does not support Openflow meter action.
>>>> This is the first stab at adding kernel datapath meter support.
>>>> This implementation supports only drop band type.
>>>>
>>>> Signed-off-by: Andy Zhou <az...@ovn.org>
>>>> ---
>>>>  net/openvswitch/Makefile   |   1 +
>>>>  net/openvswitch/datapath.c |  14 +-
>>>>  net/openvswitch/datapath.h |   3 +
>>>>  net/openvswitch/meter.c    | 611 
>>>> +++++++++++++++++++++++++++++++++++++++++++++
>>>>  net/openvswitch/meter.h    |  54 ++++
>>>>  5 files changed, 681 insertions(+), 2 deletions(-)
>>>>  create mode 100644 net/openvswitch/meter.c
>>>>  create mode 100644 net/openvswitch/meter.h
>>>>
>>> ...
>>>
>>>> diff --git a/net/openvswitch/meter.c b/net/openvswitch/meter.c
>>>> new file mode 100644
>>>> index 000000000000..f24ebb5f7af4
>>>> --- /dev/null
>>>> +++ b/net/openvswitch/meter.c
>>>
>>> ....
>>> ....
>>>> +static int ovs_meter_cmd_features(struct sk_buff *skb, struct genl_info 
>>>> *info)
>>>> +{
>>>> +       struct datapath *dp;
>>>> +       struct ovs_header *ovs_header = info->userhdr;
>>>> +       struct sk_buff *reply;
>>>> +       struct ovs_header *ovs_reply_header;
>>>> +       struct nlattr *nla, *band_nla;
>>>> +       int err;
>>>> +
>>>> +       /* Check that the datapath exists */
>>>> +       ovs_lock();
>>>> +       dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
>>>> +       ovs_unlock();
>>>> +       if (!dp)
>>>> +               return -ENODEV;
>>>> +
>>> why dp check is required for this API?
>> Is it possible for another core delete the dp, before ovs_lock()
>> returns? Then, in theory, get_dp() can
>> return NULL, no?
>
> I do not see dp used anywhere in function. so the question was why is
> dp lookup done here?

Got it. I misunderstood. You are right, we don't need the dp pointer.
Just posted v2.

>
>>>
>>>> +       reply = ovs_meter_cmd_reply_start(info, OVS_METER_CMD_FEATURES,
>>>> +                                         &ovs_reply_header);
>>>> +       if (!reply)
>>>> +               return PTR_ERR(reply);
>>>> +
>>>> +       if (nla_put_u32(reply, OVS_METER_ATTR_MAX_METERS, U32_MAX) ||
>>>> +           nla_put_u32(reply, OVS_METER_ATTR_MAX_BANDS, DP_MAX_BANDS))
>>>> +               goto nla_put_failure;
>>>> +
>>>> +       nla = nla_nest_start(reply, OVS_METER_ATTR_BANDS);
>>>> +       if (!nla)
>>>> +               goto nla_put_failure;
>>>> +
>>>> +       band_nla = nla_nest_start(reply, OVS_BAND_ATTR_UNSPEC);
>>>> +       if (!band_nla)
>>>> +               goto nla_put_failure;
>>>> +       /* Currently only DROP band type is supported. */
>>>> +       if (nla_put_u32(reply, OVS_BAND_ATTR_TYPE, 
>>>> OVS_METER_BAND_TYPE_DROP))
>>>> +               goto nla_put_failure;
>>>> +       nla_nest_end(reply, band_nla);
>>>> +       nla_nest_end(reply, nla);
>>>> +
>>>> +       genlmsg_end(reply, ovs_reply_header);
>>>> +       return genlmsg_reply(reply, info);
>>>> +
>>>> +nla_put_failure:
>>>> +       nlmsg_free(reply);
>>>> +       err = -EMSGSIZE;
>>>> +       return err;
>>>> +}
>>>> +
>>> ....
>>>
>>>> +static int ovs_meter_cmd_set(struct sk_buff *skb, struct genl_info *info)
>>>> +{
>>>> +       struct nlattr **a = info->attrs;
>>>> +       struct dp_meter *meter, *old_meter;
>>>> +       struct sk_buff *reply;
>>>> +       struct ovs_header *ovs_reply_header;
>>>> +       struct ovs_header *ovs_header = info->userhdr;
>>>> +       struct datapath *dp;
>>>> +       int err;
>>>> +       u32 meter_id;
>>>> +       bool failed;
>>>> +
>>>> +       meter = dp_meter_create(a);
>>>> +       if (IS_ERR_OR_NULL(meter))
>>>> +               return PTR_ERR(meter);
>>>> +
>>>> +       reply = ovs_meter_cmd_reply_start(info, OVS_METER_CMD_SET,
>>>> +                                         &ovs_reply_header);
>>>> +       if (IS_ERR(reply)) {
>>>> +               err = PTR_ERR(reply);
>>>> +               goto exit_free_meter;
>>>> +       }
>>>> +
>>>> +       ovs_lock();
>>>> +       dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
>>>> +       if (!dp) {
>>>> +               err = -ENODEV;
>>>> +               goto exit_unlock;
>>>> +       }
>>>> +
>>>> +       if (!a[OVS_METER_ATTR_ID]) {
>>>> +               err = -ENODEV;
>>>> +               goto exit_unlock;
>>>> +       }
>>>> +
>>>> +       meter_id = nla_get_u32(a[OVS_METER_ATTR_ID]);
>>>> +
>>>> +       /* Cannot fail after this. */
>>>> +       old_meter = lookup_meter(dp, meter_id);
>>>> +       attach_meter(dp, meter);
>>>> +       ovs_unlock();
>>>> +
>>> After the unlock, it is not safe to keep the ref to old_meter. better
>>> to release lock at the end. we could optimize it later if required.
>>
>> I see a problem here: the old_meter has not been removed from the list before
>> unlock. The code should have been:
>>
>> old_meter = lookup_meter(dp, meter_id);
>> detch_meter(dp, old_meter);
>> attach_meter(dp, meter);
>> ovs_unlock();
>>
>> Do you still see a problem w.r.t. unlock() here? Once detch_meter() is 
>> called,
>> another thread should not have access to 'old_meter' any more. right?
>
> looks good.

Reply via email to