From f58a4d51d8da7b248d8796e9981feb3d5a43d3d2 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 Jul 2019 14:34:43 -0700 Subject: samples/bpf: convert xdp_sample_pkts_user to perf_buffer API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert xdp_sample_pkts_user to libbpf's perf_buffer API. Signed-off-by: Andrii Nakryiko Acked-by: Song Liu Acked-by: Toke Høiland-Jørgensen Signed-off-by: Alexei Starovoitov --- samples/bpf/xdp_sample_pkts_user.c | 61 +++++++++++--------------------------- 1 file changed, 17 insertions(+), 44 deletions(-) (limited to 'samples') diff --git a/samples/bpf/xdp_sample_pkts_user.c b/samples/bpf/xdp_sample_pkts_user.c index dc66345a929a..3002714e3cd5 100644 --- a/samples/bpf/xdp_sample_pkts_user.c +++ b/samples/bpf/xdp_sample_pkts_user.c @@ -17,14 +17,13 @@ #include #include "perf-sys.h" -#include "trace_helpers.h" #define MAX_CPUS 128 -static int pmu_fds[MAX_CPUS], if_idx; -static struct perf_event_mmap_page *headers[MAX_CPUS]; +static int if_idx; static char *if_name; static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST; static __u32 prog_id; +static struct perf_buffer *pb = NULL; static int do_attach(int idx, int fd, const char *name) { @@ -73,7 +72,7 @@ static int do_detach(int idx, const char *name) #define SAMPLE_SIZE 64 -static int print_bpf_output(void *data, int size) +static void print_bpf_output(void *ctx, int cpu, void *data, __u32 size) { struct { __u16 cookie; @@ -83,45 +82,20 @@ static int print_bpf_output(void *data, int size) int i; if (e->cookie != 0xdead) { - printf("BUG cookie %x sized %d\n", - e->cookie, size); - return LIBBPF_PERF_EVENT_ERROR; + printf("BUG cookie %x sized %d\n", e->cookie, size); + return; } printf("Pkt len: %-5d bytes. Ethernet hdr: ", e->pkt_len); for (i = 0; i < 14 && i < e->pkt_len; i++) printf("%02x ", e->pkt_data[i]); printf("\n"); - - return LIBBPF_PERF_EVENT_CONT; -} - -static void test_bpf_perf_event(int map_fd, int num) -{ - struct perf_event_attr attr = { - .sample_type = PERF_SAMPLE_RAW, - .type = PERF_TYPE_SOFTWARE, - .config = PERF_COUNT_SW_BPF_OUTPUT, - .wakeup_events = 1, /* get an fd notification for every event */ - }; - int i; - - for (i = 0; i < num; i++) { - int key = i; - - pmu_fds[i] = sys_perf_event_open(&attr, -1/*pid*/, i/*cpu*/, - -1/*group_fd*/, 0); - - assert(pmu_fds[i] >= 0); - assert(bpf_map_update_elem(map_fd, &key, - &pmu_fds[i], BPF_ANY) == 0); - ioctl(pmu_fds[i], PERF_EVENT_IOC_ENABLE, 0); - } } static void sig_handler(int signo) { do_detach(if_idx, if_name); + perf_buffer__free(pb); exit(0); } @@ -140,13 +114,13 @@ int main(int argc, char **argv) struct bpf_prog_load_attr prog_load_attr = { .prog_type = BPF_PROG_TYPE_XDP, }; + struct perf_buffer_opts pb_opts = {}; const char *optstr = "F"; int prog_fd, map_fd, opt; struct bpf_object *obj; struct bpf_map *map; char filename[256]; - int ret, err, i; - int numcpus; + int ret, err; while ((opt = getopt(argc, argv, optstr)) != -1) { switch (opt) { @@ -169,10 +143,6 @@ int main(int argc, char **argv) return 1; } - numcpus = get_nprocs(); - if (numcpus > MAX_CPUS) - numcpus = MAX_CPUS; - snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); prog_load_attr.file = filename; @@ -211,14 +181,17 @@ int main(int argc, char **argv) return 1; } - test_bpf_perf_event(map_fd, numcpus); + pb_opts.sample_cb = print_bpf_output; + pb = perf_buffer__new(map_fd, 8, &pb_opts); + err = libbpf_get_error(pb); + if (err) { + perror("perf_buffer setup failed"); + return 1; + } - for (i = 0; i < numcpus; i++) - if (perf_event_mmap_header(pmu_fds[i], &headers[i]) < 0) - return 1; + while ((ret = perf_buffer__poll(pb, 1000)) >= 0) { + } - ret = perf_event_poller_multi(pmu_fds, headers, numcpus, - print_bpf_output); kill(0, SIGINT); return ret; } -- cgit v1.2.3-59-g8ed1b From c17bec549c9dc969b4e725c56aa9ebb125378397 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 Jul 2019 14:34:44 -0700 Subject: samples/bpf: switch trace_output sample to perf_buffer API Convert trace_output sample to libbpf's perf_buffer API. Signed-off-by: Andrii Nakryiko Acked-by: Song Liu Signed-off-by: Alexei Starovoitov --- samples/bpf/trace_output_user.c | 43 ++++++++++++++--------------------------- 1 file changed, 14 insertions(+), 29 deletions(-) (limited to 'samples') diff --git a/samples/bpf/trace_output_user.c b/samples/bpf/trace_output_user.c index 2dd1d39b152a..8ee47699a870 100644 --- a/samples/bpf/trace_output_user.c +++ b/samples/bpf/trace_output_user.c @@ -18,9 +18,6 @@ #include #include "bpf_load.h" #include "perf-sys.h" -#include "trace_helpers.h" - -static int pmu_fd; static __u64 time_get_ns(void) { @@ -31,12 +28,12 @@ static __u64 time_get_ns(void) } static __u64 start_time; +static __u64 cnt; #define MAX_CNT 100000ll -static int print_bpf_output(void *data, int size) +static void print_bpf_output(void *ctx, int cpu, void *data, __u32 size) { - static __u64 cnt; struct { __u64 pid; __u64 cookie; @@ -45,7 +42,7 @@ static int print_bpf_output(void *data, int size) if (e->cookie != 0x12345678) { printf("BUG pid %llx cookie %llx sized %d\n", e->pid, e->cookie, size); - return LIBBPF_PERF_EVENT_ERROR; + return; } cnt++; @@ -53,30 +50,14 @@ static int print_bpf_output(void *data, int size) if (cnt == MAX_CNT) { printf("recv %lld events per sec\n", MAX_CNT * 1000000000ll / (time_get_ns() - start_time)); - return LIBBPF_PERF_EVENT_DONE; + return; } - - return LIBBPF_PERF_EVENT_CONT; -} - -static void test_bpf_perf_event(void) -{ - struct perf_event_attr attr = { - .sample_type = PERF_SAMPLE_RAW, - .type = PERF_TYPE_SOFTWARE, - .config = PERF_COUNT_SW_BPF_OUTPUT, - }; - int key = 0; - - pmu_fd = sys_perf_event_open(&attr, -1/*pid*/, 0/*cpu*/, -1/*group_fd*/, 0); - - assert(pmu_fd >= 0); - assert(bpf_map_update_elem(map_fd[0], &key, &pmu_fd, BPF_ANY) == 0); - ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE, 0); } int main(int argc, char **argv) { + struct perf_buffer_opts pb_opts = {}; + struct perf_buffer *pb; char filename[256]; FILE *f; int ret; @@ -88,16 +69,20 @@ int main(int argc, char **argv) return 1; } - test_bpf_perf_event(); - - if (perf_event_mmap(pmu_fd) < 0) + pb_opts.sample_cb = print_bpf_output; + pb = perf_buffer__new(map_fd[0], 8, &pb_opts); + ret = libbpf_get_error(pb); + if (ret) { + printf("failed to setup perf_buffer: %d\n", ret); return 1; + } f = popen("taskset 1 dd if=/dev/zero of=/dev/null", "r"); (void) f; start_time = time_get_ns(); - ret = perf_event_poller(pmu_fd, print_bpf_output); + while ((ret = perf_buffer__poll(pb, 1000)) >= 0 && cnt < MAX_CNT) { + } kill(0, SIGINT); return ret; } -- cgit v1.2.3-59-g8ed1b From 3783d43752eab247ed296ac8d5022484ed969151 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Thu, 8 Aug 2019 18:17:37 +0200 Subject: samples/bpf: xdp_fwd rename devmap name to be xdp_tx_ports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The devmap name 'tx_port' came from a copy-paste from xdp_redirect_map which only have a single TX port. Change name to xdp_tx_ports to make it more descriptive. Signed-off-by: Jesper Dangaard Brouer Reviewed-by: David Ahern Acked-by: Yonghong Song Reviewed-by: Toke Høiland-Jørgensen Signed-off-by: Daniel Borkmann --- samples/bpf/xdp_fwd_kern.c | 5 +++-- samples/bpf/xdp_fwd_user.c | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'samples') diff --git a/samples/bpf/xdp_fwd_kern.c b/samples/bpf/xdp_fwd_kern.c index a7e94e7ff87d..e6ffc4ea06f4 100644 --- a/samples/bpf/xdp_fwd_kern.c +++ b/samples/bpf/xdp_fwd_kern.c @@ -23,7 +23,8 @@ #define IPV6_FLOWINFO_MASK cpu_to_be32(0x0FFFFFFF) -struct bpf_map_def SEC("maps") tx_port = { +/* For TX-traffic redirect requires net_device ifindex to be in this devmap */ +struct bpf_map_def SEC("maps") xdp_tx_ports = { .type = BPF_MAP_TYPE_DEVMAP, .key_size = sizeof(int), .value_size = sizeof(int), @@ -117,7 +118,7 @@ static __always_inline int xdp_fwd_flags(struct xdp_md *ctx, u32 flags) memcpy(eth->h_dest, fib_params.dmac, ETH_ALEN); memcpy(eth->h_source, fib_params.smac, ETH_ALEN); - return bpf_redirect_map(&tx_port, fib_params.ifindex, 0); + return bpf_redirect_map(&xdp_tx_ports, fib_params.ifindex, 0); } return XDP_PASS; diff --git a/samples/bpf/xdp_fwd_user.c b/samples/bpf/xdp_fwd_user.c index 5b46ee12c696..ba012d9f93dd 100644 --- a/samples/bpf/xdp_fwd_user.c +++ b/samples/bpf/xdp_fwd_user.c @@ -113,7 +113,7 @@ int main(int argc, char **argv) return 1; } map_fd = bpf_map__fd(bpf_object__find_map_by_name(obj, - "tx_port")); + "xdp_tx_ports")); if (map_fd < 0) { printf("map not found: %s\n", strerror(map_fd)); return 1; -- cgit v1.2.3-59-g8ed1b From a32a32cb26eb6291125e4eb49b569874ca9a53b5 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Thu, 8 Aug 2019 18:17:42 +0200 Subject: samples/bpf: make xdp_fwd more practically usable via devmap lookup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This address the TODO in samples/bpf/xdp_fwd_kern.c, which points out that the chosen egress index should be checked for existence in the devmap. This can now be done via taking advantage of Toke's work in commit 0cdbb4b09a06 ("devmap: Allow map lookups from eBPF"). This change makes xdp_fwd more practically usable, as this allows for a mixed environment, where IP-forwarding fallback to network stack, if the egress device isn't configured to use XDP. Signed-off-by: Jesper Dangaard Brouer Reviewed-by: David Ahern Reviewed-by: Toke Høiland-Jørgensen Acked-by: Yonghong Song Signed-off-by: Daniel Borkmann --- samples/bpf/xdp_fwd_kern.c | 17 +++++++++++------ samples/bpf/xdp_fwd_user.c | 33 ++++++++++++++++++++++----------- 2 files changed, 33 insertions(+), 17 deletions(-) (limited to 'samples') diff --git a/samples/bpf/xdp_fwd_kern.c b/samples/bpf/xdp_fwd_kern.c index e6ffc4ea06f4..a43d6953c054 100644 --- a/samples/bpf/xdp_fwd_kern.c +++ b/samples/bpf/xdp_fwd_kern.c @@ -104,13 +104,18 @@ static __always_inline int xdp_fwd_flags(struct xdp_md *ctx, u32 flags) rc = bpf_fib_lookup(ctx, &fib_params, sizeof(fib_params), flags); - /* verify egress index has xdp support - * TO-DO bpf_map_lookup_elem(&tx_port, &key) fails with - * cannot pass map_type 14 into func bpf_map_lookup_elem#1: - * NOTE: without verification that egress index supports XDP - * forwarding packets are dropped. - */ if (rc == 0) { + /* Verify egress index has been configured as TX-port. + * (Note: User can still have inserted an egress ifindex that + * doesn't support XDP xmit, which will result in packet drops). + * + * Note: lookup in devmap supported since 0cdbb4b09a0. + * If not supported will fail with: + * cannot pass map_type 14 into func bpf_map_lookup_elem#1: + */ + if (!bpf_map_lookup_elem(&xdp_tx_ports, &fib_params.ifindex)) + return XDP_PASS; + if (h_proto == htons(ETH_P_IP)) ip_decrease_ttl(iph); else if (h_proto == htons(ETH_P_IPV6)) diff --git a/samples/bpf/xdp_fwd_user.c b/samples/bpf/xdp_fwd_user.c index ba012d9f93dd..97ff1dad7669 100644 --- a/samples/bpf/xdp_fwd_user.c +++ b/samples/bpf/xdp_fwd_user.c @@ -27,14 +27,20 @@ #include "libbpf.h" #include - -static int do_attach(int idx, int fd, const char *name) +static int do_attach(int idx, int prog_fd, int map_fd, const char *name) { int err; - err = bpf_set_link_xdp_fd(idx, fd, 0); - if (err < 0) + err = bpf_set_link_xdp_fd(idx, prog_fd, 0); + if (err < 0) { printf("ERROR: failed to attach program to %s\n", name); + return err; + } + + /* Adding ifindex as a possible egress TX port */ + err = bpf_map_update_elem(map_fd, &idx, &idx, 0); + if (err) + printf("ERROR: failed using device %s as TX-port\n", name); return err; } @@ -47,6 +53,9 @@ static int do_detach(int idx, const char *name) if (err < 0) printf("ERROR: failed to detach program from %s\n", name); + /* TODO: Remember to cleanup map, when adding use of shared map + * bpf_map_delete_elem((map_fd, &idx); + */ return err; } @@ -67,10 +76,10 @@ int main(int argc, char **argv) }; const char *prog_name = "xdp_fwd"; struct bpf_program *prog; + int prog_fd, map_fd = -1; char filename[PATH_MAX]; struct bpf_object *obj; int opt, i, idx, err; - int prog_fd, map_fd; int attach = 1; int ret = 0; @@ -103,8 +112,14 @@ int main(int argc, char **argv) return 1; } - if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd)) + err = bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd); + if (err) { + printf("Does kernel support devmap lookup?\n"); + /* If not, the error message will be: + * "cannot pass map_type 14 into func bpf_map_lookup_elem#1" + */ return 1; + } prog = bpf_object__find_program_by_title(obj, prog_name); prog_fd = bpf_program__fd(prog); @@ -119,10 +134,6 @@ int main(int argc, char **argv) return 1; } } - if (attach) { - for (i = 1; i < 64; ++i) - bpf_map_update_elem(map_fd, &i, &i, 0); - } for (i = optind; i < argc; ++i) { idx = if_nametoindex(argv[i]); @@ -138,7 +149,7 @@ int main(int argc, char **argv) if (err) ret = err; } else { - err = do_attach(idx, prog_fd, argv[i]); + err = do_attach(idx, prog_fd, map_fd, argv[i]); if (err) ret = err; } -- cgit v1.2.3-59-g8ed1b From abcce733adb71013997fcb84142a5454ef133616 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Thu, 8 Aug 2019 18:17:47 +0200 Subject: samples/bpf: xdp_fwd explain bpf_fib_lookup return codes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make it clear that this XDP program depend on the network stack to do the ARP resolution. This is connected with the BPF_FIB_LKUP_RET_NO_NEIGH return code from bpf_fib_lookup(). Another common mistake (seen via XDP-tutorial) is that users don't realize that sysctl net.ipv{4,6}.conf.all.forwarding setting is honored by bpf_fib_lookup. Reported-by: Anton Protopopov Signed-off-by: Jesper Dangaard Brouer Reviewed-by: David Ahern Acked-by: Yonghong Song Reviewed-by: Toke Høiland-Jørgensen Signed-off-by: Daniel Borkmann --- samples/bpf/xdp_fwd_kern.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'samples') diff --git a/samples/bpf/xdp_fwd_kern.c b/samples/bpf/xdp_fwd_kern.c index a43d6953c054..701a30f258b1 100644 --- a/samples/bpf/xdp_fwd_kern.c +++ b/samples/bpf/xdp_fwd_kern.c @@ -103,8 +103,23 @@ static __always_inline int xdp_fwd_flags(struct xdp_md *ctx, u32 flags) fib_params.ifindex = ctx->ingress_ifindex; rc = bpf_fib_lookup(ctx, &fib_params, sizeof(fib_params), flags); - - if (rc == 0) { + /* + * Some rc (return codes) from bpf_fib_lookup() are important, + * to understand how this XDP-prog interacts with network stack. + * + * BPF_FIB_LKUP_RET_NO_NEIGH: + * Even if route lookup was a success, then the MAC-addresses are also + * needed. This is obtained from arp/neighbour table, but if table is + * (still) empty then BPF_FIB_LKUP_RET_NO_NEIGH is returned. To avoid + * doing ARP lookup directly from XDP, then send packet to normal + * network stack via XDP_PASS and expect it will do ARP resolution. + * + * BPF_FIB_LKUP_RET_FWD_DISABLED: + * The bpf_fib_lookup respect sysctl net.ipv{4,6}.conf.all.forwarding + * setting, and will return BPF_FIB_LKUP_RET_FWD_DISABLED if not + * enabled this on ingress device. + */ + if (rc == BPF_FIB_LKUP_RET_SUCCESS) { /* Verify egress index has been configured as TX-port. * (Note: User can still have inserted an egress ifindex that * doesn't support XDP xmit, which will result in packet drops). -- cgit v1.2.3-59-g8ed1b