From patchwork Wed Apr 25 18:34:49 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Ahern X-Patchwork-Id: 904674 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="Da+HQyLl"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 40WTQs3lL3z9ry1 for ; Thu, 26 Apr 2018 04:35:33 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756223AbeDYSfb (ORCPT ); Wed, 25 Apr 2018 14:35:31 -0400 Received: from mail-pf0-f194.google.com ([209.85.192.194]:47093 "EHLO mail-pf0-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756120AbeDYSfQ (ORCPT ); Wed, 25 Apr 2018 14:35:16 -0400 Received: by mail-pf0-f194.google.com with SMTP id h69so15959178pfe.13 for ; Wed, 25 Apr 2018 11:35:16 -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; bh=eOh3OjaMHNbbUTN4YQl3aNFMYGjDbjQqa3ZNDVbSvWM=; b=Da+HQyLlIcS0fFAYPWe/FhPAFsX5w0AWKyY0x1TbV+ynz66VGFSg5VtSpDHOBMKIGj vdBMbAkgH/+7HP2Q2XSqOBbUULFZJWu2hvTcuYo9MOJfNaHbkPdz3tppjhYCovJAdZgA 3Q2BpQhrRN/Jx18jgSxIwS7D2ocrAuZeTioVLcUgbXC5/S21/UUI0iBs5rAD/LNVnpAA O5ErPYM9ZOIdEJ2Gc5vTG/vlO383yINt3wiXwI1Kh63bqqhfcy/Ypf1FJJ7qXgmufiXA 6bv3ClRpi7cbIxUd+9XgEgS8xTmjti5II7r4Kd0TV2802yiZIYIA1ulif3+cHJG3uSaz l1sw== 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; bh=eOh3OjaMHNbbUTN4YQl3aNFMYGjDbjQqa3ZNDVbSvWM=; b=jVnt0HxhDAeXh+xp9Tw5tj6FQNxqEoWfVI5YX8Ec7qb9m2rs7CqPK+ZLHGZGjUuLF5 wPI6/2tooDYaffE78WNjgjX/li4EzqwGLLjts/1Pfw/nRLgxv/kp5wDynFHpdCggI1rB SvTNMJg3JIM1UiUVmX4lpicRexYaxMPpBumvzBUTlMcZRg7tY2K8xUwwEoGk6+HxxwrZ CzFZJq1myIxelqKzl2Te5y99kxFIjodMI13UC71OBgcJw7CFFnVEPfL0Pc2O9BXPNM5m ur/O8SXzchtV/OxDJqdcNQvohabE/bSQQEQCxoL8RUr0HETmh9M9VPNTg+sD1ye3Uzkl Qi5A== X-Gm-Message-State: ALQs6tD2EIS4eTZDGs1BGLniyIIcILDGGWiCn9ZYaAc/Kg1UVtQhZCWb M69DbJpt/8w4y/kZFZIW9/wcUw== X-Google-Smtp-Source: AIpwx49PWSZkX2HrBZ33bvYKe7L4U6IKpzKQ2rHmgG1lmy3oYeMz33tial8vfClLZfCG57UF18tOKA== X-Received: by 10.99.143.69 with SMTP id r5mr24961514pgn.159.1524681315278; Wed, 25 Apr 2018 11:35:15 -0700 (PDT) Received: from kenny.it.cumulusnetworks.com. (fw.cumulusnetworks.com. [216.129.126.126]) by smtp.googlemail.com with ESMTPSA id e83sm47492377pfd.175.2018.04.25.11.35.13 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 25 Apr 2018 11:35:14 -0700 (PDT) From: David Ahern To: netdev@vger.kernel.org, borkmann@iogearbox.net, ast@kernel.org Cc: shm@cumulusnetworks.com, roopa@cumulusnetworks.com, brouer@redhat.com, toke@toke.dk, john.fastabend@gmail.com, David Ahern Subject: [RFC bpf-next 9/9] samples/bpf: Add examples of ipv4 and ipv6 forwarding in XDP Date: Wed, 25 Apr 2018 11:34:49 -0700 Message-Id: <20180425183449.25134-10-dsahern@gmail.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20180425183449.25134-1-dsahern@gmail.com> References: <20180425183449.25134-1-dsahern@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Signed-off-by: David Ahern --- samples/bpf/Makefile | 4 + samples/bpf/xdp_fwd_kern.c | 110 ++++++++++++++++++++++++ samples/bpf/xdp_fwd_user.c | 136 ++++++++++++++++++++++++++++++ tools/testing/selftests/bpf/bpf_helpers.h | 3 + 4 files changed, 253 insertions(+) create mode 100644 samples/bpf/xdp_fwd_kern.c create mode 100644 samples/bpf/xdp_fwd_user.c diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index aa8c392e2e52..c90d2ff74873 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -45,6 +45,7 @@ hostprogs-y += xdp_rxq_info hostprogs-y += syscall_tp hostprogs-y += cpustat hostprogs-y += xdp_adjust_tail +hostprogs-y += xdp_fwd # Libbpf dependencies LIBBPF := ../../tools/lib/bpf/bpf.o ../../tools/lib/bpf/nlattr.o @@ -97,6 +98,7 @@ xdp_rxq_info-objs := bpf_load.o $(LIBBPF) xdp_rxq_info_user.o syscall_tp-objs := bpf_load.o $(LIBBPF) syscall_tp_user.o cpustat-objs := bpf_load.o $(LIBBPF) cpustat_user.o xdp_adjust_tail-objs := bpf_load.o $(LIBBPF) xdp_adjust_tail_user.o +xdp_fwd-objs := bpf_load.o $(LIBBPF) xdp_fwd_user.o # Tell kbuild to always build the programs always := $(hostprogs-y) @@ -151,6 +153,7 @@ always += xdp2skb_meta_kern.o always += syscall_tp_kern.o always += cpustat_kern.o always += xdp_adjust_tail_kern.o +always += xdp_fwd_kern.o HOSTCFLAGS += -I$(objtree)/usr/include HOSTCFLAGS += -I$(srctree)/tools/lib/ @@ -197,6 +200,7 @@ HOSTLOADLIBES_xdp_rxq_info += -lelf HOSTLOADLIBES_syscall_tp += -lelf HOSTLOADLIBES_cpustat += -lelf HOSTLOADLIBES_xdp_adjust_tail += -lelf +HOSTLOADLIBES_xdp_fwd += -lelf # Allows pointing LLC/CLANG to a LLVM backend with bpf support, redefine on cmdline: # make samples/bpf/ LLC=~/git/llvm/build/bin/llc CLANG=~/git/llvm/build/bin/clang diff --git a/samples/bpf/xdp_fwd_kern.c b/samples/bpf/xdp_fwd_kern.c new file mode 100644 index 000000000000..4012c073fc45 --- /dev/null +++ b/samples/bpf/xdp_fwd_kern.c @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2017-18 David Ahern + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ +#define KBUILD_MODNAME "foo" +#include +#include +#include +#include +#include +#include +#include + +#include "bpf_helpers.h" + +#define IPV6_FLOWINFO_MASK cpu_to_be32(0x0FFFFFFF) + +struct bpf_map_def SEC("maps") tx_port = { + .type = BPF_MAP_TYPE_DEVMAP, + .key_size = sizeof(int), + .value_size = sizeof(int), + .max_entries = 64, +}; + +static __always_inline int xdp_fwd_flags(struct xdp_md *ctx, u32 flags) +{ + void *data_end = (void *)(long)ctx->data_end; + void *data = (void *)(long)ctx->data; + struct bpf_fib_lookup fib_params; + struct ethhdr *eth = data; + int out_index; + u16 h_proto; + u64 nh_off; + + nh_off = sizeof(*eth); + if (data + nh_off > data_end) + return XDP_DROP; + + __builtin_memset(&fib_params, 0, sizeof(fib_params)); + + h_proto = eth->h_proto; + if (h_proto == htons(ETH_P_IP)) { + struct iphdr *iph = data + nh_off; + + if (iph + 1 > data_end) + return XDP_DROP; + + fib_params.family = AF_INET; + fib_params.tos = iph->tos; + fib_params.l4_protocol = iph->protocol; + fib_params.sport = 0; + fib_params.dport = 0; + fib_params.tot_len = ntohs(iph->tot_len); + fib_params.ipv4_src = iph->saddr; + fib_params.ipv4_dst = iph->daddr; + } else if (h_proto == htons(ETH_P_IPV6)) { + struct ipv6hdr *iph = data + nh_off; + + if (iph + 1 > data_end) + return XDP_DROP; + + fib_params.family = AF_INET6; + fib_params.flowlabel = *(__be32 *)iph & IPV6_FLOWINFO_MASK; + fib_params.l4_protocol = iph->nexthdr; + fib_params.sport = 0; + fib_params.dport = 0; + fib_params.tot_len = ntohs(iph->payload_len); + fib_params.ipv6_src = iph->saddr; + fib_params.ipv6_dst = iph->daddr; + } else { + return XDP_PASS; + } + + fib_params.ifindex = ctx->ingress_ifindex; + + out_index = 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: + if (out_index > 0) { + memcpy(eth->h_dest, fib_params.dmac, ETH_ALEN); + memcpy(eth->h_source, fib_params.smac, ETH_ALEN); + return bpf_redirect_map(&tx_port, out_index, 0); + } + + return XDP_PASS; +} + +SEC("xdp_fwd") +int xdp_fwd_prog(struct xdp_md *ctx) +{ + return xdp_fwd_flags(ctx, 0); +} + +SEC("xdp_fwd_direct") +int xdp_fwd_direct_prog(struct xdp_md *ctx) +{ + return xdp_fwd_flags(ctx, BPF_FIB_LOOKUP_DIRECT); +} + +char _license[] SEC("license") = "GPL"; diff --git a/samples/bpf/xdp_fwd_user.c b/samples/bpf/xdp_fwd_user.c new file mode 100644 index 000000000000..9c6606f57126 --- /dev/null +++ b/samples/bpf/xdp_fwd_user.c @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2017-18 David Ahern + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bpf_load.h" +#include "bpf_util.h" +#include "libbpf.h" + + +static int do_attach(int idx, int fd, const char *name) +{ + int err; + + err = bpf_set_link_xdp_fd(idx, fd, 0); + if (err < 0) + printf("ERROR: failed to attach program to %s\n", name); + + return err; +} + +static int do_detach(int idx, const char *name) +{ + int err; + + err = bpf_set_link_xdp_fd(idx, -1, 0); + if (err < 0) + printf("ERROR: failed to detach program from %s\n", name); + + return err; +} + +static void usage(const char *prog) +{ + fprintf(stderr, + "usage: %s [OPTS] interface-list\n" + "\nOPTS:\n" + " -d detach program\n" + " -D direct table lookups (skip fib rules)\n", + prog); +} + +int main(int argc, char **argv) +{ + char filename[PATH_MAX]; + int opt, i, idx, err; + int prog_id = 0; + int attach = 1; + int ret = 0; + + while ((opt = getopt(argc, argv, ":dD")) != -1) { + switch (opt) { + case 'd': + attach = 0; + break; + case 'D': + prog_id = 1; + break; + default: + usage(basename(argv[0])); + return 1; + } + } + + if (optind == argc) { + usage(basename(argv[0])); + return 1; + } + + if (attach) { + snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); + + if (access(filename, O_RDONLY) < 0) { + printf("error accessing file %s: %s\n", + filename, strerror(errno)); + return 1; + } + + if (load_bpf_file(filename)) { + printf("%s", bpf_log_buf); + return 1; + } + + if (!prog_fd[prog_id]) { + printf("load_bpf_file: %s\n", strerror(errno)); + return 1; + } + } + if (attach) { + for (i = 1; i < 64; ++i) + bpf_map_update_elem(map_fd[0], &i, &i, 0); + } + + for (i = optind; i < argc; ++i) { + idx = if_nametoindex(argv[i]); + if (!idx) + idx = strtoul(argv[i], NULL, 0); + + if (!idx) { + fprintf(stderr, "Invalid arg\n"); + return 1; + } + if (!attach) { + err = do_detach(idx, argv[i]); + if (err) + ret = err; + } else { + err = do_attach(idx, prog_fd[prog_id], argv[i]); + if (err) + ret = err; + } + } + + return ret; +} diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h index 69d7b918e66a..4407766a5950 100644 --- a/tools/testing/selftests/bpf/bpf_helpers.h +++ b/tools/testing/selftests/bpf/bpf_helpers.h @@ -101,6 +101,9 @@ static int (*bpf_xdp_adjust_tail)(void *ctx, int offset) = static int (*bpf_skb_get_xfrm_state)(void *ctx, int index, void *state, int size, int flags) = (void *) BPF_FUNC_skb_get_xfrm_state; +static int (*bpf_fib_lookup)(void *ctx, struct bpf_fib_lookup *params, + int plen, __u32 flags) = + (void *) BPF_FUNC_fib_lookup; /* llvm builtin functions that eBPF C program may use to * emit BPF_LD_ABS and BPF_LD_IND instructions