BPF List
 help / color / mirror / Atom feed
From: Kui-Feng Lee <sinquersw@gmail.com>
To: Quentin Monnet <quentin@isovalent.com>,
	Kui-Feng Lee <thinker.li@gmail.com>
Cc: bpf@vger.kernel.org, ast@kernel.org, martin.lau@linux.dev,
	song@kernel.org, kernel-team@meta.com, andrii@kernel.org,
	yhs@meta.com, Kui-Feng Lee <kuifeng@meta.com>
Subject: Re: [PATCH bpf-next] bpftool: Register struct_ops with a link.
Date: Tue, 18 Apr 2023 17:36:40 -0700	[thread overview]
Message-ID: <a02b37d9-279a-00c1-351c-a4da23b54abf@gmail.com> (raw)
In-Reply-To: <CACdoK4LU6Zh341YYQTgsciRhfMZYP--+_mY_=+HfBW7hBFmF7A@mail.gmail.com>



On 4/18/23 15:55, Quentin Monnet wrote:
> On Tue, 18 Apr 2023 at 21:01, Kui-Feng Lee <thinker.li@gmail.com> wrote:
>>
>> You can include an optional path after specifying the object name for the
>> 'struct_ops register' subcommand.
>>
>> Since the commit 226bc6ae6405 ("Merge branch 'Transit between BPF TCP
>> congestion controls.'") has been accepted, it is now possible to create a
>> link for a struct_ops. This can be done by defining a struct_ops in
>> SEC(".struct_ops.link") to make libbpf returns a real link. If we don't pin
>> the links before leaving bpftool, they will disappear. To instruct bpftool
>> to pin the links in a directory with the names of the maps, we need to
>> provide the path of that directory.
>>
>> Signed-off-by: Kui-Feng Lee <kuifeng@meta.com>
>> ---
>>   tools/bpf/bpftool/struct_ops.c | 86 ++++++++++++++++++++++++++++------
>>   1 file changed, 72 insertions(+), 14 deletions(-)
>>
>> diff --git a/tools/bpf/bpftool/struct_ops.c b/tools/bpf/bpftool/struct_ops.c
>> index b389f4830e11..d1ae39f9d8df 100644
>> --- a/tools/bpf/bpftool/struct_ops.c
>> +++ b/tools/bpf/bpftool/struct_ops.c
>> @@ -475,21 +475,62 @@ static int do_unregister(int argc, char **argv)
>>          return cmd_retval(&res, true);
>>   }
>>
>> +static int pathname_concat(char *buf, int buf_sz, const char *path,
>> +                          const char *name)
>> +{
>> +       int len;
>> +
>> +       len = snprintf(buf, buf_sz, "%s/%s", path, name);
>> +       if (len < 0)
>> +               return -EINVAL;
>> +       if (len >= buf_sz)
>> +               return -ENAMETOOLONG;
>> +
>> +       return 0;
>> +}
> 
> This is nearly identical to the one in prog.c. If we do need this, we
> should move it to common.c and reuse it.

Got it!

> 
>> +
>> +static int pin_link(struct bpf_link *link, const char *pindir,
>> +                   const char *name)
>> +{
>> +       char pinfile[PATH_MAX];
>> +       int err;
>> +
>> +       err = pathname_concat(pinfile, sizeof(pinfile), pindir, name);
>> +       if (err)
>> +               return -1;
>> +
>> +       err = bpf_link__pin(link, pinfile);
>> +       if (err)
>> +               return -1;
>> +
>> +       return 0;
>> +}
>> +
>>   static int do_register(int argc, char **argv)
>>   {
>>          LIBBPF_OPTS(bpf_object_open_opts, open_opts);
>> +       __u32 link_info_len = sizeof(struct bpf_link_info);
>> +       struct bpf_link_info link_info = {};
>>          struct bpf_map_info info = {};
>>          __u32 info_len = sizeof(info);
>>          int nr_errs = 0, nr_maps = 0;
>> +       const char *pindir = NULL;
>>          struct bpf_object *obj;
>>          struct bpf_link *link;
>>          struct bpf_map *map;
>>          const char *file;
>>
>> -       if (argc != 1)
>> +       if (argc != 1 && argc != 2)
>>                  usage();
>>
>>          file = GET_ARG();
>> +       if (argc == 1)
>> +               pindir = GET_ARG();
>> +
>> +       if (pindir && mount_bpffs_for_pin(pindir)) {
>> +               p_err("can't mount bpffs for pinning");
>> +               return -1;
>> +       }
>>
>>          if (verifier_logs)
>>                  /* log_level1 + log_level2 + stats, but not stable UAPI */
>> @@ -519,21 +560,38 @@ static int do_register(int argc, char **argv)
>>                  }
>>                  nr_maps++;
>>
>> -               bpf_link__disconnect(link);
>> -               bpf_link__destroy(link);
>> -
>> -               if (!bpf_map_get_info_by_fd(bpf_map__fd(map), &info,
>> -                                           &info_len))
>> -                       p_info("Registered %s %s id %u",
>> -                              get_kern_struct_ops_name(&info),
>> -                              bpf_map__name(map),
>> -                              info.id);
>> -               else
>> +               if (bpf_map_get_info_by_fd(bpf_map__fd(map), &info,
>> +                                          &info_len)) {
>>                          /* Not p_err.  The struct_ops was attached
>>                           * successfully.
>>                           */
>> -                       p_info("Registered %s but can't find id: %s",
>> -                              bpf_map__name(map), strerror(errno));
>> +                       p_err("Registered %s but can't find id: %s",
>> +                             bpf_map__name(map), strerror(errno));
> 
> See comment right above: p_info() is probably enough here. If for some
> reason we do need to switch to an error message and change the
> existing behaviour, can you please motivate it and make it a separate
> commit (and update the comment)?

Ok! I will revert this change concerning about behavior changing.

> 
>> +                       nr_errs++;
>> +               } else if (!(bpf_map__map_flags(map) & BPF_F_LINK)) {
>> +                       p_info("Registered %s %s id %u",
>> +                              get_kern_struct_ops_name(&info),
>> +                              info.name,
>> +                              info.id);
>> +               } else if (bpf_link_get_info_by_fd(bpf_link__fd(link),
>> +                                                  &link_info,
>> +                                           &link_info_len)) {
>> +                       p_err("Registered %s but can't find link id: %s",
>> +                             bpf_map__name(map), strerror(errno));
>> +                       nr_errs++;
>> +               } else if (pindir && pin_link(link, pindir, info.name)) {
> 
> Why do we have "pindir" and not a pinned path? Instead of taking a
> directory name to concatenate, why not let the user specify the pinned
> path directly, as we do for maps, programs, and links already? The
> only existing use of dirname + concat I can think of is for "bpftool
> prog loadall", but this is because we need one path to pin multiple
> programs. Here we just have one, so let the user choose their path?

We could have multiple struct_ops in an object file as well.

> 
> I would also avoid using "pin" too much in variable or function names.
> I know we have "bpf_link__pin()", but I find it makes things confusing
> between the concepts of pinned objects (through BPF_OBJ_PIN) and of
> BPF links. How about "linkdir" or "linkpath" instead?

It sounds good!

> 
>> +                       p_err("can't pin link %u for %s: %s",
>> +                             link_info.id, info.name,
>> +                             strerror(errno));
>> +                       nr_errs++;
>> +               } else
>> +                       p_info("Registered %s %s map id %u link id %u",
>> +                              get_kern_struct_ops_name(&info),
>> +                              info.name, info.id, link_info.id);
> 
> Missing curly brackets on the "else" block.
> 
> I find it not easy to follow the logic in this long "else if..."
> chain, it would probably feel more natural with simple "if"s and some
> "goto"s to reach the bpf_link__disconnect() call below. But maybe this
> is just me.

I agree actually! I implemented it with goto first, but move to if-else 
to following the style I found in map.c. If you think goto is better, I 
will be glad to move to it.

> 
>> +
>> +               bpf_link__disconnect(link);
>> +               bpf_link__destroy(link);
>> +
> 
> Nit: We don't need this empty line.
> 

Got it!

>>          }
>>
>>          bpf_object__close(obj);
>> @@ -562,7 +620,7 @@ static int do_help(int argc, char **argv)
>>          fprintf(stderr,
>>                  "Usage: %1$s %2$s { show | list } [STRUCT_OPS_MAP]\n"
>>                  "       %1$s %2$s dump [STRUCT_OPS_MAP]\n"
>> -               "       %1$s %2$s register OBJ\n"
>> +               "       %1$s %2$s register OBJ [PATH]\n"
> 
> This is not enough to understand what PATH means here. I'd use
> something like "LINK_DIR", or preferably "LINK_PATH" if we let users
> specify the full path. And we need to update the
> bpftool-struct_ops.rst man page (under bpftool's Documentation/) to
> explain what this optional argument is for, can you please take care
> of this?

Sure!

> 
> We usually have to update the bash completion too, but it seems that
> it offers filenames multiple times already after "bpftool struct_ops
> register", which is not intentional but covers completion for the new
> argument.

I didn'know about bash completion before.
Good to know!

> 
>>                  "       %1$s %2$s unregister STRUCT_OPS_MAP\n"
>>                  "       %1$s %2$s help\n"
>>                  "\n"
>> --
>> 2.34.1
>>

      reply	other threads:[~2023-04-19  0:36 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-04-18 20:00 [PATCH bpf-next] bpftool: Register struct_ops with a link Kui-Feng Lee
2023-04-18 22:55 ` Quentin Monnet
2023-04-19  0:36   ` Kui-Feng Lee [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=a02b37d9-279a-00c1-351c-a4da23b54abf@gmail.com \
    --to=sinquersw@gmail.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=kernel-team@meta.com \
    --cc=kuifeng@meta.com \
    --cc=martin.lau@linux.dev \
    --cc=quentin@isovalent.com \
    --cc=song@kernel.org \
    --cc=thinker.li@gmail.com \
    --cc=yhs@meta.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox