From patchwork Sun Mar 29 23:16:30 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Sage X-Patchwork-Id: 221620 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=-7.0 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, LOTS_OF_MONEY, MAILING_LIST_MULTI, NORMAL_HTTP_TO_IP, NUMERIC_HTTP_ADDR, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, UNWANTED_LANGUAGE_BODY, 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 09A58C43331 for ; Sun, 29 Mar 2020 23:16:47 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 833A220774 for ; Sun, 29 Mar 2020 23:16:46 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=sage.org header.i=@sage.org header.b="C151wAML" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727376AbgC2XQp (ORCPT ); Sun, 29 Mar 2020 19:16:45 -0400 Received: from mail-ot1-f66.google.com ([209.85.210.66]:37977 "EHLO mail-ot1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727263AbgC2XQn (ORCPT ); Sun, 29 Mar 2020 19:16:43 -0400 Received: by mail-ot1-f66.google.com with SMTP id t28so16130708ott.5 for ; Sun, 29 Mar 2020 16:16:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sage.org; s=google; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=CsBMxR9v+LPP540eGOJLkT9Zcju8zCoz3xtTREcavTQ=; b=C151wAMLJ4AvbI5flyc9i8myQrBtTt2pAsnsp+AYOY1nSTJzJmdv4hMccvGJuizVbY L7516Wny9P9Fkz61/72eQVhZrzmSDfnIv59nG4BCjoSVH43Pqm+s3TPIPb0VClN353KE jqMHYwu9y+hE5NaNeyndIZCKp5j8CX9qnRgZtdTlQRfYNtO1z1qFYiAt9+TGpq+Bpa8i 6hvAKX/+l6ptARgwn5OJSQE4l6W2YKIW9fMSakTI+PXkf3yQK+9+IFyNI/Xmj6atMe6r BcXFFeKmm1ll3OZvY7jGCiqTHWgwJvUnRMqZ3/O1DDst8th2PZUau2y2I9Hx7jPrRam/ nypQ== 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:mime-version :content-transfer-encoding; bh=CsBMxR9v+LPP540eGOJLkT9Zcju8zCoz3xtTREcavTQ=; b=JhNj/7Xa5006DwSy8V56wAV67n3g3eYy3a21HxAxK3a1e9tfl7GthpTez/hhQ5YTy5 dyka6doXTG9Z/HtGOxjiYNd86Ds7YGjAvk6NDOCsBc8kBpTY5Rrw+a7faYLhNJ4D5wSI fghfFVle3fHDs4hzHaKvqZuEcMX89N1bsabzGIiB8xasYAfqMjKoNVzkUpWXPD+IqfEJ ct1U2Sn8HCk5CEP90gIxVBoMuzW9KUOpwPBIgRDNPg1e5EukxjIZeFpsw+LEVEwpldZF xglas39E4go3DMHQdxNHnHGQGzNGGfPN75C98oN0Y55XZ7VGuPHY68a30Q5JWCVTMS4p /TEw== X-Gm-Message-State: ANhLgQ2PYv1Zb6WTHq34SWjySu1bnM6DJxEBw7/gt8KDYWuXsQ7aAQoG w4djgOxpdnVVzNgiSkRxGJZpqg== X-Google-Smtp-Source: ADFU+vuVJsaZCvZheGLl5kcd9A+qLOAseEepef4KH4kGFhX88qT0a0gqPJfitWJ21u+DxkCry9fIZA== X-Received: by 2002:a9d:5a15:: with SMTP id v21mr2431207oth.86.1585523797731; Sun, 29 Mar 2020 16:16:37 -0700 (PDT) Received: from tower.attlocal.net ([2600:1700:4a30:fd70::48]) by smtp.googlemail.com with ESMTPSA id 33sm3950011otn.50.2020.03.29.16.16.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 29 Mar 2020 16:16:36 -0700 (PDT) From: Eric Sage To: bpf@vger.kernel.org Cc: ast@kernel.org, daniel@iogearbox.net, kafai@fb.com, yhs@fb.com, andriin@fb.com, hawk@kernel.org, john.fastabend@gmail.com, davem@davemloft.net, netdev@vger.kernel.org, Eric Sage Subject: [PATCH v4] samples/bpf: Add xdp_stat sample program Date: Sun, 29 Mar 2020 16:16:30 -0700 Message-Id: <20200329231630.41950-1-eric@sage.org> X-Mailer: git-send-email 2.25.1 MIME-Version: 1.0 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org At Facebook we use tail calls to jump between our firewall filters and our L4LB. This is a program I wrote to estimate per program performance by swapping out the entries in the program array with interceptors that take measurements and then jump to the original entries. I found the sample programs to be invaluable in understanding how to use the libbpf API (as well as the test env from the xdp-tutorial repo for testing), and want to return the favor. I am currently working on my next iteration that uses fentry/fexit to be less invasive, but I thought it was an interesting PoC of what you can do with program arrays. v4: - rebase v3: - Fixed typos in xdp_stat_kern.c - Switch to using key_size, value_size for prog arrays Signed-off-by: Eric Sage Acked-by: Andrii Nakryiko --- samples/bpf/Makefile | 3 + samples/bpf/xdp_stat | Bin 0 -> 200488 bytes samples/bpf/xdp_stat_common.h | 28 ++ samples/bpf/xdp_stat_kern.c | 192 +++++++++ samples/bpf/xdp_stat_user.c | 748 ++++++++++++++++++++++++++++++++++ 5 files changed, 971 insertions(+) create mode 100755 samples/bpf/xdp_stat create mode 100644 samples/bpf/xdp_stat_common.h create mode 100644 samples/bpf/xdp_stat_kern.c create mode 100644 samples/bpf/xdp_stat_user.c diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index 424f6fe7ce38..52ceabdca08e 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -53,6 +53,7 @@ tprogs-y += task_fd_query tprogs-y += xdp_sample_pkts tprogs-y += ibumad tprogs-y += hbm +tprogs-y += xdp_stat # Libbpf dependencies LIBBPF = $(TOOLS_PATH)/lib/bpf/libbpf.a @@ -109,6 +110,7 @@ task_fd_query-objs := bpf_load.o task_fd_query_user.o $(TRACE_HELPERS) xdp_sample_pkts-objs := xdp_sample_pkts_user.o $(TRACE_HELPERS) ibumad-objs := bpf_load.o ibumad_user.o $(TRACE_HELPERS) hbm-objs := bpf_load.o hbm.o $(CGROUP_HELPERS) +xdp_stat-objs := xdp_stat_user.o # Tell kbuild to always build the programs always-y := $(tprogs-y) @@ -170,6 +172,7 @@ always-y += ibumad_kern.o always-y += hbm_out_kern.o always-y += hbm_edt_kern.o always-y += xdpsock_kern.o +always-y += xdp_stat_kern.o ifeq ($(ARCH), arm) # Strip all except -D__LINUX_ARM_ARCH__ option needed to handle linux diff --git a/samples/bpf/xdp_stat b/samples/bpf/xdp_stat new file mode 100755 index 0000000000000000000000000000000000000000..32a05e4e3f804400914d5048bfb602888af00b11 GIT binary patch literal 200488 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 entrypoint -> interceptor_1 -> prog_1 -> ... -> + * interceptor_N -> prog_N -> XDP_ACTION + * + * At any point in the chain, including in the entrypoint, an XDP_ACTION can + * be returned. It is also not assumed that the order of jumps will not change + * (except that the entrypoint always comes first). + * + * Because there is no way to hook into the return of the XDP action, the + * entrypoint (interceptor_0) is also used to record the terminal run of the + * previous BPF program on the same CPU. Conceptually: + * + * ... -> prog_N -> XDP_ACTION -> interceptor_0 -> ... + * + * FIXME: A bad side effect of this is that the reported stats will always be + * behind in tracking terminal runs which is confusing to the user. + */ + +#include +#include + +#include "xdp_stat_common.h" + +// The maximum size of the intercepted program array. +#define MAX_PROG_ARRAY 64 + +/* NR is used to map interceptors to the programs that are being intercepted. */ +#define INTERCEPTOR(INDEX) \ + SEC("xdp/interceptor_" #INDEX) \ + int interceptor_##INDEX(struct xdp_md *ctx) \ + { \ + return interceptor_impl(ctx, INDEX); \ + } + +/* Required to use bpf_ktime_get_ns() */ +char _license[] SEC("license") = "GPL"; + +/* interception_info holds a single record per CPU to pass global state between + * interceptor programs. + */ +struct { + __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); + __uint(max_entries, 1); + __type(key, __u32); + __type(value, struct interception_info_rec); +} interception_info SEC(".maps"); + +/* interceptor_stats maps interceptor indexes to measurements of an intercepted + * BPF program. Index 0 maps the interceptor entrypoint to measurements of the + * original entrypoint. + */ +struct { + __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); + __uint(max_entries, MAX_PROG_ARRAY); + __type(key, __u32); + __type(value, struct prog_stats_rec); +} prog_stats SEC(".maps"); + +/* interceptor_nr_to_prog_id maps the number identifying an interceptor to the + * index of the intercepted BPF progam in jmp_table_copy. + */ +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(max_entries, MAX_PROG_ARRAY); + __type(key, __u32); + __type(value, __u32); +} interceptor_nr_to_prog_idx SEC(".maps"); + +/* jmp_table_entry has a single entry - the original XDP entrypoint - so that + * the interceptor entrypoint can jump to it. + */ +struct { + __uint(type, BPF_MAP_TYPE_PROG_ARRAY); + __uint(max_entries, 1); + __uint(key_size, sizeof(__u32)); + __uint(value_size, sizeof(__u32)); +} jmp_table_entrypoint SEC(".maps"); + +// jmp_table_copy contains a copy of the original jump table so it can be +// restored once the interception is complete. +struct { + __uint(type, BPF_MAP_TYPE_PROG_ARRAY); + __uint(max_entries, MAX_PROG_ARRAY); + __uint(key_size, sizeof(__u32)); + __uint(value_size, sizeof(__u32)); +} jmp_table_copy SEC(".maps"); + +/* interceptor_entrypoint replaces the BPF program attached to the XDP hook. + * The entrypoint records the terminal run on the previous BPF program before + * jumping back to the original entrypoint. + */ +SEC("xdp/interceptor_0") +int interceptor_entrypoint(struct xdp_md *ctx) +{ + __u32 info_key = 0; + + struct interception_info_rec *info = + bpf_map_lookup_elem(&interception_info, &info_key); + if (!info) + goto jmp_back; + + if (info->prev_ns_start != 0) { + struct prog_stats_rec *stats = bpf_map_lookup_elem( + &prog_stats, &info->prev_interceptor_nr); + if (!stats) + goto jmp_back; + stats->nr_terminal_runs++; + } + + info->prev_interceptor_nr = 0; + info->prev_ns_start = bpf_ktime_get_ns(); + +jmp_back: + bpf_tail_call(ctx, &jmp_table_entrypoint, 0); + return XDP_ABORTED; +} + +/* interceptor_impl records the chained run of the previous BPF program before + * jumping back to the intercepted BPF program in the copied jump table. + */ +static __always_inline int interceptor_impl(struct xdp_md *ctx, __u32 idx) +{ + __u32 info_key = 0; + __u64 ns_since_boot = bpf_ktime_get_ns(); + + __u32 *original_idx = + bpf_map_lookup_elem(&interceptor_nr_to_prog_idx, &idx); + if (!original_idx) + return XDP_ABORTED; + + struct interception_info_rec *info = + bpf_map_lookup_elem(&interception_info, &info_key); + if (!info) + goto jmp_back; + + struct prog_stats_rec *stats = + bpf_map_lookup_elem(&prog_stats, &info->prev_interceptor_nr); + if (!stats) + goto jmp_back; + + __u64 ns_elapsed = ns_since_boot - info->prev_ns_start; + + stats->nr_chained_runs++; + stats->ns_chained_runtime += ns_elapsed; + + info->prev_interceptor_nr = idx; + info->prev_ns_start = bpf_ktime_get_ns(); + +jmp_back: + bpf_tail_call(ctx, &jmp_table_copy, idx); + return XDP_ABORTED; +} + +/* The number of interceptors MUST match MAX_INTERCEPTORS in + * xdp_stat_common.h + */ +INTERCEPTOR(1); +INTERCEPTOR(2); +INTERCEPTOR(3); +INTERCEPTOR(4); +INTERCEPTOR(5); +INTERCEPTOR(6); +INTERCEPTOR(7); +INTERCEPTOR(8); +INTERCEPTOR(9); +INTERCEPTOR(10); +INTERCEPTOR(11); +INTERCEPTOR(12); +INTERCEPTOR(13); +INTERCEPTOR(14); +INTERCEPTOR(15); +INTERCEPTOR(16); +INTERCEPTOR(17); +INTERCEPTOR(18); +INTERCEPTOR(19); +INTERCEPTOR(20); +INTERCEPTOR(21); +INTERCEPTOR(22); +INTERCEPTOR(23); +INTERCEPTOR(24); +INTERCEPTOR(25); +INTERCEPTOR(26); +INTERCEPTOR(27); +INTERCEPTOR(28); +INTERCEPTOR(29); +INTERCEPTOR(30); +INTERCEPTOR(31); diff --git a/samples/bpf/xdp_stat_user.c b/samples/bpf/xdp_stat_user.c new file mode 100644 index 000000000000..f3879ad289e8 --- /dev/null +++ b/samples/bpf/xdp_stat_user.c @@ -0,0 +1,748 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2019 Facebook + */ + +static const char *__doc__ = + "\n" + "WARNING: This program intercepts the XDP hook and modifies the\n" + "monitored program array. USE WITH CAUTION.\n" + "\n" + "--device is the netdev the XDP program to be monitored is attached to.\n" + "--map is the BPF program array to intercept in /sys/fs/bpf.\n" + "\n" + "Measures performance of XDP programs using tail calls\n" + "\n" + "Measures the run count and run time of tail call XDP BPF programs.\n" + "Measurements are divided into chained and terminal program runs.\n" + "Chained runs occur when a BPF program chains with a tail call.\n" + "Terminal runs occur when a BPF program returns an XDP action.\n" + "\n" + "Terminal run measurements are less accurate and are only accounted\n" + "when the next packet is received.\n" + "\n" + "The maximum number of BPF programs that can be intercepted is 32\n"; + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "xdp_stat_common.h" + +#define MAX_PROGNAME 4096 + +/* Name of the file containing BPF code. + */ +#define FILENAME_XDP_STAT_KERN "xdp_stat_kern.o" + +/* Names of maps shared by kernel and userspace. + */ +#define MAPNAME_PROG_STATS "prog_stats" +#define MAPNAME_NR_TO_PROG_IDX "interceptor_nr_to_prog_idx" +#define MAPNAME_JMP_TABLE_ENTRYPOINT "jmp_table_entrypoint" +#define MAPNAME_JMP_TABLE_COPY "jmp_table_copy" + +static bool verbose; + +volatile sig_atomic_t keep_going = 1; + +static void handle_signal(int sig) +{ + keep_going = 0; + signal(SIGINT, handle_signal); +} + +struct intercept_ctx { + int ifindex; + int prog_cnt; + struct bpf_object *bpf_obj; + int entry_fd; + int entry_copy_fd; + int jmp_table_fd; + int jmp_copy_fd; + int jmp_entry_fd; + int prog_stats_fd; + int nr_to_prog_idx_fd; + int stats_enabled_oldval; +}; + +struct intercept_prog { + char *name; + __u64 id; + struct prog_stats_rec stats; +}; + +struct intercept_stats { + __u64 timestamp; + __u64 run_cnt_total; + __u64 run_time_ns_total; + __u64 run_time_ns_accounted; + struct intercept_prog progs[MAX_INTERCEPTORS]; +}; + +struct config { + char *ifname; + int ifindex; + char *mappath; + int count; + int interval; +}; + +static struct option long_options[] = { + { "verbose", no_argument, NULL, 'v' }, + { "device", required_argument, NULL, 'd' }, + { "map", required_argument, NULL, 'm' }, + { "interval", required_argument, NULL, 'i' }, + { 0, 0, 0, 0 }, +}; + +static void usage(char *argv[]) +{ + int i; + + printf("\nDOCUMENTATION:\n%s\n", __doc__); + printf("\n"); + printf(" Usage: %s (options-see-below)\n", argv[0]); + printf(" Listing options:\n"); + for (i = 0; long_options[i].name != 0; i++) { + printf(" --%-15s", long_options[i].name); + if (long_options[i].flag != NULL) + printf(" flag (internal value: %d)", + *long_options[i].flag); + else + printf("short-option: -%c", long_options[i].val); + printf("\n"); + } + printf("\n"); +} + +static void parse_args(int argc, char **argv, struct config *cfg) +{ + int opt; + + while ((opt = getopt_long(argc, argv, "pvabd:m:ic", long_options, + NULL)) != -1) { + switch (opt) { + case 'v': + verbose = 1; + break; + case 'd': + if (strlen(optarg) >= IF_NAMESIZE) { + fprintf(stderr, "ERR: --dev name too long\n"); + goto error; + } + cfg->ifname = strdup(optarg); + cfg->ifindex = if_nametoindex(cfg->ifname); + if (cfg->ifindex == 0) { + fprintf(stderr, + "ERR: --dev name unknown err(%d): %s\n", + errno, strerror(errno)); + goto error; + } + break; + case 'm': + cfg->mappath = strdup(optarg); + break; + case 'i': + cfg->interval = atoi(optarg); + break; + case 'h': + usage(argv); + return; +error: + default: + usage(argv); + exit(EXIT_FAILURE); + } + } +} + +static int _update_sysctl(const char *filename, int newval) +{ + int err, ret; + FILE *f; + const char *fmt = "%d\n"; + + f = fopen(filename, "r+"); + if (f == NULL) { + printf("fopen failed\n"); + return -errno; + } + + err = fscanf(f, fmt, &ret); + if (err != 1) { + printf("fscanf failed\n"); + err = err == EOF ? -EIO : -errno; + fclose(f); + return err; + } + + if (fseek(f, 0, SEEK_SET) < 0) { + printf("seek failed\n"); + fclose(f); + return -errno; + } + + if (fputc(newval, f) == EOF) { + printf("fputc failed\n"); + fclose(f); + return -errno; + } + + fclose(f); + return ret; +} + +static int __open_prog_fd(struct bpf_object *obj, const char *progname) +{ + struct bpf_program *prog = + bpf_object__find_program_by_title(obj, progname); + + if (!prog) { + printf("ERR: could not find bpf prog(%s)\n", progname); + return -1; + } + + return bpf_program__fd(prog); +} + +static int __open_map_fd(struct bpf_object *obj, const char *mapname) +{ + struct bpf_map *map = bpf_object__find_map_by_name(obj, mapname); + + if (!map) { + printf("ERR: could not find bpf map(%s)\n", mapname); + return -1; + } + + return bpf_map__fd(map); +} + +/* Copies contents of src_fd progam array to dst_fd program array. Returns less + * than zero on failure. + */ +static int __copy_prog_array_map(int src_fd, int dst_fd) +{ + int prog_fd; + __u32 val, prev_key, key = 0; + + while (bpf_map_get_next_key(src_fd, &prev_key, &key) == 0) { + prev_key = key; + + /* Reading a BPF program array returns BPF program IDs. */ + if (bpf_map_lookup_elem(src_fd, &key, &val) < 0) + continue; + + if (verbose) + printf("copying map fd(%d)[%d]: %d to map fd(%d)\n", + src_fd, key, val, dst_fd); + + /* Open a fd for the BPF program ID */ + prog_fd = bpf_prog_get_fd_by_id(val); + if (prog_fd < 0) { + printf("failed to get fd for prog id: %d", val); + return -1; + } + + if (bpf_map_update_elem(dst_fd, &key, &prog_fd, BPF_ANY) != 0) { + printf("failed to copy map elem: %s\n", + strerror(errno)); + return -1; + } + } + if (errno != ENOENT) { + printf("bpf_get_next_key failed: %s\n", strerror(errno)); + return -1; + } + return 0; +} + +/* __swap_xdp_entrypoint swaps the BPF program attached to the XDP hook with + * new_entry_prog_fd. Before the swap the old program is placed into the + * jmp_entrypoint program array at index zero. Returns less than zero on + * failure. + */ +static int __swap_xdp_entrypoint(struct bpf_object *bpf_obj, + int new_entrypoint_prog_fd, int ifindex) +{ + __u32 old_entrypoint_prog_id = 0; + __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST; + int jmp_table_entry_fd, old_entrypoint_prog_fd, idx = 0; + const char *jmp_table_entry_mapname = "jmp_table_entrypoint"; + + jmp_table_entry_fd = __open_map_fd(bpf_obj, jmp_table_entry_mapname); + if (jmp_table_entry_fd < 0) { + printf("ERR: open map(%s) failed\n", jmp_table_entry_mapname); + return EXIT_FAILURE; + } + + if (verbose) + printf("looking up xdp prog attached to ifindex(%d)\n", + ifindex); + + if (bpf_get_link_xdp_id(ifindex, &old_entrypoint_prog_id, xdp_flags)) { + printf("ERR: bpf_get_link_xdp_id %s\n", strerror(errno)); + return -1; + } + + if (!old_entrypoint_prog_id) { + printf("ERR: bpf_get_link_xdp_id did not fill entry_prog_id\n"); + return -1; + } + + if (verbose) + printf("BPF prog(%u) attached to XDP\n", + old_entrypoint_prog_id); + + old_entrypoint_prog_fd = bpf_prog_get_fd_by_id(old_entrypoint_prog_id); + if (old_entrypoint_prog_fd < 0) { + printf("ERR: get fd for prog id(%u) failed\n", + old_entrypoint_prog_id); + return -1; + } + + if (bpf_map_update_elem(jmp_table_entry_fd, &idx, + &old_entrypoint_prog_fd, BPF_ANY) != 0) { + printf("ERR: failed to update entry table: %s\n", + strerror(errno)); + return -1; + } + + xdp_flags &= ~XDP_FLAGS_UPDATE_IF_NOEXIST; + + if (bpf_set_link_xdp_fd(ifindex, new_entrypoint_prog_fd, xdp_flags)) { + printf("ERR: failed to attach intercept to XDP: %s\n", + strerror(errno)); + return -1; + } + + if (verbose) + printf("attached intercept entrypoint to XDP\n"); + + return old_entrypoint_prog_fd; +} + +/* load_interceptors replaces each fd entry in the provided jump table fd with + * an interceptor program. Each interceptor is named "intercept_N" starting from + * 1 (0 is the entrypoint which is loaded separately). The map nr_to_prog_idx + * is loaded with a mapping of N to the jump table index where N is located. + * + * The return value is the number of interceptors loaded or less than zero on + * error. + */ +static int __load_interceptors(struct bpf_object *intercept_bpf_obj, + int jmp_table_fd, int nr_to_prog_idx_fd) +{ + char intercept_name[MAX_PROGNAME]; + int prog_fd, intercept_nr = 1; + __u32 intercepted_prog_id, prev_idx, idx = -1; + const char *fmt = "xdp/interceptor_%d"; + + while (bpf_map_get_next_key(jmp_table_fd, &prev_idx, &idx) == 0) { + prev_idx = idx; + if (bpf_map_lookup_elem(jmp_table_fd, &idx, + &intercepted_prog_id) < 0) + continue; + + sprintf(intercept_name, fmt, intercept_nr); + + prog_fd = __open_prog_fd(intercept_bpf_obj, intercept_name); + if (prog_fd < 0) + return -1; + + if (bpf_map_update_elem(jmp_table_fd, &idx, &prog_fd, + BPF_ANY) != 0) { + printf("ERR: insert %s into jump table: %s\n", + intercept_name, strerror(errno)); + return -1; + } + if (bpf_map_update_elem(nr_to_prog_idx_fd, &intercept_nr, &idx, + BPF_ANY) != 0) { + printf("ERR: insert %s into intercept table: %s\n", + intercept_name, strerror(errno)); + return -1; + } + if (verbose) + printf("success: %s placed at idx(%d)\n", + intercept_name, idx); + intercept_nr++; + } + if (errno != ENOENT) { + printf("ERR: bpf_get_next_idx failed: %s\n", strerror(errno)); + return -1; + } + return intercept_nr--; +} + +static struct bpf_prog_info *__get_interceptor_info(struct intercept_ctx *ctx, + int ic_nr, + bool use_entry_table, + bool use_entry_fd) +{ + __u32 info_len = sizeof(struct bpf_prog_info); + struct bpf_prog_info *info = calloc(1, info_len); + __u32 prog_id, jmp_idx; + int prog_fd, table_fd = ctx->jmp_copy_fd; + + if (bpf_map_lookup_elem(ctx->nr_to_prog_idx_fd, &ic_nr, &jmp_idx) != + 0) { + printf("ERR: bpf_map_lookup_elem failed key: %d\n", ic_nr); + return NULL; + } + + if (use_entry_table) + table_fd = ctx->jmp_entry_fd; + + if (bpf_map_lookup_elem(table_fd, &jmp_idx, &prog_id) != 0) { + fprintf(stderr, "ERR: bpf_map_lookup_elem failed key: %d\n", + jmp_idx); + return NULL; + } + + prog_fd = bpf_prog_get_fd_by_id(prog_id); + if (prog_fd < 0) { + fprintf(stderr, "ERR: bpf_prog_get_fd_by_id(%d)\n", prog_id); + return NULL; + } + + if (use_entry_fd) + prog_fd = ctx->entry_fd; + + if (bpf_obj_get_info_by_fd(prog_fd, info, &info_len) < 0) { + fprintf(stderr, "ERR: bpf_obj_get_info_by_fd(%d)\n", prog_fd); + perror("Bleh"); + return NULL; + } + + return info; +} + +/* intercept_setup is called to begin interception of the XDP program attached + * to ifindex. mappath must be a pinned BPF map that the XDP program jumps to. + * + * The system is modified as follows: + * 1. XDP stats are enabled via sys.kernel.bpf_stats_enabled. + * 2. The program array at mappath is backed up. + * 3. The programs in the program array are replaced with interceptors. + * 4. The XDP entrypoint is unhooked and an interceptor entrpoint is attached. + * + * Returns a ctx object which is used to retrieve statistics and teardown + * the interception. + * + * WARNING: Failing to call intercept__teardown will leave the system in an + * incosistent state. intercept__teardown MUST be called. + */ +static struct intercept_ctx *intercept__setup(char *mappath, int ifindex) +{ + struct intercept_ctx *ctx = malloc(sizeof(struct intercept_ctx)); + + ctx->ifindex = ifindex; + + ctx->stats_enabled_oldval = + _update_sysctl("/proc/sys/kernel/bpf_stats_enabled", 1); + if (ctx->stats_enabled_oldval < 0) + perror("ERR: set bpf_stats_enabled sysctl failed\n"); + + if (bpf_prog_load(FILENAME_XDP_STAT_KERN, BPF_PROG_TYPE_XDP, + &ctx->bpf_obj, &ctx->entry_fd)) { + fprintf(stderr, "ERR: failed to load %s\n", + FILENAME_XDP_STAT_KERN); + return NULL; + } + + ctx->prog_stats_fd = __open_map_fd(ctx->bpf_obj, MAPNAME_PROG_STATS); + ctx->nr_to_prog_idx_fd = + __open_map_fd(ctx->bpf_obj, MAPNAME_NR_TO_PROG_IDX); + ctx->jmp_entry_fd = + __open_map_fd(ctx->bpf_obj, MAPNAME_JMP_TABLE_ENTRYPOINT); + ctx->jmp_copy_fd = __open_map_fd(ctx->bpf_obj, MAPNAME_JMP_TABLE_COPY); + + if ((ctx->prog_stats_fd | ctx->nr_to_prog_idx_fd | ctx->jmp_entry_fd | + ctx->jmp_copy_fd) < 0) + return NULL; + + if (verbose) + printf("opening (%s)\n", mappath); + + ctx->jmp_table_fd = bpf_obj_get(mappath); + if (ctx->jmp_table_fd < 0) { + fprintf(stderr, "ERR: failed to open %s\n", mappath); + return NULL; + } + + if (verbose) + printf("copying jmp_table to jmp_table_copy\n"); + + if (__copy_prog_array_map(ctx->jmp_table_fd, ctx->jmp_copy_fd) < 0) { + fprintf(stderr, "ERR: failed to copy jump table\n"); + return NULL; + } + + ctx->prog_cnt = __load_interceptors(ctx->bpf_obj, ctx->jmp_table_fd, + ctx->nr_to_prog_idx_fd); + if (ctx->prog_cnt < 0) { + fprintf(stderr, "ERR: failed to load intercepts\n"); + return NULL; + } + + if (verbose) + printf("%d intercepts loaded into jmp_table\n", ctx->prog_cnt); + + ctx->entry_copy_fd = __swap_xdp_entrypoint(ctx->bpf_obj, ctx->entry_fd, + ctx->ifindex); + if (ctx->entry_copy_fd < 0) { + fprintf(stderr, "ERR: failed to intercept entrypoint\n"); + return NULL; + } + + if (verbose) + printf("intercept attached to XDP entrypoint\n"); + + return ctx; +} + +/* intercept__teardown does the following: + * + * 1. Restores the intercepted program array using a backup copy made during + * intercept__setup. + * 2. The original XDP entrypoint is rehooked. + * 3. The previous value of sys.kernel.bpf_stats_enabled before the call to + * intercept__setup is restored. + * 4. The context is freed. + * + * This function MUST be called ONCE after creating a context via + * intercept__setup. + */ +static int intercept__teardown(struct intercept_ctx *ctx) +{ + if (__copy_prog_array_map(ctx->jmp_copy_fd, ctx->jmp_table_fd) < 0) { + fprintf(stderr, "ERR: failed to restore jump table\n"); + return -1; + } + + if (__swap_xdp_entrypoint(ctx->bpf_obj, ctx->entry_copy_fd, + ctx->ifindex) < 0) { + fprintf(stderr, "ERR: failed to restore entrypoint\n"); + return -1; + } + + if (_update_sysctl("/proc/sys/kernel/bpf_stats_enabled", + ctx->stats_enabled_oldval) < 0) { + perror("ERR: failed to restore bpf_stats_enabled sysctl\n"); + return -1; + } + + free(ctx); + + return 0; +} + +static struct intercept_stats *intercept__alloc_stats(struct intercept_ctx *ctx) +{ + struct intercept_stats *stats; + + stats = malloc(sizeof(*stats)); + if (!stats) { + fprintf(stderr, "ERR: mem alloc failed\n"); + return stats; + } + + return stats; +} + +static void intercept__free_stats(struct intercept_stats *stats) +{ + free(stats); +} + +static int intercept__collect_stats(struct intercept_ctx *ctx, + struct intercept_stats *stats) +{ + int nr, i; + unsigned int nr_cpus = libbpf_num_possible_cpus(); + struct bpf_prog_info *info; + + info = __get_interceptor_info(ctx, 0, true, true); + if (info == NULL) + return -1; + + memset(stats, 0, sizeof(*stats)); + + stats->run_time_ns_total = info->run_time_ns; + stats->run_cnt_total = info->run_cnt; + + for (nr = 0; nr < ctx->prog_cnt; nr++) { + struct prog_stats_rec values[nr_cpus]; + + if (bpf_map_lookup_elem(ctx->prog_stats_fd, &nr, values) != 0) { + fprintf(stderr, "ERR: intercept_stats_map(%d)\n", nr); + return -1; + } + + info = __get_interceptor_info(ctx, nr, !nr, false); + if (info == NULL) { + fprintf(stderr, "ERR: get_intercept_info(%d)\n", nr); + return -1; + } + + stats->progs[nr].name = strdup(info->name); + stats->progs[nr].id = info->id; + + for (i = 0; i < nr_cpus; i++) { + stats->run_time_ns_accounted += + values[i].ns_chained_runtime; + stats->progs[nr].stats.nr_terminal_runs += + values[i].nr_terminal_runs; + stats->progs[nr].stats.nr_chained_runs += + values[i].nr_chained_runs; + stats->progs[nr].stats.ns_chained_runtime += + values[i].ns_chained_runtime; + } + } + + free(info); + return 0; +} + +static int intercept__print_stats(struct intercept_ctx *ctx, + struct intercept_stats *stats) +{ + int i; + char timestamp[12]; + time_t t = time(NULL); + struct tm *lt = localtime(&t); + + if (intercept__collect_stats(ctx, stats) < 0) { + fprintf(stderr, "ERR: failed to get xdp stats\n"); + return -1; + } + + sprintf(timestamp, "%d:%d:%d", lt->tm_hour, lt->tm_min, lt->tm_sec); + + /* Print header */ + printf("%-8s %-4s %-25s ", timestamp, "Id", "Name"); + printf("%-15s %-15s ", "chain_runs", "chain/ns"); + printf("%-15s %-15s ", "term_runs", "term/ns"); + printf("%-15s\n", "total/ns"); + + /* Print row per BPF program */ + struct intercept_prog prog; + + for (i = 0; i < ctx->prog_cnt; i++) { + prog = stats->progs[i]; + printf("%-8s ", timestamp); + printf("%-4lld %-25s ", prog.id, prog.name); + printf("%-15lld %-15lld ", prog.stats.nr_chained_runs, + prog.stats.ns_chained_runtime); + + double terminal_weight = 0; + double ns_terminal_runtime = 0; + double ns_total_runtime = 0; + + /* Calculate estimates of terminal and total runtime */ + if (prog.stats.nr_terminal_runs != 0) { + terminal_weight = (stats->run_cnt_total / + (double)prog.stats.nr_terminal_runs); + ns_terminal_runtime = terminal_weight * + (stats->run_time_ns_total - + stats->run_time_ns_accounted); + } + ns_total_runtime = + ns_terminal_runtime + prog.stats.ns_chained_runtime; + + printf("%-15lld %-15.0f ", prog.stats.nr_terminal_runs, + ns_terminal_runtime); + printf("%-15.0f\n", ns_total_runtime); + } + printf("\n"); + + return 0; +} + +int main(int argc, char **argv) +{ + struct config cfg = { 0 }; + struct intercept_ctx *ctx; + struct intercept_stats *stats; + + signal(SIGINT, handle_signal); + + cfg.interval = 2; + + parse_args(argc, argv, &cfg); + + if (cfg.ifname == NULL) { + fprintf(stderr, "ERR: --dev is a required parameter\n"); + usage(argv); + return EXIT_FAILURE; + } + + if (cfg.mappath == NULL) { + fprintf(stderr, "ERR: --map is a required parameter\n"); + usage(argv); + return EXIT_FAILURE; + } + + if (verbose) + printf("ifname(%s) ifindex(%d) mappath(%s) interval(%d)\n", + cfg.ifname, cfg.ifindex, cfg.mappath, cfg.interval); + + struct rlimit r = { RLIM_INFINITY, RLIM_INFINITY }; + + // Remove memlock limits as BPF maps are accounted as locked kernel + // memory. + if (setrlimit(RLIMIT_MEMLOCK, &r)) { + perror("setrlimit(RLIMIT_MEMLOCK)"); + return 1; + } + + if (verbose) + printf("calling intercept__setup\n"); + + ctx = intercept__setup(cfg.mappath, cfg.ifindex); + if (ctx == NULL) { + fprintf(stderr, "ERR: failed to setup intercept\n"); + return EXIT_FAILURE; + } + + stats = intercept__alloc_stats(ctx); + if (stats == NULL) + goto teardown; + + while (1) { + if (intercept__print_stats(ctx, stats) < 0) + goto teardown; + + if (!keep_going) { + printf("Interrupted by user\n"); + break; + } + sleep(cfg.interval); + } + + intercept__free_stats(stats); + + if (verbose) + printf("calling intercept__restore\n"); + +teardown: + if (intercept__teardown(ctx) != 0) { + fprintf(stderr, "CRITICAL ERR: failed to restore\n"); + EXIT_FAILURE; + } + + return EXIT_SUCCESS; +}