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
>>
prev parent 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