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.
+}
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.
- 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.
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?
- /* 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.
}
} 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,