aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWang Nan <wangnan0@huawei.com>2015-11-16 07:10:09 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2015-11-18 15:51:03 -0500
commitb580563e38487d9db8e94080149644da71c533c1 (patch)
tree7c4f1b69a9b99706c1aaec7c818cb09221673b03
parent7d85c434214ea0b3416f7a62f76a0785b00d8797 (diff)
bpf tools: Load a program with different instances using preprocessor
This patch is a preparation for BPF prologue support which allows generating a series of BPF bytecode for fetching kernel data before calling program code. With the newly introduced multiple instances support, perf is able to create different prologues for different kprobe points. Before this patch, a bpf_program can be loaded into kernel only once, and get the only resulting fd. What this patch does is to allow creating and loading different variants of one bpf_program, then fetching their fds. Here we describe the basic idea in this patch. The detailed description of the newly introduced APIs can be found in comments in the patch body. The key of this patch is the new mechanism in bpf_program__load(). Instead of loading BPF program into kernel directly, it calls a 'pre-processor' to generate program instances which would be finally loaded into the kernel based on the original code. To enable the generation of multiple instances, libbpf passes an index to the pre-processor so it know which instance is being loaded. Pre-processor should be called from libbpf's user (perf) using bpf_program__set_prep(). The number of instances and the relationship between indices and the target instance should be clear when calling bpf_program__set_prep(). To retrieve a fd for a specific instance of a program, bpf_program__nth_fd() is introduced. It returns the resulting fd according to index. Signed-off-by: He Kuang <hekuang@huawei.com> Cc: Alexei Starovoitov <ast@kernel.org> Cc: He Kuang <hekuang@huawei.com> Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Cc: Zefan Li <lizefan@huawei.com> Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1447675815-166222-8-git-send-email-wangnan0@huawei.com Signed-off-by: Wang Nan <wangnan0@huawei.com> [ Enclosed multi-line if/else blocks with {}, (*func_ptr)() -> func_ptr() ] Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r--tools/lib/bpf/libbpf.c146
-rw-r--r--tools/lib/bpf/libbpf.h64
2 files changed, 201 insertions, 9 deletions
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index e176bad19bcb..e3f4c3379f14 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -152,7 +152,11 @@ struct bpf_program {
152 } *reloc_desc; 152 } *reloc_desc;
153 int nr_reloc; 153 int nr_reloc;
154 154
155 int fd; 155 struct {
156 int nr;
157 int *fds;
158 } instances;
159 bpf_program_prep_t preprocessor;
156 160
157 struct bpf_object *obj; 161 struct bpf_object *obj;
158 void *priv; 162 void *priv;
@@ -206,10 +210,25 @@ struct bpf_object {
206 210
207static void bpf_program__unload(struct bpf_program *prog) 211static void bpf_program__unload(struct bpf_program *prog)
208{ 212{
213 int i;
214
209 if (!prog) 215 if (!prog)
210 return; 216 return;
211 217
212 zclose(prog->fd); 218 /*
219 * If the object is opened but the program was never loaded,
220 * it is possible that prog->instances.nr == -1.
221 */
222 if (prog->instances.nr > 0) {
223 for (i = 0; i < prog->instances.nr; i++)
224 zclose(prog->instances.fds[i]);
225 } else if (prog->instances.nr != -1) {
226 pr_warning("Internal error: instances.nr is %d\n",
227 prog->instances.nr);
228 }
229
230 prog->instances.nr = -1;
231 zfree(&prog->instances.fds);
213} 232}
214 233
215static void bpf_program__exit(struct bpf_program *prog) 234static void bpf_program__exit(struct bpf_program *prog)
@@ -260,7 +279,8 @@ bpf_program__init(void *data, size_t size, char *name, int idx,
260 memcpy(prog->insns, data, 279 memcpy(prog->insns, data,
261 prog->insns_cnt * sizeof(struct bpf_insn)); 280 prog->insns_cnt * sizeof(struct bpf_insn));
262 prog->idx = idx; 281 prog->idx = idx;
263 prog->fd = -1; 282 prog->instances.fds = NULL;
283 prog->instances.nr = -1;
264 284
265 return 0; 285 return 0;
266errout: 286errout:
@@ -860,13 +880,73 @@ static int
860bpf_program__load(struct bpf_program *prog, 880bpf_program__load(struct bpf_program *prog,
861 char *license, u32 kern_version) 881 char *license, u32 kern_version)
862{ 882{
863 int err, fd; 883 int err = 0, fd, i;
864 884
865 err = load_program(prog->insns, prog->insns_cnt, 885 if (prog->instances.nr < 0 || !prog->instances.fds) {
866 license, kern_version, &fd); 886 if (prog->preprocessor) {
867 if (!err) 887 pr_warning("Internal error: can't load program '%s'\n",
868 prog->fd = fd; 888 prog->section_name);
889 return -LIBBPF_ERRNO__INTERNAL;
890 }
869 891
892 prog->instances.fds = malloc(sizeof(int));
893 if (!prog->instances.fds) {
894 pr_warning("Not enough memory for BPF fds\n");
895 return -ENOMEM;
896 }
897 prog->instances.nr = 1;
898 prog->instances.fds[0] = -1;
899 }
900
901 if (!prog->preprocessor) {
902 if (prog->instances.nr != 1) {
903 pr_warning("Program '%s' is inconsistent: nr(%d) != 1\n",
904 prog->section_name, prog->instances.nr);
905 }
906 err = load_program(prog->insns, prog->insns_cnt,
907 license, kern_version, &fd);
908 if (!err)
909 prog->instances.fds[0] = fd;
910 goto out;
911 }
912
913 for (i = 0; i < prog->instances.nr; i++) {
914 struct bpf_prog_prep_result result;
915 bpf_program_prep_t preprocessor = prog->preprocessor;
916
917 bzero(&result, sizeof(result));
918 err = preprocessor(prog, i, prog->insns,
919 prog->insns_cnt, &result);
920 if (err) {
921 pr_warning("Preprocessing the %dth instance of program '%s' failed\n",
922 i, prog->section_name);
923 goto out;
924 }
925
926 if (!result.new_insn_ptr || !result.new_insn_cnt) {
927 pr_debug("Skip loading the %dth instance of program '%s'\n",
928 i, prog->section_name);
929 prog->instances.fds[i] = -1;
930 if (result.pfd)
931 *result.pfd = -1;
932 continue;
933 }
934
935 err = load_program(result.new_insn_ptr,
936 result.new_insn_cnt,
937 license, kern_version, &fd);
938
939 if (err) {
940 pr_warning("Loading the %dth instance of program '%s' failed\n",
941 i, prog->section_name);
942 goto out;
943 }
944
945 if (result.pfd)
946 *result.pfd = fd;
947 prog->instances.fds[i] = fd;
948 }
949out:
870 if (err) 950 if (err)
871 pr_warning("failed to load program '%s'\n", 951 pr_warning("failed to load program '%s'\n",
872 prog->section_name); 952 prog->section_name);
@@ -1121,5 +1201,53 @@ const char *bpf_program__title(struct bpf_program *prog, bool needs_copy)
1121 1201
1122int bpf_program__fd(struct bpf_program *prog) 1202int bpf_program__fd(struct bpf_program *prog)
1123{ 1203{
1124 return prog->fd; 1204 return bpf_program__nth_fd(prog, 0);
1205}
1206
1207int bpf_program__set_prep(struct bpf_program *prog, int nr_instances,
1208 bpf_program_prep_t prep)
1209{
1210 int *instances_fds;
1211
1212 if (nr_instances <= 0 || !prep)
1213 return -EINVAL;
1214
1215 if (prog->instances.nr > 0 || prog->instances.fds) {
1216 pr_warning("Can't set pre-processor after loading\n");
1217 return -EINVAL;
1218 }
1219
1220 instances_fds = malloc(sizeof(int) * nr_instances);
1221 if (!instances_fds) {
1222 pr_warning("alloc memory failed for fds\n");
1223 return -ENOMEM;
1224 }
1225
1226 /* fill all fd with -1 */
1227 memset(instances_fds, -1, sizeof(int) * nr_instances);
1228
1229 prog->instances.nr = nr_instances;
1230 prog->instances.fds = instances_fds;
1231 prog->preprocessor = prep;
1232 return 0;
1233}
1234
1235int bpf_program__nth_fd(struct bpf_program *prog, int n)
1236{
1237 int fd;
1238
1239 if (n >= prog->instances.nr || n < 0) {
1240 pr_warning("Can't get the %dth fd from program %s: only %d instances\n",
1241 n, prog->section_name, prog->instances.nr);
1242 return -EINVAL;
1243 }
1244
1245 fd = prog->instances.fds[n];
1246 if (fd < 0) {
1247 pr_warning("%dth instance of program '%s' is invalid\n",
1248 n, prog->section_name);
1249 return -ENOENT;
1250 }
1251
1252 return fd;
1125} 1253}
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index c9a9aef2806c..949df4b346cf 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -88,6 +88,70 @@ const char *bpf_program__title(struct bpf_program *prog, bool needs_copy);
88 88
89int bpf_program__fd(struct bpf_program *prog); 89int bpf_program__fd(struct bpf_program *prog);
90 90
91struct bpf_insn;
92
93/*
94 * Libbpf allows callers to adjust BPF programs before being loaded
95 * into kernel. One program in an object file can be transform into
96 * multiple variants to be attached to different code.
97 *
98 * bpf_program_prep_t, bpf_program__set_prep and bpf_program__nth_fd
99 * are APIs for this propose.
100 *
101 * - bpf_program_prep_t:
102 * It defines 'preprocessor', which is a caller defined function
103 * passed to libbpf through bpf_program__set_prep(), and will be
104 * called before program is loaded. The processor should adjust
105 * the program one time for each instances according to the number
106 * passed to it.
107 *
108 * - bpf_program__set_prep:
109 * Attachs a preprocessor to a BPF program. The number of instances
110 * whould be created is also passed through this function.
111 *
112 * - bpf_program__nth_fd:
113 * After the program is loaded, get resuling fds from bpf program for
114 * each instances.
115 *
116 * If bpf_program__set_prep() is not used, the program whould be loaded
117 * without adjustment during bpf_object__load(). The program has only
118 * one instance. In this case bpf_program__fd(prog) is equal to
119 * bpf_program__nth_fd(prog, 0).
120 */
121
122struct bpf_prog_prep_result {
123 /*
124 * If not NULL, load new instruction array.
125 * If set to NULL, don't load this instance.
126 */
127 struct bpf_insn *new_insn_ptr;
128 int new_insn_cnt;
129
130 /* If not NULL, result fd is set to it */
131 int *pfd;
132};
133
134/*
135 * Parameters of bpf_program_prep_t:
136 * - prog: The bpf_program being loaded.
137 * - n: Index of instance being generated.
138 * - insns: BPF instructions array.
139 * - insns_cnt:Number of instructions in insns.
140 * - res: Output parameter, result of transformation.
141 *
142 * Return value:
143 * - Zero: pre-processing success.
144 * - Non-zero: pre-processing, stop loading.
145 */
146typedef int (*bpf_program_prep_t)(struct bpf_program *prog, int n,
147 struct bpf_insn *insns, int insns_cnt,
148 struct bpf_prog_prep_result *res);
149
150int bpf_program__set_prep(struct bpf_program *prog, int nr_instance,
151 bpf_program_prep_t prep);
152
153int bpf_program__nth_fd(struct bpf_program *prog, int n);
154
91/* 155/*
92 * We don't need __attribute__((packed)) now since it is 156 * We don't need __attribute__((packed)) now since it is
93 * unnecessary for 'bpf_map_def' because they are all aligned. 157 * unnecessary for 'bpf_map_def' because they are all aligned.