From patchwork Thu Mar 25 11:59:59 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Kumar Kartikeya Dwivedi X-Patchwork-Id: 12163897 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UPPERCASE_50_75,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id DE8E4C433E1 for ; Thu, 25 Mar 2021 12:02:10 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id AEA7F61A2F for ; Thu, 25 Mar 2021 12:02:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230208AbhCYMBc (ORCPT ); Thu, 25 Mar 2021 08:01:32 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47006 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230096AbhCYMBZ (ORCPT ); Thu, 25 Mar 2021 08:01:25 -0400 Received: from mail-pf1-x443.google.com (mail-pf1-x443.google.com [IPv6:2607:f8b0:4864:20::443]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 97799C06174A; Thu, 25 Mar 2021 05:01:24 -0700 (PDT) Received: by mail-pf1-x443.google.com with SMTP id y200so1822735pfb.5; Thu, 25 Mar 2021 05:01:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=0fvJcL4250HO5zd+wRl8/iAR+2lRRD0vrCW2L2g+W8M=; b=QUCtUqyy1Mb87DIgLOyo2rqhqbZ6H1lw0Y/wkAcBum52cHy6d91qRUZ647BmO7KDY7 R516ow5i8coiHktuINCPjhxuQfvLtKWKSq4ZAEyoBTgeBGGutWrs2Bnqvd41kY94uax3 w7Pqz5tROzxuhJ7sRfl355mZIw85wycQR01q4acrFFTAxMOIYAoDNiaFcseZ0xtiW8Q5 2VuqzfTmcgPnS0lAaOkkpb4beLjqmU2TvMBf0rq/HnsgENMJxEyICCtLheOSZ2CJlOG+ cw5G8/BwCLX0lURNGf0lSfYQIy1neBy9oq5nStLruKMC+8d3TBa1XjVHJFRFUacneiv+ l/8w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=0fvJcL4250HO5zd+wRl8/iAR+2lRRD0vrCW2L2g+W8M=; b=tNaRcJKiWFYruWFyY0CP3or3kIkPduxd1rTCsG0zX1yWE/UBFjZ7y1ackF2FE/j9/n 8behdlPMlXYVI/Yz2d5s6F6N2lZoi4xL5LiXEgdS97khtTPcGbkOklOc7tbHEDHaSU0k Ipf/GjYqI2qAP1e9YOCedbuZi+iqNQOGM15iB4xHZPeyig9GoXB9s531jERajf/itucU IrHNV249Na81pHIpy1+sPDJnYskLUKebR50LfGqYsozPfr2HXwh5pW2t94bqDGg59GxS YZPD34ELnp8+zLHZ0cu9Q6UR0cz0dcqBl26zmwvrTZGO/a9U8Mk0xDI54Ihp59Ys7zqv +H1A== X-Gm-Message-State: AOAM533XqqiuBvu81Fg8/ATSIYBy6sfgNsYi7YEwqHc4GymaSY5PNIzh e2+Kwqlh4WezEP207liAlYtKbQ9mm7Yw2g== X-Google-Smtp-Source: ABdhPJwecekan97o6w/dQ++hOmNI8x7RR9JUY6Jl/Vm2f6/0mA5I33P1RWPHfMerDdanwOZyv+az2Q== X-Received: by 2002:a63:141e:: with SMTP id u30mr7495616pgl.31.1616673683845; Thu, 25 Mar 2021 05:01:23 -0700 (PDT) Received: from localhost ([112.79.237.176]) by smtp.gmail.com with ESMTPSA id fa21sm5594603pjb.25.2021.03.25.05.01.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Mar 2021 05:01:23 -0700 (PDT) From: Kumar Kartikeya Dwivedi To: bpf@vger.kernel.org Cc: brouer@redhat.com, Kumar Kartikeya Dwivedi , =?utf-8?q?Toke_H=C3=B8iland-J=C3=B8rgensen?= , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko , Martin KaFai Lau , Song Liu , Yonghong Song , John Fastabend , KP Singh , Shuah Khan , "David S. Miller" , Jakub Kicinski , Jesper Dangaard Brouer , Peter Zijlstra , linux-kernel@vger.kernel.org, netdev@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH bpf-next 1/5] tools pkt_cls.h: sync with kernel sources Date: Thu, 25 Mar 2021 17:29:59 +0530 Message-Id: <20210325120020.236504-2-memxor@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210325120020.236504-1-memxor@gmail.com> References: <20210325120020.236504-1-memxor@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org Update the header file so we can use the new defines in subsequent patches. Reviewed-by: Toke Høiland-Jørgensen Signed-off-by: Kumar Kartikeya Dwivedi --- tools/include/uapi/linux/pkt_cls.h | 174 ++++++++++++++++++++++++++++- 1 file changed, 170 insertions(+), 4 deletions(-) diff --git a/tools/include/uapi/linux/pkt_cls.h b/tools/include/uapi/linux/pkt_cls.h index 12153771396a..025c40fef93d 100644 --- a/tools/include/uapi/linux/pkt_cls.h +++ b/tools/include/uapi/linux/pkt_cls.h @@ -16,9 +16,36 @@ enum { TCA_ACT_STATS, TCA_ACT_PAD, TCA_ACT_COOKIE, + TCA_ACT_FLAGS, + TCA_ACT_HW_STATS, + TCA_ACT_USED_HW_STATS, __TCA_ACT_MAX }; +#define TCA_ACT_FLAGS_NO_PERCPU_STATS 1 /* Don't use percpu allocator for + * actions stats. + */ + +/* tca HW stats type + * When user does not pass the attribute, he does not care. + * It is the same as if he would pass the attribute with + * all supported bits set. + * In case no bits are set, user is not interested in getting any HW statistics. + */ +#define TCA_ACT_HW_STATS_IMMEDIATE (1 << 0) /* Means that in dump, user + * gets the current HW stats + * state from the device + * queried at the dump time. + */ +#define TCA_ACT_HW_STATS_DELAYED (1 << 1) /* Means that in dump, user gets + * HW stats that might be out of date + * for some time, maybe couple of + * seconds. This is the case when + * driver polls stats updates + * periodically or when it gets async + * stats update from the device. + */ + #define TCA_ACT_MAX __TCA_ACT_MAX #define TCA_OLD_COMPAT (TCA_ACT_MAX+1) #define TCA_ACT_MAX_PRIO 32 @@ -63,12 +90,53 @@ enum { #define TC_ACT_GOTO_CHAIN __TC_ACT_EXT(2) #define TC_ACT_EXT_OPCODE_MAX TC_ACT_GOTO_CHAIN +/* These macros are put here for binary compatibility with userspace apps that + * make use of them. For kernel code and new userspace apps, use the TCA_ID_* + * versions. + */ +#define TCA_ACT_GACT 5 +#define TCA_ACT_IPT 6 +#define TCA_ACT_PEDIT 7 +#define TCA_ACT_MIRRED 8 +#define TCA_ACT_NAT 9 +#define TCA_ACT_XT 10 +#define TCA_ACT_SKBEDIT 11 +#define TCA_ACT_VLAN 12 +#define TCA_ACT_BPF 13 +#define TCA_ACT_CONNMARK 14 +#define TCA_ACT_SKBMOD 15 +#define TCA_ACT_CSUM 16 +#define TCA_ACT_TUNNEL_KEY 17 +#define TCA_ACT_SIMP 22 +#define TCA_ACT_IFE 25 +#define TCA_ACT_SAMPLE 26 + /* Action type identifiers*/ -enum { - TCA_ID_UNSPEC=0, - TCA_ID_POLICE=1, +enum tca_id { + TCA_ID_UNSPEC = 0, + TCA_ID_POLICE = 1, + TCA_ID_GACT = TCA_ACT_GACT, + TCA_ID_IPT = TCA_ACT_IPT, + TCA_ID_PEDIT = TCA_ACT_PEDIT, + TCA_ID_MIRRED = TCA_ACT_MIRRED, + TCA_ID_NAT = TCA_ACT_NAT, + TCA_ID_XT = TCA_ACT_XT, + TCA_ID_SKBEDIT = TCA_ACT_SKBEDIT, + TCA_ID_VLAN = TCA_ACT_VLAN, + TCA_ID_BPF = TCA_ACT_BPF, + TCA_ID_CONNMARK = TCA_ACT_CONNMARK, + TCA_ID_SKBMOD = TCA_ACT_SKBMOD, + TCA_ID_CSUM = TCA_ACT_CSUM, + TCA_ID_TUNNEL_KEY = TCA_ACT_TUNNEL_KEY, + TCA_ID_SIMP = TCA_ACT_SIMP, + TCA_ID_IFE = TCA_ACT_IFE, + TCA_ID_SAMPLE = TCA_ACT_SAMPLE, + TCA_ID_CTINFO, + TCA_ID_MPLS, + TCA_ID_CT, + TCA_ID_GATE, /* other actions go here */ - __TCA_ID_MAX=255 + __TCA_ID_MAX = 255 }; #define TCA_ID_MAX __TCA_ID_MAX @@ -120,6 +188,10 @@ enum { TCA_POLICE_RESULT, TCA_POLICE_TM, TCA_POLICE_PAD, + TCA_POLICE_RATE64, + TCA_POLICE_PEAKRATE64, + TCA_POLICE_PKTRATE64, + TCA_POLICE_PKTBURST64, __TCA_POLICE_MAX #define TCA_POLICE_RESULT TCA_POLICE_RESULT }; @@ -333,12 +405,19 @@ enum { /* Basic filter */ +struct tc_basic_pcnt { + __u64 rcnt; + __u64 rhit; +}; + enum { TCA_BASIC_UNSPEC, TCA_BASIC_CLASSID, TCA_BASIC_EMATCHES, TCA_BASIC_ACT, TCA_BASIC_POLICE, + TCA_BASIC_PCNT, + TCA_BASIC_PAD, __TCA_BASIC_MAX }; @@ -485,17 +564,54 @@ enum { TCA_FLOWER_IN_HW_COUNT, + TCA_FLOWER_KEY_PORT_SRC_MIN, /* be16 */ + TCA_FLOWER_KEY_PORT_SRC_MAX, /* be16 */ + TCA_FLOWER_KEY_PORT_DST_MIN, /* be16 */ + TCA_FLOWER_KEY_PORT_DST_MAX, /* be16 */ + + TCA_FLOWER_KEY_CT_STATE, /* u16 */ + TCA_FLOWER_KEY_CT_STATE_MASK, /* u16 */ + TCA_FLOWER_KEY_CT_ZONE, /* u16 */ + TCA_FLOWER_KEY_CT_ZONE_MASK, /* u16 */ + TCA_FLOWER_KEY_CT_MARK, /* u32 */ + TCA_FLOWER_KEY_CT_MARK_MASK, /* u32 */ + TCA_FLOWER_KEY_CT_LABELS, /* u128 */ + TCA_FLOWER_KEY_CT_LABELS_MASK, /* u128 */ + + TCA_FLOWER_KEY_MPLS_OPTS, + + TCA_FLOWER_KEY_HASH, /* u32 */ + TCA_FLOWER_KEY_HASH_MASK, /* u32 */ + __TCA_FLOWER_MAX, }; #define TCA_FLOWER_MAX (__TCA_FLOWER_MAX - 1) +enum { + TCA_FLOWER_KEY_CT_FLAGS_NEW = 1 << 0, /* Beginning of a new connection. */ + TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED = 1 << 1, /* Part of an existing connection. */ + TCA_FLOWER_KEY_CT_FLAGS_RELATED = 1 << 2, /* Related to an established connection. */ + TCA_FLOWER_KEY_CT_FLAGS_TRACKED = 1 << 3, /* Conntrack has occurred. */ + TCA_FLOWER_KEY_CT_FLAGS_INVALID = 1 << 4, /* Conntrack is invalid. */ + TCA_FLOWER_KEY_CT_FLAGS_REPLY = 1 << 5, /* Packet is in the reply direction. */ + __TCA_FLOWER_KEY_CT_FLAGS_MAX, +}; + enum { TCA_FLOWER_KEY_ENC_OPTS_UNSPEC, TCA_FLOWER_KEY_ENC_OPTS_GENEVE, /* Nested * TCA_FLOWER_KEY_ENC_OPT_GENEVE_ * attributes */ + TCA_FLOWER_KEY_ENC_OPTS_VXLAN, /* Nested + * TCA_FLOWER_KEY_ENC_OPT_VXLAN_ + * attributes + */ + TCA_FLOWER_KEY_ENC_OPTS_ERSPAN, /* Nested + * TCA_FLOWER_KEY_ENC_OPT_ERSPAN_ + * attributes + */ __TCA_FLOWER_KEY_ENC_OPTS_MAX, }; @@ -513,18 +629,68 @@ enum { #define TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX \ (__TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX - 1) +enum { + TCA_FLOWER_KEY_ENC_OPT_VXLAN_UNSPEC, + TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP, /* u32 */ + __TCA_FLOWER_KEY_ENC_OPT_VXLAN_MAX, +}; + +#define TCA_FLOWER_KEY_ENC_OPT_VXLAN_MAX \ + (__TCA_FLOWER_KEY_ENC_OPT_VXLAN_MAX - 1) + +enum { + TCA_FLOWER_KEY_ENC_OPT_ERSPAN_UNSPEC, + TCA_FLOWER_KEY_ENC_OPT_ERSPAN_VER, /* u8 */ + TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX, /* be32 */ + TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR, /* u8 */ + TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID, /* u8 */ + __TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX, +}; + +#define TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX \ + (__TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX - 1) + +enum { + TCA_FLOWER_KEY_MPLS_OPTS_UNSPEC, + TCA_FLOWER_KEY_MPLS_OPTS_LSE, + __TCA_FLOWER_KEY_MPLS_OPTS_MAX, +}; + +#define TCA_FLOWER_KEY_MPLS_OPTS_MAX (__TCA_FLOWER_KEY_MPLS_OPTS_MAX - 1) + +enum { + TCA_FLOWER_KEY_MPLS_OPT_LSE_UNSPEC, + TCA_FLOWER_KEY_MPLS_OPT_LSE_DEPTH, + TCA_FLOWER_KEY_MPLS_OPT_LSE_TTL, + TCA_FLOWER_KEY_MPLS_OPT_LSE_BOS, + TCA_FLOWER_KEY_MPLS_OPT_LSE_TC, + TCA_FLOWER_KEY_MPLS_OPT_LSE_LABEL, + __TCA_FLOWER_KEY_MPLS_OPT_LSE_MAX, +}; + +#define TCA_FLOWER_KEY_MPLS_OPT_LSE_MAX \ + (__TCA_FLOWER_KEY_MPLS_OPT_LSE_MAX - 1) + enum { TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT = (1 << 0), TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST = (1 << 1), }; +#define TCA_FLOWER_MASK_FLAGS_RANGE (1 << 0) /* Range-based match */ + /* Match-all classifier */ +struct tc_matchall_pcnt { + __u64 rhit; +}; + enum { TCA_MATCHALL_UNSPEC, TCA_MATCHALL_CLASSID, TCA_MATCHALL_ACT, TCA_MATCHALL_FLAGS, + TCA_MATCHALL_PCNT, + TCA_MATCHALL_PAD, __TCA_MATCHALL_MAX, }; From patchwork Thu Mar 25 12:00:00 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Kumar Kartikeya Dwivedi X-Patchwork-Id: 12163899 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C8AB2C433E2 for ; Thu, 25 Mar 2021 12:02:42 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 8DF8061A2E for ; Thu, 25 Mar 2021 12:02:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230134AbhCYMCM (ORCPT ); Thu, 25 Mar 2021 08:02:12 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47084 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230096AbhCYMBr (ORCPT ); Thu, 25 Mar 2021 08:01:47 -0400 Received: from mail-pf1-x441.google.com (mail-pf1-x441.google.com [IPv6:2607:f8b0:4864:20::441]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5877EC06174A; Thu, 25 Mar 2021 05:01:47 -0700 (PDT) Received: by mail-pf1-x441.google.com with SMTP id c17so1820989pfn.6; Thu, 25 Mar 2021 05:01:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=8ZdmWVh22wEQGLiJ+FhPGw4D/jYq9k5IInMg19pQeUk=; b=m63UBDmGnmHksGN2ohPYwim3kn54/fJkoUswX4VqFUJQwTzXilWGazjIj5llHGnJdm M1ye/SbgbAHa+cFQ/gFuWku3fnAUDUNJ2E700qFBJQQts+sttZjZxZOXUdOxsbMV8Jc8 +2srlT4LkdG1HmBYA7Nk1hr5uDzH93mKx6RJSUdKJHi9PkDCu//jbRvvl3YC1h8e3RqQ hLd2Oxb1mZh6PEvy/BI6M5z/aB8DFs+dpsuoc59JVU2yhvzQaDtMq88fdzlOGluiT5w+ KYGBlsB0RfQNFEe7lqB7Mw+BUd9q7fJqLs73/85gcLznEhfqLWoLLHtba/Gs5Aq0LcgP 5BgA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=8ZdmWVh22wEQGLiJ+FhPGw4D/jYq9k5IInMg19pQeUk=; b=M/1H+wNyNiL9NV4aG9Tm8IIvry+5nazpnyxck/chvGrQ76HfmcNg+T52A9u89kR1v7 ldSvLDUY9Z0Gv66H/gbT87iWH/2ufT854ZriiCwzMsXxJkncB3JGl7uzR6wKIy7DfjXw 9WdU582UMP+wQpuR/zTKVkve+pnUI+RjBJQpF4/Z8kj4TLuKT1oGlVKTYqiclDDQ2yif M9JU894L9MzBMxyf91WK/M9kLf+BpcdpF+fj5atcBI+TccMtpnrX8z1cTqbxpMu5rmok eYRuG+UIiei80gipuVlpb6dxmCy+GQNhoiw8qhxIGGdSf87NhxrLRhaoGzpyO65j0EsW wQPA== X-Gm-Message-State: AOAM533/t9FJdEQzwP8uB4S37eL/U/G3FkRSGxMmraU7Z8WOVqMHjlYS +p+NCGSN7BLurzjZJs9Wn3Lqb+BiAVib/g== X-Google-Smtp-Source: ABdhPJyTK6btAvry0OkB+CX/KXna5g8e9ZIYZj69l+4NASqn6u3nRTIDHq6AWuyWAexuydexGhue/A== X-Received: by 2002:a17:902:82c7:b029:e4:74ad:9450 with SMTP id u7-20020a17090282c7b02900e474ad9450mr9663515plz.58.1616673706627; Thu, 25 Mar 2021 05:01:46 -0700 (PDT) Received: from localhost ([112.79.237.176]) by smtp.gmail.com with ESMTPSA id d6sm5692770pfn.197.2021.03.25.05.01.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Mar 2021 05:01:46 -0700 (PDT) From: Kumar Kartikeya Dwivedi To: bpf@vger.kernel.org Cc: brouer@redhat.com, Kumar Kartikeya Dwivedi , =?utf-8?q?Toke_H=C3=B8iland-J=C3=B8rgensen?= , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko , Martin KaFai Lau , Song Liu , Yonghong Song , John Fastabend , KP Singh , Shuah Khan , "David S. Miller" , Jakub Kicinski , Jesper Dangaard Brouer , Peter Zijlstra , linux-kernel@vger.kernel.org, netdev@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH bpf-next 2/5] libbpf: add helpers for preparing netlink attributes Date: Thu, 25 Mar 2021 17:30:00 +0530 Message-Id: <20210325120020.236504-3-memxor@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210325120020.236504-1-memxor@gmail.com> References: <20210325120020.236504-1-memxor@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org This change introduces a few helpers to wrap open coded attribute preparation in netlink.c. Every nested attribute's closure must happen using the helper end_nlattr_nested, which sets its length properly. NLA_F_NESTED is enforeced using begin_nlattr_nested helper. Other simple attributes can be added directly. The maxsz parameter corresponds to the size of the request structure which is being filled in, so for instance with req being: struct { struct nlmsghdr nh; struct tcmsg t; char buf[4096]; } req; Then, maxsz should be sizeof(req). This change also converts the open coded attribute preparation with the helpers. Note that the only failure the internal call to add_nlattr could result in the nested helper would be -EMSGSIZE, hence that is what we return to our caller. Reviewed-by: Toke Høiland-Jørgensen Signed-off-by: Kumar Kartikeya Dwivedi --- tools/lib/bpf/netlink.c | 37 +++++++++++++++-------------------- tools/lib/bpf/nlattr.h | 43 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 21 deletions(-) diff --git a/tools/lib/bpf/netlink.c b/tools/lib/bpf/netlink.c index 4dd73de00b6f..f448c29de76d 100644 --- a/tools/lib/bpf/netlink.c +++ b/tools/lib/bpf/netlink.c @@ -135,7 +135,7 @@ static int __bpf_set_link_xdp_fd_replace(int ifindex, int fd, int old_fd, __u32 flags) { int sock, seq = 0, ret; - struct nlattr *nla, *nla_xdp; + struct nlattr *nla; struct { struct nlmsghdr nh; struct ifinfomsg ifinfo; @@ -157,36 +157,31 @@ static int __bpf_set_link_xdp_fd_replace(int ifindex, int fd, int old_fd, req.ifinfo.ifi_index = ifindex; /* started nested attribute for XDP */ - nla = (struct nlattr *)(((char *)&req) - + NLMSG_ALIGN(req.nh.nlmsg_len)); - nla->nla_type = NLA_F_NESTED | IFLA_XDP; - nla->nla_len = NLA_HDRLEN; + nla = begin_nlattr_nested(&req.nh, sizeof(req), IFLA_XDP); + if (!nla) { + ret = -EMSGSIZE; + goto cleanup; + } /* add XDP fd */ - nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len); - nla_xdp->nla_type = IFLA_XDP_FD; - nla_xdp->nla_len = NLA_HDRLEN + sizeof(int); - memcpy((char *)nla_xdp + NLA_HDRLEN, &fd, sizeof(fd)); - nla->nla_len += nla_xdp->nla_len; + ret = add_nlattr(&req.nh, sizeof(req), IFLA_XDP_FD, &fd, sizeof(fd)); + if (ret < 0) + goto cleanup; /* if user passed in any flags, add those too */ if (flags) { - nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len); - nla_xdp->nla_type = IFLA_XDP_FLAGS; - nla_xdp->nla_len = NLA_HDRLEN + sizeof(flags); - memcpy((char *)nla_xdp + NLA_HDRLEN, &flags, sizeof(flags)); - nla->nla_len += nla_xdp->nla_len; + ret = add_nlattr(&req.nh, sizeof(req), IFLA_XDP_FLAGS, &flags, sizeof(flags)); + if (ret < 0) + goto cleanup; } if (flags & XDP_FLAGS_REPLACE) { - nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len); - nla_xdp->nla_type = IFLA_XDP_EXPECTED_FD; - nla_xdp->nla_len = NLA_HDRLEN + sizeof(old_fd); - memcpy((char *)nla_xdp + NLA_HDRLEN, &old_fd, sizeof(old_fd)); - nla->nla_len += nla_xdp->nla_len; + ret = add_nlattr(&req.nh, sizeof(req), IFLA_XDP_EXPECTED_FD, &flags, sizeof(flags)); + if (ret < 0) + goto cleanup; } - req.nh.nlmsg_len += NLA_ALIGN(nla->nla_len); + end_nlattr_nested(&req.nh, nla); if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) { ret = -errno; diff --git a/tools/lib/bpf/nlattr.h b/tools/lib/bpf/nlattr.h index 6cc3ac91690f..463a53bf3022 100644 --- a/tools/lib/bpf/nlattr.h +++ b/tools/lib/bpf/nlattr.h @@ -10,7 +10,10 @@ #define __LIBBPF_NLATTR_H #include +#include +#include #include + /* avoid multiple definition of netlink features */ #define __LINUX_NETLINK_H @@ -103,4 +106,44 @@ int libbpf_nla_parse_nested(struct nlattr *tb[], int maxtype, int libbpf_nla_dump_errormsg(struct nlmsghdr *nlh); + +/* Helpers for preparing/consuming attributes */ + +#define NLA_DATA(nla) ((struct nlattr *)((char *)(nla) + NLA_HDRLEN)) + +static inline int add_nlattr(struct nlmsghdr *nh, size_t maxsz, int type, + const void *data, int len) +{ + struct nlattr *nla; + + if (NLMSG_ALIGN(nh->nlmsg_len) + NLA_ALIGN(NLA_HDRLEN + len) > maxsz) + return -EMSGSIZE; + if ((!data && len) || (data && !len)) + return -EINVAL; + + nla = (struct nlattr *)((char *)nh + NLMSG_ALIGN(nh->nlmsg_len)); + nla->nla_type = type; + nla->nla_len = NLA_HDRLEN + len; + if (data) + memcpy((char *)nla + NLA_HDRLEN, data, len); + nh->nlmsg_len = NLMSG_ALIGN(nh->nlmsg_len) + NLA_ALIGN(nla->nla_len); + return 0; +} + +static inline struct nlattr *begin_nlattr_nested(struct nlmsghdr *nh, size_t maxsz, + int type) +{ + struct nlattr *tail; + + tail = (struct nlattr *)((char *)nh + NLMSG_ALIGN(nh->nlmsg_len)); + if (add_nlattr(nh, maxsz, type | NLA_F_NESTED, NULL, 0)) + return NULL; + return tail; +} + +static inline void end_nlattr_nested(struct nlmsghdr *nh, struct nlattr *tail) +{ + tail->nla_len = ((char *)nh + NLMSG_ALIGN(nh->nlmsg_len)) - (char *)(tail); +} + #endif /* __LIBBPF_NLATTR_H */ From patchwork Thu Mar 25 12:00:01 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Kumar Kartikeya Dwivedi X-Patchwork-Id: 12163903 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 43112C433DB for ; Thu, 25 Mar 2021 12:03:14 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id F2DCB61A30 for ; Thu, 25 Mar 2021 12:03:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230239AbhCYMCm (ORCPT ); Thu, 25 Mar 2021 08:02:42 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47176 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230298AbhCYMCM (ORCPT ); Thu, 25 Mar 2021 08:02:12 -0400 Received: from mail-pf1-x442.google.com (mail-pf1-x442.google.com [IPv6:2607:f8b0:4864:20::442]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BE434C06174A; Thu, 25 Mar 2021 05:02:11 -0700 (PDT) Received: by mail-pf1-x442.google.com with SMTP id m11so1802255pfc.11; Thu, 25 Mar 2021 05:02:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=HadcF0Rh2J9KQ9fQEkDQTK8DcpUyn4fd3MrWygpEydw=; b=Cq4nNEjLpdCbsS66Lv/VoeKrZEXDjZZNGj6sV3rAnvMD3Q3OGVRVmh2eLrY3/fHlbK UYX/389CU4mzYfWBbMwWlqp3Fjv5WUQu5PR09/L2s1EWGKwP7UkxCmGPXXD/ruCnjncI 4LQwsrwh607Yc3DReMFK9cKvmfTjioNsqAhmaHjfry01cX5yVeTCzqVZrB75L5ab8MRq 3N8+GWrLRlKUtEAkfCzLFaLuMQhKlWhIgeE/gsdVSG0Buy11UhtnW2NDXHf6L/CFfwlz J2opzthYUaYCZQiED7sZ9jfx4vD1xP8noeNYVUnK1uC2tTT9TC+S4mbpcN+gN/jDwfPU 7uJQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=HadcF0Rh2J9KQ9fQEkDQTK8DcpUyn4fd3MrWygpEydw=; b=JdgXrT3GnVhgXzX+2scLOTYz2cJHwgpflstWrHfa/rECe0h6Pv+p/k7wl7txnlGQWH SaGQ9czWUiAES0HxbggcKsbEkzUYA/8y0SaXkGS/tU6TtKODPzXS+e8QdF89n1SBz68s tZ0ed4qCHx0WECzn2Wb8oDthJ4RwlIDQ27T9j7+D9zaOYs+L0DbHUWGJ3pJlo9Fw7z8c ZMtorO8xlV8gEh1/w4F5r/4YJB+IL8ddYfnVBrkKaHcLDa5B7OG/Q7ZB28T1vRlQwzh3 0Dx9ZoimeBstZh5ytl6kMZf1Qgr4981l9RyWmq/NgQPFGx0cW8bO4w136cTg7782YgPA mKTg== X-Gm-Message-State: AOAM533zzKcN9uw8LwqElGgwXYbZvz5fYakBd4zfveY3O4g3Y1OjVAGM 21TWeaxTZPpZLPjvAd3RQhBM5/esWbjVdw== X-Google-Smtp-Source: ABdhPJzCtF7PlFTbyczwVZy7FjE0nHjbVtDUGGUHqfFvTzJIF1ogDVYIykvxnuquIdrxfFQnkPV/hA== X-Received: by 2002:a63:5f0c:: with SMTP id t12mr7237127pgb.381.1616673730635; Thu, 25 Mar 2021 05:02:10 -0700 (PDT) Received: from localhost ([112.79.237.176]) by smtp.gmail.com with ESMTPSA id a29sm2616916pfg.130.2021.03.25.05.02.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Mar 2021 05:02:10 -0700 (PDT) From: Kumar Kartikeya Dwivedi To: bpf@vger.kernel.org Cc: brouer@redhat.com, Kumar Kartikeya Dwivedi , =?utf-8?q?Toke_H=C3=B8iland-J=C3=B8rgensen?= , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko , Martin KaFai Lau , Song Liu , Yonghong Song , John Fastabend , KP Singh , Shuah Khan , "David S. Miller" , Jakub Kicinski , Jesper Dangaard Brouer , Peter Zijlstra , linux-kernel@vger.kernel.org, netdev@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH bpf-next 3/5] libbpf: add low level TC-BPF API Date: Thu, 25 Mar 2021 17:30:01 +0530 Message-Id: <20210325120020.236504-4-memxor@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210325120020.236504-1-memxor@gmail.com> References: <20210325120020.236504-1-memxor@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org This adds functions that wrap the netlink API used for adding, manipulating, and removing filters and actions. These functions operate directly on the loaded prog's fd, and return a handle to the filter and action using an out parameter (id for tc_cls, and index for tc_act). The basic featureset is covered to allow for attaching, manipulation of properties, and removal of filters and actions. Some additional features like TCA_BPF_POLICE and TCA_RATE for tc_cls have been omitted. These can added on top later by extending the bpf_tc_cls_opts struct. Support for binding actions directly to a classifier by passing them in during filter creation has also been omitted for now. These actions have an auto clean up property because their lifetime is bound to the filter they are attached to. This can be added later, but was omitted for now as direct action mode is a better alternative to it. An API summary: The BPF TC-CLS API bpf_tc_act_{attach, change, replace}_{dev, block} may be used to attach, change, and replace SCHED_CLS bpf classifiers. Separate set of functions are provided for network interfaces and shared filter blocks. bpf_tc_cls_detach_{dev, block} may be used to detach existing SCHED_CLS filter. The bpf_tc_cls_attach_id object filled in during attach, change, or replace must be passed in to the detach functions for them to remove the filter and its attached classififer correctly. bpf_tc_cls_get_info is a helper that can be used to obtain attributes for the filter and classififer. The opts structure may be used to choose the granularity of search, such that info for a specific filter corresponding to the same loaded bpf program can be obtained. By default, the first match is returned to the user. Examples: struct bpf_tc_cls_attach_id id = {}; struct bpf_object *obj; struct bpf_program *p; int fd, r; obj = bpf_object_open("foo.o"); if (IS_ERR_OR_NULL(obj)) return PTR_ERR(obj); p = bpf_object__find_program_by_title(obj, "classifier"); if (IS_ERR_OR_NULL(p)) return PTR_ERR(p); if (bpf_object__load(obj) < 0) return -1; fd = bpf_program__fd(p); r = bpf_tc_cls_attach_dev(fd, if_nametoindex("lo"), BPF_TC_CLSACT_INGRESS, ETH_P_IP, NULL, &id); if (r < 0) return r; ... which is roughly equivalent to (after clsact qdisc setup): # tc filter add dev lo ingress bpf obj /home/kkd/foo.o sec classifier If a user wishes to modify existing options on an attached filter, the bpf_tc_cls_change_{dev, block} API may be used. Parameters like chain_index, priority, and handle are ignored in the bpf_tc_cls_opts struct as they cannot be modified after attaching a filter. Example: /* Optional parameters necessary to select the right filter */ DECLARE_LIBBPF_OPTS(bpf_tc_cls_opts, opts, .handle = id.handle, .priority = id.priority, .chain_index = id.chain_index) /* Turn on direct action mode */ opts.direct_action = true; r = bpf_tc_cls_change_dev(fd, id.ifindex, id.parent_id, id.protocol, &opts, &id); if (r < 0) return r; /* Verify that the direct action mode has been set */ struct bpf_tc_cls_info info = {}; r = bpf_tc_cls_get_info_dev(fd, id.ifindex, id.parent_id, id.protocol, &opts, &info); if (r < 0) return r; assert(info.bpf_flags & TCA_BPF_FLAG_ACT_DIRECT); This would be roughly equivalent to doing: # tc filter change dev lo egress prio

handle bpf obj /home/kkd/foo.o section classifier da ... except a new bpf program will be loaded and replace existing one. If a user wishes to either replace an existing filter, or create a new one with the same properties, they can use bpf_tc_cls_replace_dev. The benefit of bpf_tc_cls_change is that it fails if no matching filter exists. The BPF TC-ACT API bpf_tc_act_{attach, replace} may be used to attach and replace already attached SCHED_ACT actions. Passing an index of 0 has special meaning, in that an index will be automatically chosen by the kernel. The index chosen by the kernel is the return value of these functions in case of success. bpf_tc_act_detach may be used to detach a SCHED_ACT action prog identified by the index parameter. The index 0 again has a special meaning, in that passing it will flush all existing SCHED_ACT actions loaded using the ACT API. bpf_tc_act_get_info is a helper to get the required attributes of a loaded program to be able to manipulate it futher, by passing them into the aforementioned functions. Example: struct bpf_object *obj; struct bpf_program *p; __u32 index; int fd, r; obj = bpf_object_open("foo.o"); if (IS_ERR_OR_NULL(obj)) return PTR_ERR(obj); p = bpf_object__find_program_by_title(obj, "action"); if (IS_ERR_OR_NULL(p)) return PTR_ERR(p); if (bpf_object__load(obj) < 0) return -1; fd = bpf_program__fd(p); r = bpf_tc_act_attach(fd, NULL, &index); if (r < 0) return r; if (bpf_tc_act_detach(index)) return -1; ... which is equivalent to the following sequence: tc action add action bpf obj /home/kkd/foo.o sec action tc action del action bpf index Reviewed-by: Toke Høiland-Jørgensen Signed-off-by: Kumar Kartikeya Dwivedi --- tools/lib/bpf/libbpf.h | 118 +++++++ tools/lib/bpf/libbpf.map | 14 + tools/lib/bpf/netlink.c | 715 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 841 insertions(+), 6 deletions(-) diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index a1a424b9b8ff..63baef6045b1 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -16,6 +16,9 @@ #include #include // for size_t #include +#include +#include +#include #include "libbpf_common.h" @@ -773,6 +776,121 @@ LIBBPF_API int bpf_linker__add_file(struct bpf_linker *linker, const char *filen LIBBPF_API int bpf_linker__finalize(struct bpf_linker *linker); LIBBPF_API void bpf_linker__free(struct bpf_linker *linker); +/* + * Requirements: + * If choosing hw offload mode (skip_sw = true), ifindex during prog load must be set. + */ + +/* Convenience macros for the clsact attach hooks */ +#define BPF_TC_CLSACT_INGRESS TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS) +#define BPF_TC_CLSACT_EGRESS TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_EGRESS) + +struct bpf_tc_cls_opts { + size_t sz; + __u32 chain_index; + __u32 handle; + __u32 priority; + __u32 class_id; + bool direct_action; + bool skip_sw; + bool skip_hw; + size_t :0; +}; + +#define bpf_tc_cls_opts__last_field skip_hw + +/* Acts as a handle for an attached filter */ +struct bpf_tc_cls_attach_id { + __u32 ifindex; + union { + __u32 block_index; + __u32 parent_id; + }; + __u32 protocol; + __u32 chain_index; + __u32 handle; + __u32 priority; +}; + +struct bpf_tc_cls_info { + struct bpf_tc_cls_attach_id id; + __u32 class_id; + __u32 bpf_flags; + __u32 bpf_flags_gen; +}; + +/* id is out parameter that will be written to, it must not be NULL */ +LIBBPF_API int bpf_tc_cls_attach_dev(int fd, __u32 ifindex, __u32 parent_id, + __u32 protocol, + const struct bpf_tc_cls_opts *opts, + struct bpf_tc_cls_attach_id *id); +LIBBPF_API int bpf_tc_cls_change_dev(int fd, __u32 ifindex, __u32 parent_id, + __u32 protocol, + const struct bpf_tc_cls_opts *opts, + struct bpf_tc_cls_attach_id *id); +/* This replaces an existing filter with the same attributes, so the arguments + * can be filled in from an existing attach_id when replacing, and otherwise be + * used like bpf_tc_cls_attach_dev. + */ +LIBBPF_API int bpf_tc_cls_replace_dev(int fd, __u32 ifindex, __u32 parent_id, + __u32 protocol, + const struct bpf_tc_cls_opts *opts, + struct bpf_tc_cls_attach_id *id); +LIBBPF_API int bpf_tc_cls_detach_dev(const struct bpf_tc_cls_attach_id *id); +LIBBPF_API int bpf_tc_cls_get_info_dev(int fd, __u32 ifindex, __u32 parent_id, + __u32 protocol, + const struct bpf_tc_cls_opts *opts, + struct bpf_tc_cls_info *info); + +/* id is out parameter that will be written to, it must not be NULL */ +LIBBPF_API int bpf_tc_cls_attach_block(int fd, __u32 block_index, + __u32 protocol, + const struct bpf_tc_cls_opts *opts, + struct bpf_tc_cls_attach_id *id); +LIBBPF_API int bpf_tc_cls_change_block(int fd, __u32 block_index, + __u32 protocol, + const struct bpf_tc_cls_opts *opts, + struct bpf_tc_cls_attach_id *id); +/* This replaces an existing filter with the same attributes, so the arguments + * can be filled in from an existing attach_id when replacing, and otherwise be + * used like bpf_tc_cls_attach_block. + */ +LIBBPF_API int bpf_tc_cls_replace_block(int fd, __u32 block_index, + __u32 protocol, + const struct bpf_tc_cls_opts *opts, + struct bpf_tc_cls_attach_id *id); +LIBBPF_API int bpf_tc_cls_detach_block(const struct bpf_tc_cls_attach_id *id); +LIBBPF_API int bpf_tc_cls_get_info_block(int fd, __u32 block_index, + __u32 protocol, + const struct bpf_tc_cls_opts *opts, + struct bpf_tc_cls_info *info); + +struct bpf_tc_act_opts { + size_t sz; + __u32 index; + int action; + void *cookie; + size_t cookie_len; + __u8 hw_stats_type; + bool no_percpu; + size_t :0; +}; + +#define bpf_tc_act_opts__last_field no_percpu + +struct bpf_tc_act_info { + __u32 index; + __u32 capab; + int action; + int refcnt; + int bindcnt; +}; + +LIBBPF_API int bpf_tc_act_attach(int fd, const struct bpf_tc_act_opts *opts, __u32 *index); +LIBBPF_API int bpf_tc_act_replace(int fd, const struct bpf_tc_act_opts *opts, __u32 *index); +LIBBPF_API int bpf_tc_act_detach(__u32 index); +LIBBPF_API int bpf_tc_act_get_info(int fd, struct bpf_tc_act_info *info); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map index 279ae861f568..72022b45a8b9 100644 --- a/tools/lib/bpf/libbpf.map +++ b/tools/lib/bpf/libbpf.map @@ -359,4 +359,18 @@ LIBBPF_0.4.0 { bpf_linker__finalize; bpf_linker__free; bpf_linker__new; + bpf_tc_act_attach; + bpf_tc_act_replace; + bpf_tc_act_detach; + bpf_tc_act_get_info; + bpf_tc_cls_attach_block; + bpf_tc_cls_attach_dev; + bpf_tc_cls_change_block; + bpf_tc_cls_change_dev; + bpf_tc_cls_detach_block; + bpf_tc_cls_detach_dev; + bpf_tc_cls_replace_block; + bpf_tc_cls_replace_dev; + bpf_tc_cls_get_info_dev; + bpf_tc_cls_get_info_block; } LIBBPF_0.3.0; diff --git a/tools/lib/bpf/netlink.c b/tools/lib/bpf/netlink.c index f448c29de76d..bd196d184341 100644 --- a/tools/lib/bpf/netlink.c +++ b/tools/lib/bpf/netlink.c @@ -4,8 +4,13 @@ #include #include #include +#include +#include #include +#include +#include #include +#include #include #include #include @@ -344,6 +349,20 @@ int bpf_get_link_xdp_id(int ifindex, __u32 *prog_id, __u32 flags) return ret; } +static int bpf_nl_get_ext(struct nlmsghdr *nh, int sock, unsigned int nl_pid, + __dump_nlmsg_t dump_link_nlmsg_p, + libbpf_dump_nlmsg_t dump_link_nlmsg, void *cookie) +{ + int seq = time(NULL); + + nh->nlmsg_seq = seq; + if (send(sock, nh, nh->nlmsg_len, 0) < 0) + return -errno; + + return bpf_netlink_recv(sock, nl_pid, seq, dump_link_nlmsg_p, + dump_link_nlmsg, cookie); +} + int libbpf_nl_get_link(int sock, unsigned int nl_pid, libbpf_dump_nlmsg_t dump_link_nlmsg, void *cookie) { @@ -356,12 +375,696 @@ int libbpf_nl_get_link(int sock, unsigned int nl_pid, .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, .ifm.ifi_family = AF_PACKET, }; - int seq = time(NULL); - req.nlh.nlmsg_seq = seq; - if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0) - return -errno; + return bpf_nl_get_ext(&req.nlh, sock, nl_pid, __dump_link_nlmsg, + dump_link_nlmsg, cookie); +} - return bpf_netlink_recv(sock, nl_pid, seq, __dump_link_nlmsg, - dump_link_nlmsg, cookie); +static int tc_bpf_add_fd_and_name(struct nlmsghdr *nh, size_t maxsz, int fd, + enum bpf_prog_type type) +{ + int len, ret, bpf_fd_type, bpf_name_type; + struct bpf_prog_info info = {}; + __u32 info_len = sizeof(info); + char name[64] = {}; + + switch (type) { + case BPF_PROG_TYPE_SCHED_CLS: + bpf_fd_type = TCA_BPF_FD; + bpf_name_type = TCA_BPF_NAME; + break; + case BPF_PROG_TYPE_SCHED_ACT: + bpf_fd_type = TCA_ACT_BPF_FD; + bpf_name_type = TCA_ACT_BPF_NAME; + break; + default: + return -EINVAL; + } + + ret = bpf_obj_get_info_by_fd(fd, &info, &info_len); + if (ret < 0 || type != info.type) + return ret; + + ret = add_nlattr(nh, maxsz, bpf_fd_type, &fd, sizeof(fd)); + if (ret < 0) + return ret; + + len = snprintf(name, sizeof(name), "%s:[%" PRIu32 "]", info.name, + info.id); + if (len < 0 || len >= sizeof(name)) + return len < 0 ? -EINVAL : -ENAMETOOLONG; + + return add_nlattr(nh, maxsz, bpf_name_type, name, len + 1); +} + +struct pass_info { + void *info; + __u32 prog_id; +}; + +static int cls_get_info(struct nlmsghdr *nh, libbpf_dump_nlmsg_t fn, + void *cookie); + +static int tc_cls_bpf_modify(int fd, int cmd, unsigned int flags, __u32 ifindex, + __u32 parent_id, __u32 protocol, + const struct bpf_tc_cls_opts *opts, + __dump_nlmsg_t fn, struct bpf_tc_cls_attach_id *id) +{ + unsigned int bpf_flags = 0, bpf_flags_gen = 0; + struct bpf_tc_cls_info info = {}; + int sock, seq = 0, ret; + struct nlattr *nla; + __u32 nl_pid = 0; + struct { + struct nlmsghdr nh; + struct tcmsg t; + char buf[256]; + } req; + + if (OPTS_GET(opts, priority, 0) > 0xFFFF) + return -EINVAL; + + sock = libbpf_netlink_open(&nl_pid); + if (sock < 0) + return sock; + + memset(&req, 0, sizeof(req)); + req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)); + req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags; + req.nh.nlmsg_type = cmd; + req.nh.nlmsg_pid = 0; + req.nh.nlmsg_seq = ++seq; + req.t.tcm_family = AF_UNSPEC; + req.t.tcm_handle = OPTS_GET(opts, handle, 0); + req.t.tcm_parent = parent_id; + req.t.tcm_ifindex = ifindex; + req.t.tcm_info = + TC_H_MAKE(OPTS_GET(opts, priority, 0UL) << 16, htons(protocol)); + + if (OPTS_HAS(opts, chain_index)) { + ret = add_nlattr(&req.nh, sizeof(req), TCA_CHAIN, + &opts->chain_index, sizeof(opts->chain_index)); + if (ret < 0) + goto end; + } + + ret = add_nlattr(&req.nh, sizeof(req), TCA_KIND, "bpf", sizeof("bpf")); + if (ret < 0) + goto end; + + nla = begin_nlattr_nested(&req.nh, sizeof(req), TCA_OPTIONS); + if (!nla) { + ret = -EMSGSIZE; + goto end; + } + + if (OPTS_GET(opts, class_id, TC_H_UNSPEC)) { + ret = add_nlattr(&req.nh, sizeof(req), TCA_BPF_CLASSID, + &opts->class_id, sizeof(opts->class_id)); + if (ret < 0) + goto end; + } + + if (cmd != RTM_DELTFILTER) { + ret = tc_bpf_add_fd_and_name(&req.nh, sizeof(req), fd, + BPF_PROG_TYPE_SCHED_CLS); + if (ret < 0) + goto end; + + if (OPTS_GET(opts, skip_hw, false)) + bpf_flags_gen |= TCA_CLS_FLAGS_SKIP_HW; + if (OPTS_GET(opts, skip_sw, false)) + bpf_flags_gen |= TCA_CLS_FLAGS_SKIP_SW; + if (OPTS_GET(opts, direct_action, false)) + bpf_flags |= TCA_BPF_FLAG_ACT_DIRECT; + + if (bpf_flags_gen) { + ret = add_nlattr(&req.nh, sizeof(req), + TCA_BPF_FLAGS_GEN, &bpf_flags_gen, + sizeof(bpf_flags_gen)); + if (ret < 0) + goto end; + } + + if (bpf_flags) { + ret = add_nlattr(&req.nh, sizeof(req), TCA_BPF_FLAGS, + &bpf_flags, sizeof(bpf_flags)); + if (ret < 0) + goto end; + } + } + + end_nlattr_nested(&req.nh, nla); + + ret = send(sock, &req.nh, req.nh.nlmsg_len, 0); + if (ret < 0) + goto end; + + ret = bpf_netlink_recv(sock, nl_pid, seq, fn, NULL, + &(struct pass_info){ &info, 0 }); + + if (fn) + *id = info.id; + +end: + close(sock); + return ret; +} + +int bpf_tc_cls_attach_dev(int fd, __u32 ifindex, __u32 parent_id, + __u32 protocol, const struct bpf_tc_cls_opts *opts, + struct bpf_tc_cls_attach_id *id) +{ + if (fd < 1 || !OPTS_VALID(opts, bpf_tc_cls_opts) || !id) + return -EINVAL; + + return tc_cls_bpf_modify(fd, RTM_NEWTFILTER, + NLM_F_ECHO | NLM_F_EXCL | NLM_F_CREATE, + ifindex, parent_id, protocol, opts, + cls_get_info, id); +} + +int bpf_tc_cls_change_dev(int fd, __u32 ifindex, __u32 parent_id, + __u32 protocol, const struct bpf_tc_cls_opts *opts, + struct bpf_tc_cls_attach_id *id) +{ + if (fd < 1 || !OPTS_VALID(opts, bpf_tc_cls_opts) || !id) + return -EINVAL; + + return tc_cls_bpf_modify(fd, RTM_NEWTFILTER, NLM_F_ECHO, ifindex, + parent_id, protocol, opts, cls_get_info, id); +} + +int bpf_tc_cls_replace_dev(int fd, __u32 ifindex, __u32 parent_id, + __u32 protocol, const struct bpf_tc_cls_opts *opts, + struct bpf_tc_cls_attach_id *id) +{ + if (fd < 1 || !OPTS_VALID(opts, bpf_tc_cls_opts) || !id) + return -EINVAL; + + return tc_cls_bpf_modify(fd, RTM_NEWTFILTER, NLM_F_ECHO | NLM_F_CREATE, + ifindex, parent_id, protocol, opts, + cls_get_info, id); +} + +int bpf_tc_cls_detach_dev(const struct bpf_tc_cls_attach_id *id) +{ + DECLARE_LIBBPF_OPTS(bpf_tc_cls_opts, opts, 0); + + if (!id) + return -EINVAL; + + opts.chain_index = id->chain_index; + opts.handle = id->handle; + opts.priority = id->priority; + + return tc_cls_bpf_modify(-1, RTM_DELTFILTER, 0, id->ifindex, + id->parent_id, id->protocol, &opts, NULL, + NULL); +} + +int bpf_tc_cls_attach_block(int fd, __u32 block_index, __u32 protocol, + const struct bpf_tc_cls_opts *opts, + struct bpf_tc_cls_attach_id *id) +{ + return bpf_tc_cls_attach_dev(fd, TCM_IFINDEX_MAGIC_BLOCK, block_index, + protocol, opts, id); +} + +int bpf_tc_cls_change_block(int fd, __u32 block_index, __u32 protocol, + const struct bpf_tc_cls_opts *opts, + struct bpf_tc_cls_attach_id *id) +{ + return bpf_tc_cls_attach_dev(fd, TCM_IFINDEX_MAGIC_BLOCK, block_index, + protocol, opts, id); +} + +int bpf_tc_cls_replace_block(int fd, __u32 block_index, __u32 protocol, + const struct bpf_tc_cls_opts *opts, + struct bpf_tc_cls_attach_id *id) +{ + return bpf_tc_cls_attach_dev(fd, TCM_IFINDEX_MAGIC_BLOCK, block_index, + protocol, opts, id); +} + +int bpf_tc_cls_detach_block(const struct bpf_tc_cls_attach_id *id) +{ + return bpf_tc_cls_detach_dev(id); +} + +static int __cls_get_info(void *cookie, void *msg, struct nlattr **tb) +{ + struct nlattr *tbb[TCA_BPF_MAX + 1]; + struct pass_info *cinfo = cookie; + struct bpf_tc_cls_info *info; + struct tcmsg *t = msg; + __u32 prog_id; + + info = cinfo->info; + + if (!tb[TCA_OPTIONS]) + return 0; + + libbpf_nla_parse_nested(tbb, TCA_BPF_MAX, tb[TCA_OPTIONS], NULL); + if (!tbb[TCA_BPF_ID]) + return 0; + + prog_id = libbpf_nla_getattr_u32(tbb[TCA_BPF_ID]); + if (cinfo->prog_id && cinfo->prog_id != prog_id) + return 0; + + info->id.parent_id = t->tcm_parent; + info->id.ifindex = t->tcm_ifindex; + info->id.protocol = ntohs(TC_H_MIN(t->tcm_info)); + info->id.priority = TC_H_MAJ(t->tcm_info) >> 16; + info->id.handle = t->tcm_handle; + + if (tb[TCA_CHAIN]) + info->id.chain_index = libbpf_nla_getattr_u32(tb[TCA_CHAIN]); + else + info->id.chain_index = 0; + + if (tbb[TCA_BPF_FLAGS]) + info->bpf_flags = libbpf_nla_getattr_u32(tbb[TCA_BPF_FLAGS]); + + if (tbb[TCA_BPF_FLAGS_GEN]) + info->bpf_flags_gen = + libbpf_nla_getattr_u32(tbb[TCA_BPF_FLAGS_GEN]); + + if (tbb[TCA_BPF_CLASSID]) + info->class_id = libbpf_nla_getattr_u32(tbb[TCA_BPF_CLASSID]); + + return 1; +} + +static int cls_get_info(struct nlmsghdr *nh, libbpf_dump_nlmsg_t fn, + void *cookie) +{ + struct tcmsg *t = NLMSG_DATA(nh); + struct nlattr *tb[TCA_MAX + 1]; + + libbpf_nla_parse(tb, TCA_MAX, + (struct nlattr *)((char *)t + NLMSG_ALIGN(sizeof(*t))), + NLMSG_PAYLOAD(nh, sizeof(*t)), NULL); + if (!tb[TCA_KIND]) + return -EINVAL; + + return __cls_get_info(cookie, t, tb); +} + +static int tc_cls_get_info(int fd, __u32 ifindex, __u32 parent_id, + __u32 protocol, const struct bpf_tc_cls_opts *opts, + struct bpf_tc_cls_info *info) +{ + __u32 nl_pid, info_len = sizeof(struct bpf_prog_info); + struct bpf_prog_info prog_info = {}; + int sock, ret; + struct { + struct nlmsghdr nh; + struct tcmsg t; + char buf[256]; + } req = { + .nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)), + .nh.nlmsg_type = RTM_GETTFILTER, + .nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP, + .t.tcm_family = AF_UNSPEC, + }; + + if (!OPTS_VALID(opts, bpf_tc_cls_opts)) + return -EINVAL; + + req.t.tcm_parent = parent_id; + req.t.tcm_ifindex = ifindex; + req.t.tcm_handle = OPTS_GET(opts, handle, 0); + req.t.tcm_info = + TC_H_MAKE(OPTS_GET(opts, priority, 0UL) << 16, htons(protocol)); + + ret = bpf_obj_get_info_by_fd(fd, &prog_info, &info_len); + if (ret < 0) + return ret; + + sock = libbpf_netlink_open(&nl_pid); + if (sock < 0) + return sock; + + ret = add_nlattr(&req.nh, sizeof(req), TCA_KIND, "bpf", sizeof("bpf")); + if (ret < 0) + goto end; + + if (OPTS_HAS(opts, chain_index)) { + ret = add_nlattr(&req.nh, sizeof(req), TCA_CHAIN, + &opts->chain_index, sizeof(opts->chain_index)); + if (ret < 0) + goto end; + } + + req.nh.nlmsg_seq = time(NULL); + + ret = bpf_nl_get_ext(&req.nh, sock, nl_pid, cls_get_info, NULL, + &(struct pass_info){ info, prog_info.id }); + if (ret < 0) + goto end; + /* 1 denotes a match */ + ret = ret == 1 ? 0 : -ESRCH; +end: + close(sock); + return ret; +} + +int bpf_tc_cls_get_info_dev(int fd, __u32 ifindex, __u32 parent_id, + __u32 protocol, const struct bpf_tc_cls_opts *opts, + struct bpf_tc_cls_info *info) +{ + return tc_cls_get_info(fd, ifindex, parent_id, protocol, opts, info); +} + +int bpf_tc_cls_get_info_block(int fd, __u32 block_index, __u32 protocol, + const struct bpf_tc_cls_opts *opts, + struct bpf_tc_cls_info *info) +{ + return bpf_tc_cls_get_info_dev(fd, TCM_IFINDEX_MAGIC_BLOCK, block_index, + protocol, opts, info); +} + +static int tc_act_add_action(struct nlmsghdr *nh, size_t maxsz, int type, + int fd, const struct bpf_tc_act_opts *opts) +{ + struct nlattr *nla, *nla_opt, *nla_subopt; + struct tc_act_bpf param = {}; + int ret; + + nla = begin_nlattr_nested(nh, maxsz, type); + if (!nla) + return -EMSGSIZE; + + nla_opt = begin_nlattr_nested(nh, maxsz, 1); + if (!nla_opt) + return -EMSGSIZE; + + ret = add_nlattr(nh, maxsz, TCA_ACT_KIND, "bpf", sizeof("bpf")); + if (ret < 0) + return ret; + + ret = add_nlattr(nh, maxsz, TCA_ACT_INDEX, + OPTS_HAS(opts, index) ? &opts->index : &(__u32){ 0 }, + sizeof(opts->index)); + + if (ret < 0) + return ret; + + nla_subopt = begin_nlattr_nested(nh, maxsz, TCA_ACT_OPTIONS); + if (!nla) + return -EMSGSIZE; + + if (fd > 0) { + ret = tc_bpf_add_fd_and_name(nh, maxsz, fd, + BPF_PROG_TYPE_SCHED_ACT); + if (ret < 0) + return ret; + } + + param.index = OPTS_GET(opts, index, 0); + param.action = OPTS_GET(opts, action, TC_ACT_UNSPEC); + + ret = add_nlattr(nh, maxsz, TCA_ACT_BPF_PARMS, ¶m, sizeof(param)); + if (ret < 0) + return ret; + + if (OPTS_GET(opts, cookie, NULL) && OPTS_GET(opts, cookie_len, 0)) { + if (opts->cookie_len > TC_COOKIE_MAX_SIZE) + return -E2BIG; + + ret = add_nlattr(nh, maxsz, TCA_ACT_COOKIE, opts->cookie, + opts->cookie_len); + if (ret < 0) + return ret; + } + + if (OPTS_GET(opts, hw_stats_type, 0)) { + struct nla_bitfield32 hw_stats_bf = { + .value = opts->hw_stats_type, + .selector = opts->hw_stats_type, + }; + + ret = add_nlattr(nh, maxsz, TCA_ACT_HW_STATS, &hw_stats_bf, + sizeof(hw_stats_bf)); + if (ret < 0) + return ret; + } + + if (OPTS_GET(opts, no_percpu, false)) { + struct nla_bitfield32 flags = { + TCA_ACT_FLAGS_NO_PERCPU_STATS, + TCA_ACT_FLAGS_NO_PERCPU_STATS, + }; + + ret = add_nlattr(nh, maxsz, TCA_ACT_FLAGS, &flags, + sizeof(flags)); + if (ret < 0) + return ret; + } + + end_nlattr_nested(nh, nla_subopt); + end_nlattr_nested(nh, nla_opt); + end_nlattr_nested(nh, nla); + + return 0; +} + +static int tc_act_modify(int cmd, unsigned int flags, int fd, int action, + const struct bpf_tc_act_opts *opts, __dump_nlmsg_t fn, + __u32 *index) +{ + struct bpf_tc_act_info info = {}; + int sock, seq = 0, ret; + __u32 nl_pid = 0; + struct { + struct nlmsghdr nh; + struct tcamsg t; + char buf[256]; + } req; + + sock = libbpf_netlink_open(&nl_pid); + if (sock < 0) + return sock; + + memset(&req, 0, sizeof(req)); + req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg)); + req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags; + req.nh.nlmsg_type = cmd; + req.nh.nlmsg_pid = 0; + req.nh.nlmsg_seq = ++seq; + req.t.tca_family = AF_UNSPEC; + + /* gcc complains when using req.nh here */ + ret = tc_act_add_action((struct nlmsghdr *)&req, sizeof(req), + TCA_ACT_TAB, fd, opts); + if (ret < 0) + goto end; + + ret = send(sock, &req.nh, req.nh.nlmsg_len, 0); + if (ret < 0) + goto end; + + ret = bpf_netlink_recv(sock, nl_pid, seq, fn, NULL, + &(struct pass_info){ &info, 0 }); + if (ret < 0) + goto end; + + if (fn) { + if (info.index) { + *index = info.index; + ret = 0; + } else + ret = -ESRCH; + } + +end: + close(sock); + return ret; +} + +static int get_act_info(struct nlmsghdr *nh, libbpf_dump_nlmsg_t fn, + void *cookie); + +int bpf_tc_act_attach(int fd, const struct bpf_tc_act_opts *opts, __u32 *index) +{ + if (fd < 1 || !OPTS_VALID(opts, bpf_tc_act_opts) || !index) + return -EINVAL; + + return tc_act_modify(RTM_NEWACTION, NLM_F_ECHO | NLM_F_EXCL, fd, + OPTS_GET(opts, action, TCA_ACT_UNSPEC), opts, + get_act_info, index); +} + +int bpf_tc_act_replace(int fd, const struct bpf_tc_act_opts *opts, __u32 *index) +{ + if (fd < 1 || !OPTS_VALID(opts, bpf_tc_act_opts) || !index) + return -EINVAL; + + return tc_act_modify(RTM_NEWACTION, NLM_F_ECHO | NLM_F_REPLACE, fd, + OPTS_GET(opts, action, TCA_ACT_UNSPEC), opts, + get_act_info, index); +} + +int bpf_tc_act_detach(__u32 index) +{ + DECLARE_LIBBPF_OPTS(bpf_tc_act_opts, opts, .index = index); + + return tc_act_modify(RTM_DELACTION, index ? 0 : NLM_F_ROOT, -1, + TC_ACT_UNSPEC, &opts, NULL, NULL); +} + +static int __get_act_info(void *cookie, void *msg, struct nlattr *nla) +{ + struct nlattr *tbb[TCA_ACT_BPF_MAX + 1]; + struct pass_info *ainfo = cookie; + struct bpf_tc_act_info *info; + struct tc_act_bpf parm; + __u32 prog_id; + + info = ainfo->info; + + if (!nla) + return -EINVAL; + + libbpf_nla_parse_nested(tbb, TCA_ACT_BPF_MAX, nla, NULL); + + if (!tbb[TCA_ACT_BPF_PARMS] || !tbb[TCA_ACT_BPF_ID]) + return -ESRCH; + + prog_id = libbpf_nla_getattr_u32(tbb[TCA_ACT_BPF_ID]); + if (ainfo->prog_id && ainfo->prog_id != prog_id) + return 0; + + /* Found a match */ + memcpy(&parm, libbpf_nla_data(tbb[TCA_ACT_BPF_PARMS]), + sizeof(parm)); + + info->index = parm.index; + info->capab = parm.capab; + info->action = parm.action; + info->refcnt = parm.refcnt; + info->bindcnt = parm.bindcnt; + + return 1; +} + +static int get_act_info_msg(struct nlmsghdr *nh, libbpf_dump_nlmsg_t fn, + void *cookie, __u32 total, struct nlattr *nla) +{ + struct nlattr *tbb[TCA_ACT_MAX + 1]; + struct tcamsg *t = NLMSG_DATA(nh); + struct nlattr *tb[total + 1]; + int ret; + + libbpf_nla_parse_nested(tb, total, nla, NULL); + + for (int i = 0; i <= total; i++) { + if (tb[i]) { + nla = tb[i]; + libbpf_nla_parse_nested(tbb, TCA_ACT_MAX, nla, NULL); + + if (!tbb[TCA_ACT_KIND]) + return -EINVAL; + + ret = __get_act_info(cookie, t, tbb[TCA_ACT_OPTIONS]); + if (ret < 0) + return ret; + + if (ret > 0) + return 1; + } + } + + return 0; +} + +static int get_act_info(struct nlmsghdr *nh, libbpf_dump_nlmsg_t fn, + void *cookie) +{ + struct nlattr *nla, *tb[TCA_ROOT_MAX + 1]; + __u32 total = 0; + + nla = NLMSG_DATA(nh) + NLMSG_ALIGN(sizeof(struct tcamsg)); + libbpf_nla_parse(tb, TCA_ROOT_MAX, nla, + NLMSG_PAYLOAD(nh, sizeof(struct tcamsg)), NULL); + + if (tb[TCA_ROOT_COUNT]) + total = libbpf_nla_getattr_u32(tb[TCA_ROOT_COUNT]); + + total = total ?: TCA_ACT_MAX_PRIO; + + return get_act_info_msg(nh, fn, cookie, total, tb[TCA_ACT_TAB]); +} + +static int tc_act_get_info(int sock, unsigned int nl_pid, int fd, + struct bpf_tc_act_info *info) +{ + struct bpf_prog_info prog_info = {}; + __u32 info_len = sizeof(prog_info); + struct nlattr *nla, *nla_opt; + struct { + struct nlmsghdr nh; + struct tcamsg t; + char buf[256]; + } req = { + .nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg)), + .nh.nlmsg_type = RTM_GETACTION, + .nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP, + .t.tca_family = AF_UNSPEC, + }; + int ret; + + if (fd < 1) + return -EINVAL; + + ret = bpf_obj_get_info_by_fd(fd, &prog_info, &info_len); + if (ret < 0) + return ret; + + nla = begin_nlattr_nested(&req.nh, sizeof(req), TCA_ACT_TAB); + if (!nla) + return -EMSGSIZE; + + nla_opt = begin_nlattr_nested(&req.nh, sizeof(req), 1); + if (!nla_opt) + return -EMSGSIZE; + + ret = add_nlattr(&req.nh, sizeof(req), TCA_ACT_KIND, "bpf", + sizeof("bpf")); + if (ret < 0) + return ret; + + end_nlattr_nested(&req.nh, nla_opt); + end_nlattr_nested(&req.nh, nla); + + req.nh.nlmsg_seq = time(NULL); + + /* Pass prog id the info is to be returned for */ + return bpf_nl_get_ext(&req.nh, sock, nl_pid, get_act_info, NULL, + &(struct pass_info){ info, prog_info.id }); +} + +int bpf_tc_act_get_info(int fd, struct bpf_tc_act_info *info) +{ + int sock, ret; + __u32 nl_pid; + + if (fd < 1 || !info) + return -EINVAL; + + sock = libbpf_netlink_open(&nl_pid); + if (sock < 0) + return sock; + + ret = tc_act_get_info(sock, nl_pid, fd, info); + if (ret < 0) + goto end; + + if (!info->index) + ret = -ESRCH; +end: + close(sock); + return ret; } From patchwork Thu Mar 25 12:00:02 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Kumar Kartikeya Dwivedi X-Patchwork-Id: 12163901 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 54F97C433E1 for ; Thu, 25 Mar 2021 12:03:14 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3251861A2A for ; Thu, 25 Mar 2021 12:03:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230419AbhCYMCn (ORCPT ); Thu, 25 Mar 2021 08:02:43 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47256 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230192AbhCYMCe (ORCPT ); Thu, 25 Mar 2021 08:02:34 -0400 Received: from mail-pg1-x542.google.com (mail-pg1-x542.google.com [IPv6:2607:f8b0:4864:20::542]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C8A21C06174A; Thu, 25 Mar 2021 05:02:34 -0700 (PDT) Received: by mail-pg1-x542.google.com with SMTP id r17so1601012pgi.0; Thu, 25 Mar 2021 05:02:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=NL4DiOKg00UDQaQxeDVdzlsM4CnwHYQ4poPpm4WQmLg=; b=hdaTm1dl1Z9gfZmGpJ0j5Yy2/E5R4loK5MiRH9GoQl3kyQMHqA2HtSAzIGm1c5A5Wl q9f5K7biYOXXtYcXiW3rzliG3zyUwuWO5ZsDC8A1sEoea1GnsI3iX6zblcj+JqMwBYCv ebOlFmEFy5YAuBK8yrInVv/EoUVIgUM46iqEcAHcKXsWCYmfuQy3fQNaFWFAxyn1lCMT m+XvnN03WCdTcqIXO1Yuyx6uT27R/DKc6sMQiGdy+WoK4Bi1aFW3Q+8fQvb/tSsxfQQw B3+PG8C5KjLg99/+QqjeaT/w4IsvZ3z+nOUIOHlrmZsq/mANUyRq3QzOAzcYrfq5VVkx xvOw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=NL4DiOKg00UDQaQxeDVdzlsM4CnwHYQ4poPpm4WQmLg=; b=Btle65Fub4ZxwkOkbUBgLGQqozEupbSnLoSosSF2J27CLrdoH69kWUw7WBiHVXkmAd k1UnkowS5zJHFGbyx9bINBbpCYxO/B7Kr6doB6njG2fARrhd4JtZGoiGQk/1SAgNiC7p QRdiES2prl45Up8Ij3th78hRPTyafrik5cmG5L/oLxR86X+2ene8gxNuyFtjoKF5ueMa 5Lnuhz1Eq7RBjXMRZNAO0HNLoP800LELYwTM21QHS26mGuGvFzL3bGpuHpEyiUiyqM0E LuLnE6hzRISMGAgAZOE5BwlZBNYNyF24OTJV8cp2ZxhHalOENnMDx0xkYAFS8Tdr7SVG 4U1A== X-Gm-Message-State: AOAM530ZLn7gC5C23t4LZ3U0+b1gTblx/BmvakaSUDUI8glqzRZOqD5f rtoQvYr4eyvp01Ne/aXEm2tLjv6sEGr+UQ== X-Google-Smtp-Source: ABdhPJyxKfmDHcC1e+UmEsp9XK3agpb2ofdq3+p29uHufxN+PA8aqHnTBlLn4DqiLtqtOAsoxFuxpw== X-Received: by 2002:a65:5289:: with SMTP id y9mr6539883pgp.447.1616673754082; Thu, 25 Mar 2021 05:02:34 -0700 (PDT) Received: from localhost ([112.79.237.176]) by smtp.gmail.com with ESMTPSA id h19sm5876594pfc.172.2021.03.25.05.02.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Mar 2021 05:02:33 -0700 (PDT) From: Kumar Kartikeya Dwivedi To: bpf@vger.kernel.org Cc: brouer@redhat.com, Kumar Kartikeya Dwivedi , =?utf-8?q?Toke_H=C3=B8iland-J=C3=B8rgensen?= , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko , Martin KaFai Lau , Song Liu , Yonghong Song , John Fastabend , KP Singh , Shuah Khan , "David S. Miller" , Jakub Kicinski , Jesper Dangaard Brouer , Peter Zijlstra , linux-kernel@vger.kernel.org, netdev@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH bpf-next 4/5] libbpf: add high level TC-BPF API Date: Thu, 25 Mar 2021 17:30:02 +0530 Message-Id: <20210325120020.236504-5-memxor@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210325120020.236504-1-memxor@gmail.com> References: <20210325120020.236504-1-memxor@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org A high level API is provided using the aforementioned routines internally, and these return a bpf_link object to the user. These are limited to just attach for now, and can be extended to change/replace if the use case arises in the future. It is also possible to call bpf_link__disconnect on the link and switch to managing the filter/action manually if the need arises. In most cases, the higher level API should suffice. Example: struct bpf_tc_cls_info info = {}; struct bpf_object *obj; struct bpf_program *p; struct bpf_link *link; __u32 index; int fd, r; obj = bpf_object_open("foo.o"); if (IS_ERR_OR_NULL(obj)) return PTR_ERR(obj); p = bpf_object__find_program_by_title(obj, "classifier"); if (IS_ERR_OR_NULL(p)) return PTR_ERR(p); DECLARE_LIBBPF_OPTS(bpf_tc_cls_opts, opts, .handle = 1); link = bpf_program__attach_tc_cls_dev(p, if_nametoindex("lo"), BPF_TC_CLSACT_INGRESS, ETH_P_IP, &opts); if (IS_ERR_OR_NULL(link)) return PTR_ERR(link); /* We want to take ownership of the filter, so we disconnect the * link and detach it on our own */ bpf_link__disconnect(link); r = bpf_tc_cls_get_info_dev(bpf_program__fd(fd), if_nametoindex("lo"), BPF_TC_CLSACT_INGRESS, ETH_P_IP, &opts, &info); if (r < 0) return r; /* We get the attach_id in the info struct, pass it to detach */ bpf_tc_cls_detach_dev(&info.id); bpf_link__destroy(link); Example: struct bpf_object *obj; struct bpf_program *p; struct bpf_link *link; __u32 index; int fd, r; obj = bpf_object_open("foo.o"); if (IS_ERR_OR_NULL(obj)) return PTR_ERR(obj); p = bpf_object__find_program_by_title(obj, "action"); if (IS_ERR_OR_NULL(p)) return PTR_ERR(p); /* A simple example that attaches a SCHED_ACT prog */ link = bpf_program__attach_tc_act(p, NULL); if (IS_ERR_OR_NULL(link)) return PTR_ERR(link); bpf_link__destroy(link); Reviewed-by: Toke Høiland-Jørgensen Signed-off-by: Kumar Kartikeya Dwivedi --- tools/lib/bpf/libbpf.c | 110 ++++++++++++++++++++++++++++++++++++++- tools/lib/bpf/libbpf.h | 15 ++++++ tools/lib/bpf/libbpf.map | 3 ++ 3 files changed, 127 insertions(+), 1 deletion(-) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 058b643cbcb1..cc5c200a661d 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -6847,7 +6848,7 @@ static int bpf_object__collect_relos(struct bpf_object *obj) for (i = 0; i < obj->nr_programs; i++) { struct bpf_program *p = &obj->programs[i]; - + if (!p->nr_reloc) continue; @@ -9443,6 +9444,10 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr, struct bpf_link { int (*detach)(struct bpf_link *link); int (*destroy)(struct bpf_link *link); + union { + struct bpf_tc_cls_attach_id *tc_cls_id; + __u32 tc_act_index; + }; char *pin_path; /* NULL, if not pinned */ int fd; /* hook FD, -1 if not applicable */ bool disconnected; @@ -10199,6 +10204,109 @@ struct bpf_link *bpf_map__attach_struct_ops(struct bpf_map *map) return link; } +static int bpf_link__detach_tc_cls(struct bpf_link *link) +{ + return bpf_tc_cls_detach_dev(link->tc_cls_id); +} + +static int bpf_link__destroy_tc_cls(struct bpf_link *link) +{ + zfree(&link->tc_cls_id); + return 0; +} + +struct bpf_link *bpf_program__attach_tc_cls_dev(struct bpf_program *prog, + __u32 ifindex, __u32 parent_id, + __u32 protocol, + const struct bpf_tc_cls_opts *opts) +{ + struct bpf_tc_cls_attach_id *id = NULL; + struct bpf_link *link = NULL; + char errmsg[STRERR_BUFSIZE]; + int prog_fd, err; + + prog_fd = bpf_program__fd(prog); + if (prog_fd < 0) { + pr_warn("prog '%s': can't attach before loaded\n", prog->name); + return ERR_PTR(-EINVAL); + } + + link = calloc(1, sizeof(*link)); + if (!link) + return ERR_PTR(-ENOMEM); + link->detach = &bpf_link__detach_tc_cls; + link->destroy = &bpf_link__destroy_tc_cls; + link->fd = -1; + + id = calloc(1, sizeof(*id)); + if (!id) { + err = -ENOMEM; + goto end; + } + + err = bpf_tc_cls_attach_dev(prog_fd, ifindex, parent_id, protocol, opts, id); + if (err < 0) { + pr_warn("prog '%s': failed to attach classifier: %s\n", + prog->name, + libbpf_strerror_r(err, errmsg, sizeof(errmsg))); + goto end; + } + + link->tc_cls_id = id; + return link; + +end: + free(id); + free(link); + return ERR_PTR(err); +} + +struct bpf_link *bpf_program__attach_tc_cls_block(struct bpf_program *prog, + __u32 block_index, __u32 protocol, + const struct bpf_tc_cls_opts *opts) +{ + return bpf_program__attach_tc_cls_dev(prog, TCM_IFINDEX_MAGIC_BLOCK, block_index, + protocol, opts); +} + +static int bpf_link__detach_tc_act(struct bpf_link *link) +{ + return bpf_tc_act_detach(link->tc_act_index); +} + +struct bpf_link *bpf_program__attach_tc_act(struct bpf_program *prog, + const struct bpf_tc_act_opts *opts) +{ + struct bpf_link *link = NULL; + char errmsg[STRERR_BUFSIZE]; + int prog_fd, err; + + prog_fd = bpf_program__fd(prog); + if (prog_fd < 0) { + pr_warn("prog '%s': can't attach before loading\n", prog->name); + return ERR_PTR(-EINVAL); + } + + link = calloc(1, sizeof(*link)); + if (!link) + return ERR_PTR(-ENOMEM); + link->detach = &bpf_link__detach_tc_act; + link->fd = -1; + + err = bpf_tc_act_attach(prog_fd, opts, &link->tc_act_index); + if (err < 0) { + pr_warn("prog '%s': failed to attach action: %s\n", prog->name, + libbpf_strerror_r(err, errmsg, sizeof(errmsg))); + goto end; + } + + return link; + +end: + free(link); + return ERR_PTR(err); +} + enum bpf_perf_event_ret bpf_perf_event_read_simple(void *mmap_mem, size_t mmap_size, size_t page_size, void **copy_mem, size_t *copy_size, diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 63baef6045b1..e33720d0b672 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -268,6 +268,21 @@ LIBBPF_API struct bpf_link * bpf_program__attach_freplace(struct bpf_program *prog, int target_fd, const char *attach_func_name); +struct bpf_tc_cls_opts; +struct bpf_tc_act_opts; + +LIBBPF_API struct bpf_link * +bpf_program__attach_tc_cls_dev(struct bpf_program *prog, __u32 ifindex, + __u32 parent_id, __u32 protocol, + const struct bpf_tc_cls_opts *opts); +LIBBPF_API struct bpf_link * +bpf_program__attach_tc_cls_block(struct bpf_program *prog, __u32 block_index, + __u32 protocol, + const struct bpf_tc_cls_opts *opts); +LIBBPF_API struct bpf_link * +bpf_program__attach_tc_act(struct bpf_program *prog, + const struct bpf_tc_act_opts *opts); + struct bpf_map; LIBBPF_API struct bpf_link *bpf_map__attach_struct_ops(struct bpf_map *map); diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map index 72022b45a8b9..2e1390e4ebf0 100644 --- a/tools/lib/bpf/libbpf.map +++ b/tools/lib/bpf/libbpf.map @@ -373,4 +373,7 @@ LIBBPF_0.4.0 { bpf_tc_cls_replace_dev; bpf_tc_cls_get_info_dev; bpf_tc_cls_get_info_block; + bpf_program__attach_tc_cls_dev; + bpf_program__attach_tc_cls_block; + bpf_program__attach_tc_act; } LIBBPF_0.3.0; From patchwork Thu Mar 25 12:00:03 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Kumar Kartikeya Dwivedi X-Patchwork-Id: 12163905 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5B2F5C433C1 for ; Thu, 25 Mar 2021 12:03:46 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1E70B61934 for ; Thu, 25 Mar 2021 12:03:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230358AbhCYMDO (ORCPT ); Thu, 25 Mar 2021 08:03:14 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47342 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230500AbhCYMC6 (ORCPT ); Thu, 25 Mar 2021 08:02:58 -0400 Received: from mail-pj1-x1042.google.com (mail-pj1-x1042.google.com [IPv6:2607:f8b0:4864:20::1042]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 22E9DC06174A; Thu, 25 Mar 2021 05:02:58 -0700 (PDT) Received: by mail-pj1-x1042.google.com with SMTP id x7-20020a17090a2b07b02900c0ea793940so2615440pjc.2; Thu, 25 Mar 2021 05:02:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=EBCc1b3VS8OAWVirBhTJFkz3T9KQdBDUNva6rSRKOyc=; b=YtdfuQmfquFeqs9/wkrr6hcvZcyGec5OWKtR/QYXwyGuDhleOgBluZI6q7jPcLbTec 81XJdXmbvgR/v8mHTB3ihFAkkj5R90bk8hP4kDy9wevfIZ9lJYyV4qGZdrcbYDqU8Rx7 2PCM0EvEZX3yUAywih94in7FiPB5YyZRXDxf7HNqjT5yKsX1DRc/VWoMocYMTCo4aQIM o/VpjKy09pPRXD3knn+oAEdBxy+L4J4aal/YPHF4kJPz6OMFPqoe0YkWPDOSSlfb1z6N jGWus99jdg9EVHrBP7ZZ1ep8YUh00CuQ0GiZ7yyoONk+ZgabAGkwrLe5oxdkUH6HDXi0 ZTdQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=EBCc1b3VS8OAWVirBhTJFkz3T9KQdBDUNva6rSRKOyc=; b=Gdyl8Nbgl42KWTxCMPfOgTJJW4CuPWDyj1OSv4Yr4sa9M+8QWU1TPZWpqmlcfbaiXr JyaB/2jTUsVDHE5ZVGjmQ2OYJrZfdqQepGTlqiYfTuDnLNHyS1yHJ2Dg6UIWHm98Q4A/ nGJuUwYzOaS96d2gobET8I7GUqZ9TvP93MoEL1T5pb++ejsnhsfUdDArS3Rr/Mg7ueg4 5ffwLitC1NqnpIHf3wJFtayZhpBFCY6+4hq5zcoV3e4YUlX/kIYF6rSQILKvGiH68Emy Xm15AmYKMm3nrig+dASecU0ZbhecBeoGqBoQIayTYBJFIJHHUsjq6lKx3Raak+y4hJ6G GA2A== X-Gm-Message-State: AOAM533hm7T0wFDY41MBrPusrQR1VtwarwnbcnKKJBQN8Wqie2J8rzFh JLx8MwOn7cOCiaAQWnEw/tEJMFvh4jDiUw== X-Google-Smtp-Source: ABdhPJzRLzxXur1jJPtFOouZ41pHnvy6ZvO1lbd0T3GjZTi0VRpCQW29ZcHvSTnOsYMUx4wzuFRn0g== X-Received: by 2002:a17:90a:5b11:: with SMTP id o17mr8909425pji.32.1616673777368; Thu, 25 Mar 2021 05:02:57 -0700 (PDT) Received: from localhost ([112.79.237.176]) by smtp.gmail.com with ESMTPSA id y24sm5718750pfn.213.2021.03.25.05.02.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Mar 2021 05:02:57 -0700 (PDT) From: Kumar Kartikeya Dwivedi To: bpf@vger.kernel.org Cc: brouer@redhat.com, Kumar Kartikeya Dwivedi , =?utf-8?q?Toke_H=C3=B8iland-J=C3=B8rgensen?= , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko , Martin KaFai Lau , Song Liu , Yonghong Song , John Fastabend , KP Singh , Shuah Khan , "David S. Miller" , Jakub Kicinski , Jesper Dangaard Brouer , Peter Zijlstra , linux-kernel@vger.kernel.org, netdev@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH bpf-next 5/5] libbpf: add selftests for TC-BPF API Date: Thu, 25 Mar 2021 17:30:03 +0530 Message-Id: <20210325120020.236504-6-memxor@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210325120020.236504-1-memxor@gmail.com> References: <20210325120020.236504-1-memxor@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org This adds some basic tests for the low level bpf_tc_* API and its bpf_program__attach_tc_* wrapper on top. Reviewed-by: Toke Høiland-Jørgensen Signed-off-by: Kumar Kartikeya Dwivedi --- .../selftests/bpf/prog_tests/test_tc_bpf.c | 261 ++++++++++++++++++ .../selftests/bpf/progs/test_tc_bpf_kern.c | 18 ++ 2 files changed, 279 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/test_tc_bpf.c create mode 100644 tools/testing/selftests/bpf/progs/test_tc_bpf_kern.c diff --git a/tools/testing/selftests/bpf/prog_tests/test_tc_bpf.c b/tools/testing/selftests/bpf/prog_tests/test_tc_bpf.c new file mode 100644 index 000000000000..8bab56b4dea0 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/test_tc_bpf.c @@ -0,0 +1,261 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include +#include +#include +#include + +#define LO_IFINDEX 1 + +static int test_tc_cls_internal(int fd, __u32 parent_id) +{ + struct bpf_tc_cls_attach_id id = {}; + struct bpf_tc_cls_info info = {}; + int ret; + DECLARE_LIBBPF_OPTS(bpf_tc_cls_opts, opts, .handle = 1, .priority = 10, + .class_id = TC_H_MAKE(1UL << 16, 1), + .chain_index = 5); + + ret = bpf_tc_cls_attach_dev(fd, LO_IFINDEX, parent_id, ETH_P_IP, &opts, + &id); + if (CHECK_FAIL(ret < 0)) + return ret; + + ret = bpf_tc_cls_get_info_dev(fd, LO_IFINDEX, parent_id, ETH_P_IP, NULL, + &info); + if (CHECK_FAIL(ret < 0)) + goto end; + + ret = -1; + + if (CHECK_FAIL(info.id.ifindex != id.ifindex) || + CHECK_FAIL(info.id.parent_id != id.parent_id) || + CHECK_FAIL(info.id.handle != id.handle) || + CHECK_FAIL(info.id.protocol != id.protocol) || + CHECK_FAIL(info.id.chain_index != id.chain_index) || + CHECK_FAIL(info.id.priority != id.priority) || + CHECK_FAIL(info.id.ifindex != LO_IFINDEX) || + CHECK_FAIL(info.id.parent_id != parent_id) || + CHECK_FAIL(info.id.handle != 1) || + CHECK_FAIL(info.id.priority != 10) || + CHECK_FAIL(info.id.protocol != ETH_P_IP) || + CHECK_FAIL(info.class_id != TC_H_MAKE(1UL << 16, 1)) || + CHECK_FAIL(info.id.chain_index != 5)) + goto end; + + opts.direct_action = true; + ret = bpf_tc_cls_replace_dev(fd, id.ifindex, id.parent_id, id.protocol, + &opts, &id); + if (CHECK_FAIL(ret < 0)) + return ret; + +end:; + ret = bpf_tc_cls_detach_dev(&id); + CHECK_FAIL(ret < 0); + return ret; +} + +static int test_tc_cls(struct bpf_program *prog, __u32 parent_id) +{ + struct bpf_tc_cls_info info = {}; + struct bpf_link *link; + int ret; + DECLARE_LIBBPF_OPTS(bpf_tc_cls_opts, opts, .priority = 10, .handle = 1, + .class_id = TC_H_MAKE(1UL << 16, 1)); + + link = bpf_program__attach_tc_cls_dev(prog, LO_IFINDEX, parent_id, + ETH_P_ALL, &opts); + if (CHECK_FAIL(IS_ERR_OR_NULL(link))) + return PTR_ERR(link); + + ret = bpf_tc_cls_get_info_dev(bpf_program__fd(prog), LO_IFINDEX, + parent_id, ETH_P_ALL, NULL, &info); + if (CHECK_FAIL(ret < 0)) + goto end; + + ret = -1; + + if (CHECK_FAIL(info.id.ifindex != LO_IFINDEX) || + CHECK_FAIL(info.id.handle != 1) || + CHECK_FAIL(info.id.priority != 10) || + CHECK_FAIL(info.id.protocol != ETH_P_ALL) || + CHECK_FAIL(info.class_id != TC_H_MAKE(1UL << 16, 1))) + goto end; + + /* Demonstrate changing attributes (e.g. to direct action) */ + opts.class_id = TC_H_MAKE(1UL << 16, 2); + opts.direct_action = true; + + /* Disconnect as we drop to the lower level API, which invalidates the + * link. + */ + bpf_link__disconnect(link); + + ret = bpf_tc_cls_change_dev(bpf_program__fd(prog), info.id.ifindex, + info.id.parent_id, info.id.protocol, &opts, + &info.id); + if (CHECK_FAIL(ret < 0)) + goto end; + + ret = bpf_tc_cls_get_info_dev(bpf_program__fd(prog), info.id.ifindex, + info.id.parent_id, info.id.protocol, NULL, + &info); + if (CHECK_FAIL(ret < 0)) + goto end; + + ret = -1; + + if (CHECK_FAIL(info.class_id != TC_H_MAKE(1UL << 16, 2))) + goto end; + if (CHECK_FAIL((info.bpf_flags & TCA_BPF_FLAG_ACT_DIRECT) != 1)) + goto end; + + ret = bpf_tc_cls_detach_dev(&info.id); + if (CHECK_FAIL(ret < 0)) + goto end; + +end: + ret = bpf_link__destroy(link); + CHECK_FAIL(ret < 0); + return ret; +} + +static int test_tc_act_internal(int fd) +{ + struct bpf_tc_act_info info = {}; + __u32 index = 0; + int ret; + DECLARE_LIBBPF_OPTS(bpf_tc_act_opts, opts, 0); + + ret = bpf_tc_act_attach(fd, &opts, &index); + if (CHECK_FAIL(ret < 0 || !index)) + goto end; + + index = 0; + ret = bpf_tc_act_attach(fd, &opts, &index); + if (CHECK_FAIL(ret < 0 || !index)) + goto end; + + opts.index = 3; + index = 0; + ret = bpf_tc_act_attach(fd, &opts, &index); + if (CHECK_FAIL(ret < 0 || !index)) + goto end; + + index = 0; + ret = bpf_tc_act_replace(fd, &opts, &index); + if (CHECK_FAIL(ret < 0 || !index)) + goto end; + + opts.index = 1; + ret = bpf_tc_act_attach(fd, &opts, &index); + if (CHECK_FAIL(!ret || ret != -EEXIST)) { + ret = -1; + goto end; + } + + for (int i = 0; i < 3; i++) { + memset(&info, 0, sizeof(info)); + + ret = bpf_tc_act_get_info(fd, &info); + if (CHECK_FAIL(ret < 0 && ret != -ESRCH)) + goto end; + + if (CHECK_FAIL(ret == -ESRCH)) + goto end; + + if (CHECK_FAIL(info.refcnt != 1)) + goto end; + + ret = bpf_tc_act_detach(info.index); + if (CHECK_FAIL(ret < 0)) + goto end; + } + + CHECK_FAIL(bpf_tc_act_get_info(fd, &info) == -ESRCH); + +end: + ret = bpf_tc_act_detach(0); + CHECK_FAIL(ret < 0); + return ret; +} + +static int test_tc_act(struct bpf_program *prog) +{ + struct bpf_tc_act_info info = {}; + struct bpf_link *link; + int ret; + DECLARE_LIBBPF_OPTS(bpf_tc_act_opts, opts, .index = 42); + + link = bpf_program__attach_tc_act(prog, &opts); + if (CHECK_FAIL(IS_ERR_OR_NULL(link))) + return PTR_ERR(link); + + ret = bpf_tc_act_get_info(bpf_program__fd(prog), &info); + if (CHECK_FAIL(ret < 0)) + goto end; + + if (CHECK_FAIL(info.index != 42)) + goto end; + +end: + ret = bpf_link__destroy(link); + CHECK_FAIL(ret < 0); + return ret; +} + +void test_test_tc_bpf(void) +{ + const char *file = "./test_tc_bpf_kern.o"; + int cls_fd, act_fd, ret; + struct bpf_program *clsp, *actp; + struct bpf_object *obj; + + obj = bpf_object__open(file); + if (CHECK_FAIL(IS_ERR_OR_NULL(obj))) + return; + + clsp = bpf_object__find_program_by_title(obj, "classifier"); + if (CHECK_FAIL(IS_ERR_OR_NULL(clsp))) + goto end; + + actp = bpf_object__find_program_by_title(obj, "action"); + if (CHECK_FAIL(IS_ERR_OR_NULL(clsp))) + goto end; + + ret = bpf_object__load(obj); + if (CHECK_FAIL(ret < 0)) + goto end; + + cls_fd = bpf_program__fd(clsp); + act_fd = bpf_program__fd(actp); + + if (CHECK_FAIL(system("tc qdisc add dev lo clsact"))) + goto end; + + ret = test_tc_cls_internal(cls_fd, BPF_TC_CLSACT_INGRESS); + if (CHECK_FAIL(ret < 0)) + goto end; + + ret = test_tc_cls(clsp, BPF_TC_CLSACT_EGRESS); + if (CHECK_FAIL(ret < 0)) + goto end; + + system("tc qdisc del dev lo clsact"); + + ret = test_tc_act_internal(act_fd); + if (CHECK_FAIL(ret < 0)) + goto end; + + ret = test_tc_act(actp); + if (CHECK_FAIL(ret < 0)) + goto end; + +end: + bpf_object__close(obj); + return; +} diff --git a/tools/testing/selftests/bpf/progs/test_tc_bpf_kern.c b/tools/testing/selftests/bpf/progs/test_tc_bpf_kern.c new file mode 100644 index 000000000000..d39644ea0fd7 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_tc_bpf_kern.c @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include + +// Dummy prog to test tc_bpf API + +SEC("classifier") +int cls(struct __sk_buff *skb) +{ + return 0; +} + +SEC("action") +int act(struct __sk_buff *skb) +{ + return 0; +}