Re: [PATCH v2 bpf-next 2/6] libbpf: rename static variables during linking

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Apr 27, 2021 at 9:55 PM Alexei Starovoitov
<alexei.starovoitov@xxxxxxxxx> wrote:
>
> On Tue, Apr 27, 2021 at 02:27:26PM -0700, Andrii Nakryiko wrote:
> >
> > It's static for the purposes of BPF code, so no naming collisions in
> > BPF code and no intentional or unintentional accesses beyond a single
> > .bpf.c file. That's what we want. We don't want BPF library writers to
> > worry about names colliding with some other library or user code.
>
> Who is 'we' ?

Me and Yonghong, at least. Putting myself into BPF library
writer/maintainer shoes (which I have plans for), I'd say any BPF
library writer as well.

> The skel gen by accident (probably) extended 'static' visibility
> from .bpf.c into user space .c.
> My point that it was a bad accident and I only realized it now.
> The naming conflict in linking exposed this problem.

There is no linking naming conflict. We are talking about BPF skeleton
(and not just trough BPF skeleton, potentially) access to
global/static variables (and static maps as well).

> The selftests are relying on this 'feature' now.
> Potentially some user could have used it as well.
> Do I want to break that use case? Not really, but that's still an option.
>
> I agree that library writers shouldn't worry about
> naming conflicts in *.bpf.c space.
> If they're exporting a static from .bpf.c into .c I think it's ok
> to make them do extra steps.
> Such 'static in .bpf.c' but 'extern into .c' should somehow work
> without requiring people rename their vars.
> I mean that the user of the library shouldn't need to do renames,
> but the library author shouldn't rely on 'all statics are visible
> in skel'.
> In that sense what I proposed earlier to allow linking, but fail
> skel gen is a step towards such development process.

This is not just variables in BPF skeleton. Static maps, even without
skeleton, will have the same problem. All maps are accessible through
bpf_object__find_map_by_name().

> Something like attr(alias()) or some other way hopefully can
> help library authors create such library where static+something
> is visible to library's skeleton, but users of the library
> don't see its statics.
> I think the static handling logic needs to be discussed
> with your sub-skeleton idea.
> If I got it correctly there will be something like this:
> - lib.bpf.c compiled into lib.bpf.o

small adjustment here, it might be lib1.bpf.c + lib2.bpf.c + and so on
-> (through intermediate .bpf.o) -> final lib.bpf.o

> - main.bpf.c that links with lib.bpf.o
>   It's all in *.bpf.c space and static has normal C scope.
>   The static vars and maps in lib.bpf.c are not
>   visible in main.bpf.c
> - there is lib.c that works with lib.bpf.c via lib.skel.h
>   that was generated out of lib.bpf.o
> - main.c that links with lib.o
>   main.c works with main.bpf.c via main.skel.h
>
> I think lib.skel.h you were calling sub-skeleton.
> pls correct me.

no, all correct

> Since main.bpf.o was linked with lib.bpf.o
> the main.skel.h will include the things from it.
> But main.c shouldn't be accessing them, since that's the
> point of the library.
>
> At the same time lib.bpf.c and main.bpf.c could have been
> just two files of the same project. If lib.bpf.o isn't a library
> then main.skel.h should access it just fine.
> So what is bpf library? How should it be defined?

In very abstract terms, it's a piece of BPF application (maps,
programs, variables) and corresponding user-space (initialization,
teardown, runtime operations) that is not a complete application and
is supposed to be linked into (potentially) someone else's
application.

You are right that right now main.skel.h will have visibility into
library's maps, variables, programs. Not great, but didn't feel that
horrible either. After all, user of BPF library has to follow some API
expectations regardless, like calling some init and teardown APIs and
otherwise setting up BPF library at runtime.

I'm not sure what alternative there is. User-space C ecosystem doesn't
differentiate between linking with some my_prog.o vs libbpf.a. So
static libraries are not special in any way and if they have
conflicting global variable names, it will cause linker error. This is
where static variables are important.

Shared libraries are a bit more formally recognized, but that's a very
different thing (that's where STV_HIDDEN plays the role in user-space
linking).

So I feel like you are getting at something, but don't quite spell it
out. Please elaborate.

> And what is the scope and visibility of its vars/maps/funcs?
> Unlike traditional C the bpf has two worlds .bpf.c and .c
> So traditional 'static' doesn't cover these cases.

Right, static is static only within the BPF world.

>
> > And
> > from the perspective of a user of two BPF libraries that have
> > colliding names it's not great to have to somehow rename those
> > libraries' internal variables through source code changes.
>
> It's not great. That's why I'm trying to provoke a discussion
> of more options and pick the best considering all + and -.
>

We are having this discussion, even if it produces disappointing
results. I don't know better options short of disabling static
variables. I've thought a lot about it.

What's worse, to bpftool, generating BPF skeleton for .bpf.o straight
from Clang or to statically-linked .bpf.o is indistinguishable, so
it's not even simple to just say "let's not generate static variables
into BPF skeleton". But there are also static maps with similar issues
and non-skeleton-based APIs to access them by name
(bpf_object__find_map_by_name()). There we definitely can't just keep
saying that static maps are not supported. I think we both agreed
static maps would be good to have, but no one will die if we drop
them.

> >
> > Omitting static variables from skeleton is a regression and will
> > surprise existing users, we already went over this with you and
> > Yonghong in previous emails.
>
> Do I want to suffer this regression? No, but it could be the only option.
>
> > Beyond that, it's not clear what exactly you are proposing.
>
> To discuss all options as a whole and hopefully you and others
> can come up with more than what I proposed.
>
> > For
> > alias() seems like another variable with that "external_name" has to
> > be already defined and you can't initialize var, it has to be just a
> > declaration. And BTF doesn't capture attributes right now as well. And
> > overall it sounds like an overly complicated approach both for users
> > and for libbpf.
>
> yes. supporting alias() would mean more work in clang, libbpf and
> maybe new bits in BTF.
>
> > As for the extra SEC() annotation. It's both not supported by libbpf
> > right now, and it's not exactly clear how it helps with name conflicts
> > (see example above with two libraries colliding). In that regard a
> > prefix and ability to override it by user gives them an opportunity to
> > resolve such naming conflicts. I know it's kind of ugly, but name
> > overrides should hopefully be rarely needed.
>
> Yes. it's not supported today. All I'm saying it's one of the options.
>
> > What can I do to unblock BPF static linker work, though?
>
> I believe that the way bpf toolchain interprets static is
> a critical long term decision that shouldn't be done lightly.
> There is no rush to define it quickly as an automatic prefix of filename
> to all statics only because it's trivial to implement and sort-of works.
> It's not something we can undo later. Today there are no libraries
> and static definition of maps doesn't really work.
> So the only regression (if we decide to change) would be the way skeleton
> emits statics.
>
> > I don't think we'll find an ideal solution that will satisfy everyone.
>
> I think we didn't even start looking for that solution.
> At least I'm only starting to grasp the complexity of the problem.

I did and didn't find anything satisfactory. But I think we are coming
at this from two different angles, which is why we can't agree on
anything. So just a reminder, static is about two properties:
    1) access protection
    2) naming collisions.

I'm trying to let name collisions on BPF side happen and be allowed
*while* also allowing access to those same name-collisioned entities
(maps and vars, both) from user-space in some non-random fashion. That
inevitably requires some compromises/conventions on the user-space
side. Such an approach preserves both 1) and 2).

You are trying to enforce unique names (or at least aliases) for
static variables, if I understand correctly, which preserves 1) at the
expense of 2). It seems to be a similar idea with custom SEC(), though
you ignored my request to elaborate on how you see that used, so I'm
guessing here a bit.

But I think we can get just 1) with global variables with custom
visibilities. E.g., just marking map/variable as __hidden would
disallow extern'ing it from other files. That's obviously limiting for
extern'ing within the library, so we can keep digging deeper and
define __internal (STV_INTERNAL) that would be "upgraded" to
STV_HIDDEN after the initial linking pass. So you'd compile your BPF
library with __internal, but your lib.bpf.o will have those global
variables as STV_HIDDEN and thus inaccessible from other libraries and
BPF app itself.

So if we are ok breaking existing static variable users, then just
dropping statics from BPF skeleton and supporting extra __hidden and
__internal semantics for variables and maps would bypass these issues.
I wanted statics mostly for property 2), but if I can't get it, then
I'd drop statics from skeletons altogether.

If I could drop statics for skeletons that were statically linked,
that wouldn't be a regression. It's impossible to do right now, but we
can also add a new SHT_NOTE section, which we can use to detect
statically linked vs Clang-generated .bpf.o. Certainly more ELF
fussing around than I'd like, but not the end of the world either.

Thoughts? Did that summarize the issue well enough?



[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux