]> git.ipfire.org Git - thirdparty/iproute2.git/commitdiff
{f,m}_bpf: make tail calls working
authorDaniel Borkmann <daniel@iogearbox.net>
Thu, 26 Nov 2015 14:38:42 +0000 (15:38 +0100)
committerStephen Hemminger <shemming@brocade.com>
Sun, 29 Nov 2015 19:55:16 +0000 (11:55 -0800)
Now that we have the possibility of sharing maps, it's time we get the
ELF loader fully working with regards to tail calls. Since program array
maps are pinned, we can keep them finally alive. I've noticed two bugs
that are being fixed in bpf_fill_prog_arrays() with this patch. Example
code comes as follow-up.

Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Alexei Starovoitov <ast@kernel.org>
tc/tc_bpf.c

index bc7bc9ffae544b4101d1684a606b723791c91be8..c3adc23c0eb3eb139c6f11c5e98e23e57243ca49 100644 (file)
@@ -1139,11 +1139,22 @@ static int bpf_fetch_prog_sec(struct bpf_elf_ctx *ctx, const char *section)
        return ret;
 }
 
+static int bpf_find_map_by_id(struct bpf_elf_ctx *ctx, uint32_t id)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(ctx->map_fds); i++)
+               if (ctx->map_fds[i] && ctx->maps[i].id == id &&
+                   ctx->maps[i].type == BPF_MAP_TYPE_PROG_ARRAY)
+                       return i;
+       return -1;
+}
+
 static int bpf_fill_prog_arrays(struct bpf_elf_ctx *ctx)
 {
        struct bpf_elf_sec_data data;
        uint32_t map_id, key_id;
-       int fd, i, ret;
+       int fd, i, ret, idx;
 
        for (i = 1; i < ctx->elf_hdr.e_shnum; i++) {
                if (ctx->sec_done[i])
@@ -1153,20 +1164,20 @@ static int bpf_fill_prog_arrays(struct bpf_elf_ctx *ctx)
                if (ret < 0)
                        continue;
 
-               ret = sscanf(data.sec_name, "%u/%u", &map_id, &key_id);
-               if (ret != 2 || map_id >= ARRAY_SIZE(ctx->map_fds) ||
-                   !ctx->map_fds[map_id])
+               ret = sscanf(data.sec_name, "%i/%i", &map_id, &key_id);
+               if (ret != 2)
                        continue;
-               if (ctx->maps[map_id].type != BPF_MAP_TYPE_PROG_ARRAY ||
-                   ctx->maps[map_id].max_elem <= key_id)
+
+               idx = bpf_find_map_by_id(ctx, map_id);
+               if (idx < 0)
                        continue;
 
                fd = bpf_fetch_prog_sec(ctx, data.sec_name);
                if (fd < 0)
                        return -EIO;
 
-               ret = bpf_map_update(ctx->map_fds[map_id], &key_id,
-                                    &fd, BPF_NOEXIST);
+               ret = bpf_map_update(ctx->map_fds[idx], &key_id,
+                                    &fd, BPF_ANY);
                if (ret < 0)
                        return -ENOENT;