Skip to content

Commit bf5182b

Browse files
committed
basic04: Text nits
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
1 parent 4a1373c commit bf5182b

1 file changed

Lines changed: 88 additions & 81 deletions

File tree

basic04-pinning-maps/README.org

Lines changed: 88 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,66 @@
11
# -*- fill-column: 76; -*-
2-
#+TITLE: Tutorial: Basic04
2+
#+TITLE: Tutorial: Basic04 - pinning of maps
33
#+OPTIONS: ^:nil
44

5-
In this lesson you will learn about reading BPF-maps from another "external"
5+
In this lesson you will learn about reading BPF maps from another "external"
66
program.
77

8-
In basic03 the [[file:../basic03-map-counter/xdp_load_and_stats.c][xdp_load_and_stats.c]] program were both doing BPF/XDP-loading
9-
and reading stats from the map. This was practical as the map
10-
file-descriptor was readily available. In this lesson this program have been
11-
split into two separate programs:
12-
- one focused on BPF/XDP-loading ([[file:xdp_loader.c]]) and
8+
In basic03 the [[file:../basic03-map-counter/xdp_load_and_stats.c][xdp_load_and_stats.c]] program was both loading the BPF program
9+
and reading the stats from the map. This was practical as the map
10+
file descriptor was readily available; however it is often limiting that a
11+
map can only be accessed from the same program that loads it.
12+
13+
In this lesson we will split the program into two separate programss:
14+
- one focused on BPF/XDP loading ([[file:xdp_loader.c]]) and
1315
- one focused on reading and printing stats ([[file:xdp_stats.c]]).
1416

1517
The basic quest revolves around how to share or obtain the UNIX
16-
file-descriptor to the BPF-map, that we want to read from. Access to a
17-
BPF_map still goes through the BPF-syscall, but the handle is a standard
18-
UNIX file-descriptor.
18+
file descriptor pointing to the BPF map from another program than the one
19+
that created the map.
1920

20-
* Overview of exercise :TOC:
21+
* Table of Contents :TOC:
2122
- [[#solutions-to-basic03-assignments][Solutions to basic03 assignments]]
22-
- [[#lessons][Lessons]]
23-
- [[#lesson1-bpf-syscall-wrappers][Lesson#1: bpf-syscall wrappers]]
24-
- [[#lesson2-mount-bpf-file-system][Lesson#2: mount BPF file-system]]
25-
- [[#lesson3-gotchas-with-pinned-maps][Lesson#3: gotchas with pinned maps]]
26-
- [[#lesson4-deleting-maps-on-xdp-reload][Lesson#4: Deleting maps on XDP-reload]]
23+
- [[#what-you-will-learn-in-this-lesson][What you will learn in this lesson]]
24+
- [[#bpf-syscall-wrappers][bpf syscall wrappers]]
25+
- [[#mounting-the-bpf-file-system][Mounting the BPF file system]]
26+
- [[#gotchas-with-pinned-maps][Gotchas with pinned maps]]
27+
- [[#deleting-maps-on-xdp-reload][Deleting maps on XDP reload]]
2728
- [[#assignments][Assignments]]
28-
- [[#assignment1-xdp_statsc-reload-map-file-descriptor][Assignment#1: (xdp_stats.c) reload map file-descriptor]]
29-
- [[#assignment2-xdp_loaderc-reuse-pinned-map][Assignment#2: (xdp_loader.c) reuse pinned map]]
29+
- [[#assignment-1-xdp_statsc-reload-map-file-descriptor][Assignment 1: (xdp_stats.c) reload map file-descriptor]]
30+
- [[#assignment-2-xdp_loaderc-reuse-pinned-map][Assignment 2: (xdp_loader.c) reuse pinned map]]
3031

3132
* Solutions to basic03 assignments
3233

3334
The assignments in [[file:../basic03-map-counter][basic03]] have been "solved" or implemented in this basic04
3435
lesson. Thus, this functions as the reference solution for basic03.
3536

36-
* Lessons
37+
* What you will learn in this lesson
3738

38-
** Lesson#1: bpf-syscall wrappers
39+
** bpf syscall wrappers
3940

40-
When splitting up the [[file:../basic03-map-counter/xdp_load_and_stats.c][xdp_load_and_stats.c]] program, into [[file:xdp_loader.c]]
41-
and [[file:xdp_stats.c]], notice that xdp_stats.c no-longer =#include
42-
<bpf/libbpf.h>=. This is because xdp_stats doesn't use any of the advanced
43-
libbpf "object" related functions, it only use the basis bpf-syscall
41+
When splitting up the [[file:../basic03-map-counter/xdp_load_and_stats.c][xdp_load_and_stats.c]] program into [[file:xdp_loader.c]]
42+
and [[file:xdp_stats.c]], notice that xdp_stats.c no longer includes
43+
=#<bpf/libbpf.h>=. This is because xdp_stats doesn't use any of the advanced
44+
libbpf "object" related functions, it only uses the basis bpf syscall
4445
wrappers, which libbpf also provides.
4546

46-
The bpf-syscall wrappers are provided by libbpf via =#include <bpf/bpf.h>=,
47-
which for this build-setup gets installed in =../libbpf/src/root/usr/include/bpf/bpf.h=
48-
(link to source [[https://github.com/libbpf/libbpf/blob/master/src/bpf.h][bpf.h]] in libbpf-github repo).
47+
The bpf syscall wrappers are provided by libbpf via the =#<bpf/bpf.h>=
48+
include file, which for this tutorial setup lives in
49+
=../libbpf/src/root/usr/include/bpf/bpf.h= (but see also the [[https://github.com/libbpf/libbpf/blob/master/src/bpf.h][source bpf.h in
50+
the libbpf github repository]]).
4951

50-
The point there is that libbpf keep the low-level bpf-syscall wrappers in
51-
separate files [[https://github.com/libbpf/libbpf/blob/master/src/bpf.h][bpf.h]] and [[https://github.com/libbpf/libbpf/blob/master/src/bpf.c][bpf.c]]. We could create a smaller binary by not
52-
linking with libbpf.a, but for ease of use, the proper library is used.
52+
The point here is that libbpf keeps the low-level bpf-syscall wrappers in
53+
separate files [[https://github.com/libbpf/libbpf/blob/master/src/bpf.h][bpf.h]] and [[https://github.com/libbpf/libbpf/blob/master/src/bpf.c][bpf.c]]. Thus, we could shrink the size of our binary
54+
by not linking with libbpf.a. However, for ease of use we just link
55+
everything with the full library in this tutorial.
5356

54-
** Lesson#2: mount BPF file-system
57+
** Mounting the BPF file system
5558

56-
Pinning BPF-map means creating files for-each map under a special mount
57-
point =/sys/fs/bpf/=. This mount point use a "BPF file-system" type. The
58-
pinning will fail of this is not mounted under =/sys/fs/bpf/=.
59+
The mechanism used for sharing BPF maps between programs is called
60+
/pinning/. What this means is that we create a file for each map under a
61+
special file system mounted at =/sys/fs/bpf/=. If this file system is not
62+
mounted, our attempts to pin BPF objects will fail, so we need to make sure
63+
it is mounted.
5964

6065
The needed mount command is:
6166
#+begin_example
@@ -67,33 +72,34 @@ mounted without noticing. As both iproute2 'ip' and our [[file:../testenv][teste
6772
automatically mount it to the default location under =/sys/fs/bpf/=.
6873
If not, use the above command to mount it.
6974

70-
** Lesson#3: gotchas with pinned maps
75+
** Gotchas with pinned maps
7176

7277
Pinning all maps in a =bpf_object= using libbpf is easily done with:
73-
=bpf_object__pin_maps(bpf_object, pin_dir)=.
74-
75-
To avoid filename collisions, when loading several XDP program on different
76-
interfaces, the maps are export/pinned under a sub-directory with the
77-
interface name, that was specified via =--dev=. The libbpf
78-
=bpf_object__pin_maps()= call even handle creating this sub-directory (via
79-
mkdir(3)).
80-
81-
Open [[file:xdp_loader.c]] and look at our function =pin_maps_in_bpf_object()=,
82-
and you will see that due to corner-case it is slightly more complicated.
83-
E.g. need to handle cleanup of previous XDP progs that not have cleaned up
84-
their maps, which we choose to do via =bpf_object__unpin_maps()=. If this is
85-
the first usage, then we should not try to "unpin maps" as that will fail.
86-
87-
We currently don't handle the corner case, where our BPF-prog get extended
88-
with a new-map, and then want to replace an existing BPF-prog that doesn't
89-
contain this new-map, which will result in =bpf_object__unpin_maps()= not
90-
finding the new-map to unlink, and then fails.
91-
92-
** Lesson#4: Deleting maps on XDP-reload
93-
94-
When reloading the XDP BPF-prog via our =xdp_loader=, then the existing
95-
pinned maps are not reused. This differs from iproute2 tool BPF-loader (=ip=
96-
and =tc= commands), which will reuse the existing pinned maps, rather than
78+
=bpf_object__pin_maps(bpf_object, pin_dir)=, which we use in =xdp_loader=.
79+
80+
To avoid filename collisions, we create a subdirectory named after the
81+
interface that we are loading the BPF program onto. The libbpf
82+
=bpf_object__pin_maps()= call even handles creating this subdirectory if it
83+
doesn't exist.
84+
85+
However, if you open [[file:xdp_loader.c]] and look at our function
86+
=pin_maps_in_bpf_object()=, you will see that due to corner cases things are
87+
slightly more complicated. E.g., we also need to handle cleanup of previous
88+
XDP programs that not have cleaned up their maps, which we choose to do via
89+
=bpf_object__unpin_maps()=. If this is the first usage, then we should not
90+
try to "unpin maps" as that will fail.
91+
92+
There is one corner case that we currently don't handle, namely the case
93+
where our BPF-prog get extended with a new map, and is loaded as a
94+
replacement for an existing BPF progam that doesn't contain this new map. In
95+
this case, =bpf_object__unpin_maps()= won't finding the new map to unlink,
96+
and therefore fail in its operation.
97+
98+
** Deleting maps on XDP reload
99+
100+
When reloading the XDP BPF program via our =xdp_loader=, the existing pinned
101+
maps are not reused. This differs from iproute2 tool BPF-loader (=ip= and
102+
=tc= commands), which will reuse the existing pinned maps, rather than
97103
creating new maps.
98104

99105
This is a design choice, mostly because libbpf doesn't have easy support for
@@ -103,15 +109,15 @@ applications it could be a problem that the counters reset to zero for the
103109
different stats tools. Even for our split =xdp_stats= program it is
104110
annoying, as you must remember to restart the =xdp_stats= tool, after
105111
reloading via =xdp_loader=, else it will be watching the wrong FD.
106-
(See [[#assignment1-xdp_statsc-reload-map-file-descriptor][Assignment#1]] for workaround)
112+
(See [[#assignment1-xdp_statsc-reload-map-file-descriptor][Assignment 1]] for workaround)
107113

108-
*** Lesson#4.1: libbpf reuse map
114+
*** Reusing maps with libbpf
109115

110-
The libbpf library can *reuse and replace* a map with an existing map
111-
file-descriptor, via the libbpf API call: =bpf_map__reuse_fd()=. But you
112-
cannot use =bpf_prog_load()= any-longer, instead you have to open-code it,
113-
as you need a step in-between =bpf_object__open()= and =bpf_object__load=.
114-
The basic steps needed looks like:
116+
The libbpf library can *reuse and replace* a map with an existing map file
117+
descriptor, via the libbpf API call: =bpf_map__reuse_fd()=. But you cannot
118+
use =bpf_prog_load()= for this; instead you have to code it yourself, as you
119+
need a step in-between =bpf_object__open()= and =bpf_object__load=. The
120+
basic steps needed looks like:
115121

116122
#+begin_src C
117123
int pinned_map_fd = bpf_obj_get("/sys/fs/bpf/veth0/xdp_stats_map");
@@ -121,29 +127,30 @@ The basic steps needed looks like:
121127
bpf_object__load(obj);
122128
#+end_src
123129

124-
(Hint: see [[#assignment2-xdp_loaderc-reuse-pinned-map][Assignment#2]])
130+
(Hint: see [[#assignment2-xdp_loaderc-reuse-pinned-map][Assignment 2]])
125131

126132
* Assignments
127133

128-
** Assignment#1: (xdp_stats.c) reload map file-descriptor
134+
** Assignment 1: (xdp_stats.c) reload map file-descriptor
129135

130-
As mentioned in Lesson#4, the =xdp_stats= tool will not detect if
131-
=xdp_loader= loads new maps and new BPF-prog, and will need to be restarted.
132-
This is annoying. The *assignment* is to reload the map file-descriptor
133-
dynamically, such that the =xdp_stats= program doesn't need to be restarted.
136+
As mentioned above, the =xdp_stats= tool will not detect if =xdp_loader=
137+
loads new maps and new BPF programs, and will need to be restarted. This is
138+
annoying. The *assignment* is to reload the map file descriptor dynamically,
139+
such that the =xdp_stats= program doesn't need to be restarted.
134140

135-
There are more than one solution. The naive solution is to reopen the pinned
136-
map file each time, but how do you detect that the file changed. If you
137-
don't detect this is a new map, then the stats diff between two measurements
138-
will be negative. Think about solutions were you remember/use the ID number
139-
to detect changes, either via the map ID or XDP BPF-prog ID.
141+
There are several solutions to this. The naive solution is to reopen the
142+
pinned map file each time; but how do you detect that the file changed? If
143+
you don't detect when dealing with a new map, then the stats diff between
144+
two measurements will be negative. Think about solutions were you
145+
remember/use the ID number to detect changes, either via the map ID or XDP
146+
BPF program ID.
140147

141-
** Assignment#2: (xdp_loader.c) reuse pinned map
148+
** Assignment 2: (xdp_loader.c) reuse pinned map
142149

143-
As mentioned in Lesson#4.1, libbpf can reuse and replace a map with an
144-
existing map, it just requires open coding =bpf_prog_load()= (or
150+
As mentioned above, libbpf can reuse and replace a map with an existing map,
151+
it just requires writing your own =bpf_prog_load()= (or
145152
=bpf_prog_load_xattr=).
146153

147-
The *assignment* is to in [[file:xdp_loader.c][xdp_loader]] check if there is already a pinned
154+
The *assignment* is to check in [[file:xdp_loader.c][xdp_loader]] if there already is a pinned
148155
version of the map "xdp_stats_map" and use libbpf =bpf_map__reuse_fd()= API
149156
to reuse it, instead of creating a new map.

0 commit comments

Comments
 (0)