From patchwork Wed Nov 7 19:35:52 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stanislav Fomichev X-Patchwork-Id: 10672939 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 93BFC15E9 for ; Wed, 7 Nov 2018 19:36:05 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 83D3F2B870 for ; Wed, 7 Nov 2018 19:36:05 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 77D3D2CE9A; Wed, 7 Nov 2018 19:36:05 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.5 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI, USER_IN_DEF_DKIM_WL autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 39ABC2B870 for ; Wed, 7 Nov 2018 19:36:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1725724AbeKHFHt (ORCPT ); Thu, 8 Nov 2018 00:07:49 -0500 Received: from mail-qk1-f201.google.com ([209.85.222.201]:38778 "EHLO mail-qk1-f201.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726782AbeKHFHt (ORCPT ); Thu, 8 Nov 2018 00:07:49 -0500 Received: by mail-qk1-f201.google.com with SMTP id l7-v6so32798539qkd.5 for ; Wed, 07 Nov 2018 11:36:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=syr0nwezev7C7HpqdBvryVygj/JchKShhqEvUajIL/A=; b=hhVuaIh0nZleqV7aHqiTAaEaAC3yjffOpx8W3Q0ufpgZUSa4r8hheKAGos50W4IoxK sjM/cgoeEvvU/Eb9m7HtAkHMBeaiOxTFDvY948+y472ZZKQ5dGe8gybLarQekU2/ALyl A8TferDjcbCuKMlWE469zAb+HgiZw2Rc22q5cnBjgnXzm6+dmsXmqru/N94zluHUmjZ1 WlkAfKbV1KV74q4VoMs2FQybr0yhvJgg7a1B8caveAQSDcYnzSnzuX8vf65/k0lDRpJw 87+ea+U/7++obeykh4XO+w0dgNC+lTMmHZQc6zZHRi/feGUtgxqeSChTmRCn4jS/wh9l JBXw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=syr0nwezev7C7HpqdBvryVygj/JchKShhqEvUajIL/A=; b=BBSbI8jHAR39WXMY1f1I6VcEkheC8juwwjV3m+kWTPlsQNiWrkTtVZmJAPh7kOeMsq mQ/RXUFdHx1ZUnTxpSB9g6oq9PaKGT1wwklXV36t5KsXFrBgQ2GHrdjFncHdVMqXIt/0 nkDy583nBxbzml8fVI/QDAWs/xTAeI3d5+HEwxp3OCatLmIgh+SOu+2iioQkqEKQGFIP NCuldCzcfShKSS6+NyKK+FIFlkwW1Y7e0Zsy7dlU9HqHAn8fityB8mYiRd6xgT9ELp90 XsBuWp1wHy3yxd0mHZJq9LHh5YoDw8X4m10dDMKRtkweoebFgVcxCpuFWWvkoUfc3t+I UKEQ== X-Gm-Message-State: AGRZ1gIBicmDdrJguQBmehgWmCgSx6ymA976cdkHzwxzYN1mYnxbC67e CD2Dtffd2IesZwwYJgYXZOpvGVk= X-Google-Smtp-Source: AJdET5cd6kTKT6d7M7m7KQQqp35YCbdvMArLu+668GnBkk3mWhuMh0KkfVStES7jiK88sbohelhgCEE= X-Received: by 2002:ac8:292a:: with SMTP id y39mr979459qty.4.1541619361737; Wed, 07 Nov 2018 11:36:01 -0800 (PST) Date: Wed, 7 Nov 2018 11:35:52 -0800 In-Reply-To: <20181107193552.77894-1-sdf@google.com> Message-Id: <20181107193552.77894-3-sdf@google.com> Mime-Version: 1.0 References: <20181107193552.77894-1-sdf@google.com> X-Mailer: git-send-email 2.19.1.930.g4563a0d9d0-goog Subject: [PATCH bpf-next 2/2] bpftool: support loading flow dissector From: Stanislav Fomichev To: netdev@vger.kernel.org, linux-kselftest@vger.kernel.org, ast@kernel.org, daniel@iogearbox.net, shuah@kernel.org Cc: jakub.kicinski@netronome.com, quentin.monnet@netronome.com, guro@fb.com, jiong.wang@netronome.com, sdf@google.com, bhole_prashant_q7@lab.ntt.co.jp, john.fastabend@gmail.com, jbenc@redhat.com, treeze.taeung@gmail.com, yhs@fb.com, osk@fb.com, sandipan@linux.vnet.ibm.com Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This commit adds support for loading/attaching/detaching flow dissector program. The structure of the flow dissector program is assumed to be the same as in the selftests: * flow_dissector section with the main entry point * a bunch of tail call progs * a jmp_table map that is populated with the tail call progs When `bpftool load` is called with a flow_dissector prog (i.e. when the first section is flow_dissector of 'type flow_dissector' argument is passed), we load and pin all the programs and build the jump table. The last argument of `bpftool attach` is made optional for this use case. Example: bpftool prog load tools/testing/selftests/bpf/bpf_flow.o \ /sys/fs/bpf/flow type flow_dissector bpftool prog attach pinned /sys/fs/bpf/flow/flow_dissector/0 flow_dissector Tested by using the above two lines to load the prog in the test_flow_dissector.sh selftest. Signed-off-by: Stanislav Fomichev --- .../bpftool/Documentation/bpftool-prog.rst | 16 ++- tools/bpf/bpftool/common.c | 32 +++-- tools/bpf/bpftool/main.h | 1 + tools/bpf/bpftool/prog.c | 135 +++++++++++++++--- 4 files changed, 141 insertions(+), 43 deletions(-) diff --git a/tools/bpf/bpftool/Documentation/bpftool-prog.rst b/tools/bpf/bpftool/Documentation/bpftool-prog.rst index ac4e904b10fb..3caa9153435b 100644 --- a/tools/bpf/bpftool/Documentation/bpftool-prog.rst +++ b/tools/bpf/bpftool/Documentation/bpftool-prog.rst @@ -25,8 +25,8 @@ MAP COMMANDS | **bpftool** **prog dump jited** *PROG* [{**file** *FILE* | **opcodes**}] | **bpftool** **prog pin** *PROG* *FILE* | **bpftool** **prog load** *OBJ* *FILE* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*] -| **bpftool** **prog attach** *PROG* *ATTACH_TYPE* *MAP* -| **bpftool** **prog detach** *PROG* *ATTACH_TYPE* *MAP* +| **bpftool** **prog attach** *PROG* *ATTACH_TYPE* [*MAP*] +| **bpftool** **prog detach** *PROG* *ATTACH_TYPE* [*MAP*] | **bpftool** **prog help** | | *MAP* := { **id** *MAP_ID* | **pinned** *FILE* } @@ -39,7 +39,9 @@ MAP COMMANDS | **cgroup/bind4** | **cgroup/bind6** | **cgroup/post_bind4** | **cgroup/post_bind6** | | **cgroup/connect4** | **cgroup/connect6** | **cgroup/sendmsg4** | **cgroup/sendmsg6** | } -| *ATTACH_TYPE* := { **msg_verdict** | **skb_verdict** | **skb_parse** } +| *ATTACH_TYPE* := { +| | **msg_verdict** | **skb_verdict** | **skb_parse** | **flow_dissector** +| } DESCRIPTION @@ -97,13 +99,13 @@ DESCRIPTION contain a dot character ('.'), which is reserved for future extensions of *bpffs*. - **bpftool prog attach** *PROG* *ATTACH_TYPE* *MAP* + **bpftool prog attach** *PROG* *ATTACH_TYPE* [*MAP*] Attach bpf program *PROG* (with type specified by *ATTACH_TYPE*) - to the map *MAP*. + to the optional map *MAP*. - **bpftool prog detach** *PROG* *ATTACH_TYPE* *MAP* + **bpftool prog detach** *PROG* *ATTACH_TYPE* [*MAP*] Detach bpf program *PROG* (with type specified by *ATTACH_TYPE*) - from the map *MAP*. + from the optional map *MAP*. **bpftool prog help** Print short help message. diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c index 25af85304ebe..963881142dfb 100644 --- a/tools/bpf/bpftool/common.c +++ b/tools/bpf/bpftool/common.c @@ -169,34 +169,24 @@ int open_obj_pinned_any(char *path, enum bpf_obj_type exp_type) return fd; } -int do_pin_fd(int fd, const char *name) +int mount_bpffs_for_pin(const char *name) { char err_str[ERR_MAX_LEN]; char *file; char *dir; int err = 0; - err = bpf_obj_pin(fd, name); - if (!err) - goto out; - file = malloc(strlen(name) + 1); strcpy(file, name); dir = dirname(file); - if (errno != EPERM || is_bpffs(dir)) { - p_err("can't pin the object (%s): %s", name, strerror(errno)); + if (is_bpffs(dir)) { + /* nothing to do if already mounted */ goto out_free; } - /* Attempt to mount bpffs, then retry pinning. */ err = mnt_bpffs(dir, err_str, ERR_MAX_LEN); - if (!err) { - err = bpf_obj_pin(fd, name); - if (err) - p_err("can't pin the object (%s): %s", name, - strerror(errno)); - } else { + if (err) { err_str[ERR_MAX_LEN - 1] = '\0'; p_err("can't mount BPF file system to pin the object (%s): %s", name, err_str); @@ -204,10 +194,22 @@ int do_pin_fd(int fd, const char *name) out_free: free(file); -out: return err; } +int do_pin_fd(int fd, const char *name) +{ + int err = mount_bpffs_for_pin(name); + + if (err) { + p_err("can't mount bpffs for pin %s: %s", + name, strerror(errno)); + return err; + } + + return bpf_obj_pin(fd, name); +} + int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(__u32)) { unsigned int id; diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h index 28322ace2856..1383824c9baf 100644 --- a/tools/bpf/bpftool/main.h +++ b/tools/bpf/bpftool/main.h @@ -129,6 +129,7 @@ const char *get_fd_type_name(enum bpf_obj_type type); char *get_fdinfo(int fd, const char *key); int open_obj_pinned(char *path); int open_obj_pinned_any(char *path, enum bpf_obj_type exp_type); +int mount_bpffs_for_pin(const char *name); int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(__u32)); int do_pin_fd(int fd, const char *name); diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c index 5302ee282409..f3a07ec3a444 100644 --- a/tools/bpf/bpftool/prog.c +++ b/tools/bpf/bpftool/prog.c @@ -81,6 +81,7 @@ static const char * const attach_type_strings[] = { [BPF_SK_SKB_STREAM_PARSER] = "stream_parser", [BPF_SK_SKB_STREAM_VERDICT] = "stream_verdict", [BPF_SK_MSG_VERDICT] = "msg_verdict", + [BPF_FLOW_DISSECTOR] = "flow_dissector", [__MAX_BPF_ATTACH_TYPE] = NULL, }; @@ -724,9 +725,10 @@ int map_replace_compar(const void *p1, const void *p2) static int do_attach(int argc, char **argv) { enum bpf_attach_type attach_type; - int err, mapfd, progfd; + int err, progfd; + int mapfd = 0; - if (!REQ_ARGS(5)) { + if (!REQ_ARGS(3)) { p_err("too few parameters for map attach"); return -EINVAL; } @@ -741,10 +743,11 @@ static int do_attach(int argc, char **argv) return -EINVAL; } NEXT_ARG(); - - mapfd = map_parse_fd(&argc, &argv); - if (mapfd < 0) - return mapfd; + if (argc > 0) { + mapfd = map_parse_fd(&argc, &argv); + if (mapfd < 0) + return mapfd; + } err = bpf_prog_attach(progfd, mapfd, attach_type, 0); if (err) { @@ -760,9 +763,10 @@ static int do_attach(int argc, char **argv) static int do_detach(int argc, char **argv) { enum bpf_attach_type attach_type; - int err, mapfd, progfd; + int err, progfd; + int mapfd = 0; - if (!REQ_ARGS(5)) { + if (!REQ_ARGS(3)) { p_err("too few parameters for map detach"); return -EINVAL; } @@ -777,10 +781,11 @@ static int do_detach(int argc, char **argv) return -EINVAL; } NEXT_ARG(); - - mapfd = map_parse_fd(&argc, &argv); - if (mapfd < 0) - return mapfd; + if (argc > 0) { + mapfd = map_parse_fd(&argc, &argv); + if (mapfd < 0) + return mapfd; + } err = bpf_prog_detach2(progfd, mapfd, attach_type); if (err) { @@ -792,6 +797,56 @@ static int do_detach(int argc, char **argv) jsonw_null(json_wtr); return 0; } + +/* Flow dissector consists of a main program and a jump table for each + * supported protocol. The assumption here is that the first prog is the main + * one and the other progs are used in the tail calls. In this routine we + * build the jump table for the non-main progs. + */ +static int build_flow_dissector_jmp_table(struct bpf_object *obj, + struct bpf_program *prog, + const char *jmp_table_map) +{ + struct bpf_map *jmp_table; + struct bpf_program *pos; + int i = 0; + int prog_fd, jmp_table_fd, fd; + + prog_fd = bpf_program__fd(prog); + if (prog_fd < 0) { + p_err("failed to get fd of main prog"); + return prog_fd; + } + + jmp_table = bpf_object__find_map_by_name(obj, jmp_table_map); + if (jmp_table == NULL) { + p_err("failed to find '%s' map", jmp_table_map); + return -1; + } + + jmp_table_fd = bpf_map__fd(jmp_table); + if (jmp_table_fd < 0) { + p_err("failed to get fd of jmp_table"); + return jmp_table_fd; + } + + bpf_object__for_each_program(pos, obj) { + fd = bpf_program__fd(pos); + if (fd < 0) { + p_err("failed to get fd of '%s'", + bpf_program__title(pos, false)); + return fd; + } + + if (fd != prog_fd) { + bpf_map_update_elem(jmp_table_fd, &i, &fd, BPF_ANY); + ++i; + } + } + + return 0; +} + static int do_load(int argc, char **argv) { enum bpf_attach_type expected_attach_type; @@ -800,7 +855,7 @@ static int do_load(int argc, char **argv) }; struct map_replace *map_replace = NULL; unsigned int old_map_fds = 0; - struct bpf_program *prog; + struct bpf_program *prog, *pos; struct bpf_object *obj; struct bpf_map *map; const char *pinfile; @@ -918,13 +973,19 @@ static int do_load(int argc, char **argv) goto err_free_reuse_maps; } - prog = bpf_program__next(NULL, obj); + if (attr.prog_type == BPF_PROG_TYPE_FLOW_DISSECTOR) { + /* for the flow dissector type, the entry point is in the + * section flow_dissector; other progs are tail calls + */ + prog = bpf_object__find_program_by_title(obj, "flow_dissector"); + } else { + prog = bpf_program__next(NULL, obj); + } if (!prog) { p_err("object file doesn't contain any bpf program"); goto err_close_obj; } - bpf_program__set_ifindex(prog, ifindex); if (attr.prog_type == BPF_PROG_TYPE_UNSPEC) { const char *sec_name = bpf_program__title(prog, false); @@ -936,8 +997,13 @@ static int do_load(int argc, char **argv) goto err_close_obj; } } - bpf_program__set_type(prog, attr.prog_type); - bpf_program__set_expected_attach_type(prog, expected_attach_type); + + bpf_object__for_each_program(pos, obj) { + bpf_program__set_ifindex(pos, ifindex); + bpf_program__set_type(pos, attr.prog_type); + bpf_program__set_expected_attach_type(pos, + expected_attach_type); + } qsort(map_replace, old_map_fds, sizeof(*map_replace), map_replace_compar); @@ -1001,8 +1067,34 @@ static int do_load(int argc, char **argv) goto err_close_obj; } - if (do_pin_fd(bpf_program__fd(prog), pinfile)) + err = mount_bpffs_for_pin(pinfile); + if (err) { + p_err("failed to mount bpffs for pin '%s'", pinfile); goto err_close_obj; + } + + if (attr.prog_type == BPF_PROG_TYPE_FLOW_DISSECTOR) { + err = build_flow_dissector_jmp_table(obj, prog, "jmp_table"); + if (err) { + p_err("failed to build flow dissector jump table"); + goto err_close_obj; + } + /* flow dissector consist of multiple programs, + * we want to pin them all + */ + err = bpf_object__pin(obj, pinfile); + if (err) { + p_err("failed to pin flow dissector object"); + goto err_close_obj; + } + } else { + err = bpf_obj_pin(bpf_program__fd(prog), pinfile); + if (err) { + p_err("failed to pin program %s", + bpf_program__title(prog, false)); + goto err_close_obj; + } + } if (json_output) jsonw_null(json_wtr); @@ -1037,8 +1129,8 @@ static int do_help(int argc, char **argv) " %s %s pin PROG FILE\n" " %s %s load OBJ FILE [type TYPE] [dev NAME] \\\n" " [map { idx IDX | name NAME } MAP]\n" - " %s %s attach PROG ATTACH_TYPE MAP\n" - " %s %s detach PROG ATTACH_TYPE MAP\n" + " %s %s attach PROG ATTACH_TYPE [MAP]\n" + " %s %s detach PROG ATTACH_TYPE [MAP]\n" " %s %s help\n" "\n" " " HELP_SPEC_MAP "\n" @@ -1050,7 +1142,8 @@ static int do_help(int argc, char **argv) " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n" " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n" " cgroup/sendmsg4 | cgroup/sendmsg6 }\n" - " ATTACH_TYPE := { msg_verdict | skb_verdict | skb_parse }\n" + " ATTACH_TYPE := { msg_verdict | skb_verdict | skb_parse |\n" + " flow_dissector }\n" " " HELP_SPEC_OPTIONS "\n" "", bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],