Hi Jakub,
many thanks for your review. Please see my responses inline:

On Tue, 10 Nov 2020 14:50:21 -0800
Jakub Kicinski <k...@kernel.org> wrote:

> On Sat,  7 Nov 2020 16:31:36 +0100 Andrea Mayer wrote:
> > Depending on the attribute (i.e.: SEG6_LOCAL_SRH, SEG6_LOCAL_TABLE, etc),
> > the parse() callback performs some validity checks on the provided input
> > and updates the tunnel state (slwt) with the result of the parsing
> > operation. However, an attribute may also need to reserve some additional
> > resources (i.e.: memory or setting up an eBPF program) in the parse()
> > callback to complete the parsing operation.
> 
> Looks good, a few nit picks below.
> 
> > diff --git a/net/ipv6/seg6_local.c b/net/ipv6/seg6_local.c
> > index eba23279912d..63a82e2fdea9 100644
> > --- a/net/ipv6/seg6_local.c
> > +++ b/net/ipv6/seg6_local.c
> > @@ -710,6 +710,12 @@ static int cmp_nla_srh(struct seg6_local_lwt *a, 
> > struct seg6_local_lwt *b)
> >     return memcmp(a->srh, b->srh, len);
> >  }
> >  
> > +static void destroy_attr_srh(struct seg6_local_lwt *slwt)
> > +{
> > +   kfree(slwt->srh);
> > +   slwt->srh = NULL;
> 
> This should never be called twice, right? No need for defensive
> programming then.
>

Yes, the patch that I wrote does not call the function twice.
When I wrote the code my only concern was if someone (in the future) could ever
call the destroy_attr_srh() in a wrong way or in an inappropriate part of the 
code.
This choice was driven by an excess of paranoia rather than a real issue.

Given that, I will remove it with no problem at all in v3.

> > +}
> > +
> >  static int parse_nla_table(struct nlattr **attrs, struct seg6_local_lwt 
> > *slwt)
> >  {
> >     slwt->table = nla_get_u32(attrs[SEG6_LOCAL_TABLE]);
> > @@ -901,16 +907,33 @@ static int cmp_nla_bpf(struct seg6_local_lwt *a, 
> > struct seg6_local_lwt *b)
> >     return strcmp(a->bpf.name, b->bpf.name);
> >  }
> >  
> > +static void destroy_attr_bpf(struct seg6_local_lwt *slwt)
> > +{
> > +   kfree(slwt->bpf.name);
> > +   if (slwt->bpf.prog)
> > +           bpf_prog_put(slwt->bpf.prog);
> 
> Same - why check if prog is NULL? That doesn't seem necessary if the
> code is correct.
> 

Same as above.

> > +   slwt->bpf.name = NULL;
> > +   slwt->bpf.prog = NULL;
> > +}
> > +
> >  struct seg6_action_param {
> >     int (*parse)(struct nlattr **attrs, struct seg6_local_lwt *slwt);
> >     int (*put)(struct sk_buff *skb, struct seg6_local_lwt *slwt);
> >     int (*cmp)(struct seg6_local_lwt *a, struct seg6_local_lwt *b);
> > +
> > +   /* optional destroy() callback useful for releasing resources which
> > +    * have been previously acquired in the corresponding parse()
> > +    * function.
> > +    */
> > +   void (*destroy)(struct seg6_local_lwt *slwt);
> >  };
> >  
> >  static struct seg6_action_param seg6_action_params[SEG6_LOCAL_MAX + 1] = {
> >     [SEG6_LOCAL_SRH]        = { .parse = parse_nla_srh,
> >                                 .put = put_nla_srh,
> > -                               .cmp = cmp_nla_srh },
> > +                               .cmp = cmp_nla_srh,
> > +                               .destroy = destroy_attr_srh },
> >  
> >     [SEG6_LOCAL_TABLE]      = { .parse = parse_nla_table,
> >                                 .put = put_nla_table,
> > @@ -934,13 +957,68 @@ static struct seg6_action_param 
> > seg6_action_params[SEG6_LOCAL_MAX + 1] = {
> >  
> >     [SEG6_LOCAL_BPF]        = { .parse = parse_nla_bpf,
> >                                 .put = put_nla_bpf,
> > -                               .cmp = cmp_nla_bpf },
> > +                               .cmp = cmp_nla_bpf,
> > +                               .destroy = destroy_attr_bpf },
> >  
> >  };
> >  
> > +/* call the destroy() callback (if available) for each set attribute in
> > + * @parsed_attrs, starting from attribute index @start up to @end excluded.
> > + */
> > +static void __destroy_attrs(unsigned long parsed_attrs, int start, int end,
> 
> You always pass 0 as start, no need for that argument.
> 
> slwt and max_parsed should be the only args this function needs.
> 

My initial goal was to explicitly pass the 'parsed_attrs' as an argument so that
we can reuse this function also for further improvements (i.e.: the patch for
optional attributes I am working on).

However, for v3 I will keep the stuff straight forward following what you
suggested to me.

> > +                       struct seg6_local_lwt *slwt)
> > +{
> > +   struct seg6_action_param *param;
> > +   int i;
> > +
> > +   /* Every seg6local attribute is identified by an ID which is encoded as
> > +    * a flag (i.e: 1 << ID) in the @parsed_attrs bitmask; such bitmask
> > +    * keeps track of the attributes parsed so far.
> > +
> > +    * We scan the @parsed_attrs bitmask, starting from the attribute
> > +    * identified by @start up to the attribute identified by @end
> > +    * excluded. For each set attribute, we retrieve the corresponding
> > +    * destroy() callback.
> > +    * If the callback is not available, then we skip to the next
> > +    * attribute; otherwise, we call the destroy() callback.
> > +    */
> > +   for (i = start; i < end; ++i) {
> > +           if (!(parsed_attrs & (1 << i)))
> > +                   continue;
> > +
> > +           param = &seg6_action_params[i];
> > +
> > +           if (param->destroy)
> > +                   param->destroy(slwt);
> > +   }
> > +}
> > +
> > +/* release all the resources that may have been acquired during parsing
> > + * operations.
> > + */
> > +static void destroy_attrs(struct seg6_local_lwt *slwt)
> > +{
> > +   struct seg6_action_desc *desc;
> > +   unsigned long attrs;
> > +
> > +   desc = slwt->desc;
> > +   if (!desc) {
> > +           WARN_ONCE(1,
> > +                     "seg6local: seg6_action_desc* for action %d is NULL",
> > +                     slwt->action);
> > +           return;
> > +   }
> 
> Defensive programming?
> 

Yes, like above. I will remove the check on the 'desc' and consequently the
WARN_ON in v3.

> > +
> > +   /* get the attributes for the current behavior instance */
> > +   attrs = desc->attrs;
> > +
> > +   __destroy_attrs(attrs, 0, SEG6_LOCAL_MAX + 1, slwt);
> > +}
> > +
> >  static int parse_nla_action(struct nlattr **attrs, struct seg6_local_lwt 
> > *slwt)
> >  {
> >     struct seg6_action_param *param;
> > +   unsigned long parsed_attrs = 0;
> >     struct seg6_action_desc *desc;
> >     int i, err;
> >  
> > @@ -963,11 +1041,22 @@ static int parse_nla_action(struct nlattr **attrs, 
> > struct seg6_local_lwt *slwt)
> >  
> >                     err = param->parse(attrs, slwt);
> >                     if (err < 0)
> > -                           return err;
> > +                           goto parse_err;
> > +
> > +                   /* current attribute has been parsed correctly */
> > +                   parsed_attrs |= (1 << i);
> 
> Why do you need parsed_attrs, attributes are not optional. Everything
> that's sepecified in desc->attrs and lower than i must had been parsed.
> 

Here, all the attributes are required and not optional. So in this patch, the
parsed_attrs can be certainly avoided. I'll remove it in v3.

> >             }
> >     }
> >  
> >     return 0;
> > +
> > +parse_err:
> > +   /* release any resource that may have been acquired during the i-1
> > +    * parse() operations.
> > +    */
> > +   __destroy_attrs(parsed_attrs, 0, i, slwt);
> > +
> > +   return err;
> >  }
> >  
> >  static int seg6_local_build_state(struct net *net, struct nlattr *nla,
> 
> 

Thank you,
Andrea

Reply via email to