summaryrefslogtreecommitdiff
path: root/samples/bpf/xdp_redirect_cpu_user.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-03-05 08:26:13 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2019-03-05 08:26:13 -0800
commit6456300356433873309a1cae6aa05e77d6b59153 (patch)
tree3158f04f2ca63a48e4d3021aba31aee8f18221cf /samples/bpf/xdp_redirect_cpu_user.c
parentcd2a3bf02625ffad02a6b9f7df758ee36cf12769 (diff)
parent18a4d8bf250a33c015955f0dec27259780ef6448 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
Pull networking updates from David Miller: "Here we go, another merge window full of networking and #ebpf changes: 1) Snoop DHCPACKS in batman-adv to learn MAC/IP pairs in the DHCP range without dealing with floods of ARP traffic, from Linus Lüssing. 2) Throttle buffered multicast packet transmission in mt76, from Felix Fietkau. 3) Support adaptive interrupt moderation in ice, from Brett Creeley. 4) A lot of struct_size conversions, from Gustavo A. R. Silva. 5) Add peek/push/pop commands to bpftool, as well as bash completion, from Stanislav Fomichev. 6) Optimize sk_msg_clone(), from Vakul Garg. 7) Add SO_BINDTOIFINDEX, from David Herrmann. 8) Be more conservative with local resends due to local congestion, from Yuchung Cheng. 9) Allow vetoing of unsupported VXLAN FDBs, from Petr Machata. 10) Add health buffer support to devlink, from Eran Ben Elisha. 11) Add TXQ scheduling API to mac80211, from Toke Høiland-Jørgensen. 12) Add statistics to basic packet scheduler filter, from Cong Wang. 13) Add GRE tunnel support for mlxsw Spectrum-2, from Nir Dotan. 14) Lots of new IP tunneling forwarding tests, also from Nir Dotan. 15) Add 3ad stats to bonding, from Nikolay Aleksandrov. 16) Lots of probing improvements for bpftool, from Quentin Monnet. 17) Various nfp drive #ebpf JIT improvements from Jakub Kicinski. 18) Allow #ebpf programs to access gso_segs from skb shared info, from Eric Dumazet. 19) Add sock_diag support for AF_XDP sockets, from Björn Töpel. 20) Support 22260 iwlwifi devices, from Luca Coelho. 21) Use rbtree for ipv6 defragmentation, from Peter Oskolkov. 22) Add JMP32 instruction class support to #ebpf, from Jiong Wang. 23) Add spinlock support to #ebpf, from Alexei Starovoitov. 24) Support 256-bit keys and TLS 1.3 in ktls, from Dave Watson. 25) Add device infomation API to devlink, from Jakub Kicinski. 26) Add new timestamping socket options which are y2038 safe, from Deepa Dinamani. 27) Add RX checksum offloading for various sh_eth chips, from Sergei Shtylyov. 28) Flow offload infrastructure, from Pablo Neira Ayuso. 29) Numerous cleanups, improvements, and bug fixes to the PHY layer and many drivers from Heiner Kallweit. 30) Lots of changes to try and make packet scheduler classifiers run lockless as much as possible, from Vlad Buslov. 31) Support BCM957504 chip in bnxt_en driver, from Erik Burrows. 32) Add concurrency tests to tc-tests infrastructure, from Vlad Buslov. 33) Add hwmon support to aquantia, from Heiner Kallweit. 34) Allow 64-bit values for SO_MAX_PACING_RATE, from Eric Dumazet. And I would be remiss if I didn't thank the various major networking subsystem maintainers for integrating much of this work before I even saw it. Alexei Starovoitov, Daniel Borkmann, Pablo Neira Ayuso, Johannes Berg, Kalle Valo, and many others. Thank you!" * git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (2207 commits) net/sched: avoid unused-label warning net: ignore sysctl_devconf_inherit_init_net without SYSCTL phy: mdio-mux: fix Kconfig dependencies net: phy: use phy_modify_mmd_changed in genphy_c45_an_config_aneg net: dsa: mv88e6xxx: add call to mv88e6xxx_ports_cmode_init to probe for new DSA framework selftest/net: Remove duplicate header sky2: Disable MSI on Dell Inspiron 1545 and Gateway P-79 net/mlx5e: Update tx reporter status in case channels were successfully opened devlink: Add support for direct reporter health state update devlink: Update reporter state to error even if recover aborted sctp: call iov_iter_revert() after sending ABORT team: Free BPF filter when unregistering netdev ip6mr: Do not call __IP6_INC_STATS() from preemptible context isdn: mISDN: Fix potential NULL pointer dereference of kzalloc net: dsa: mv88e6xxx: support in-band signalling on SGMII ports with external PHYs cxgb4/chtls: Prefix adapter flags with CXGB4 net-sysfs: Switch to bitmap_zalloc() mellanox: Switch to bitmap_zalloc() bpf: add test cases for non-pointer sanitiation logic mlxsw: i2c: Extend initialization by querying resources data ...
Diffstat (limited to 'samples/bpf/xdp_redirect_cpu_user.c')
-rw-r--r--samples/bpf/xdp_redirect_cpu_user.c196
1 files changed, 136 insertions, 60 deletions
diff --git a/samples/bpf/xdp_redirect_cpu_user.c b/samples/bpf/xdp_redirect_cpu_user.c
index 2d23054aaccf..586b294d72d3 100644
--- a/samples/bpf/xdp_redirect_cpu_user.c
+++ b/samples/bpf/xdp_redirect_cpu_user.c
@@ -24,20 +24,26 @@ static const char *__doc__ =
/* How many xdp_progs are defined in _kern.c */
#define MAX_PROG 6
-/* Wanted to get rid of bpf_load.h and fake-"libbpf.h" (and instead
- * use bpf/libbpf.h), but cannot as (currently) needed for XDP
- * attaching to a device via bpf_set_link_xdp_fd()
- */
#include <bpf/bpf.h>
-#include "bpf_load.h"
+#include "bpf/libbpf.h"
#include "bpf_util.h"
static int ifindex = -1;
static char ifname_buf[IF_NAMESIZE];
static char *ifname;
-
-static __u32 xdp_flags;
+static __u32 prog_id;
+
+static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
+static int cpu_map_fd;
+static int rx_cnt_map_fd;
+static int redirect_err_cnt_map_fd;
+static int cpumap_enqueue_cnt_map_fd;
+static int cpumap_kthread_cnt_map_fd;
+static int cpus_available_map_fd;
+static int cpus_count_map_fd;
+static int cpus_iterator_map_fd;
+static int exception_cnt_map_fd;
/* Exit return codes */
#define EXIT_OK 0
@@ -51,27 +57,50 @@ static const struct option long_options[] = {
{"help", no_argument, NULL, 'h' },
{"dev", required_argument, NULL, 'd' },
{"skb-mode", no_argument, NULL, 'S' },
- {"debug", no_argument, NULL, 'D' },
{"sec", required_argument, NULL, 's' },
- {"prognum", required_argument, NULL, 'p' },
+ {"progname", required_argument, NULL, 'p' },
{"qsize", required_argument, NULL, 'q' },
{"cpu", required_argument, NULL, 'c' },
{"stress-mode", no_argument, NULL, 'x' },
{"no-separators", no_argument, NULL, 'z' },
+ {"force", no_argument, NULL, 'F' },
{0, 0, NULL, 0 }
};
static void int_exit(int sig)
{
- fprintf(stderr,
- "Interrupted: Removing XDP program on ifindex:%d device:%s\n",
- ifindex, ifname);
- if (ifindex > -1)
- bpf_set_link_xdp_fd(ifindex, -1, xdp_flags);
+ __u32 curr_prog_id = 0;
+
+ if (ifindex > -1) {
+ if (bpf_get_link_xdp_id(ifindex, &curr_prog_id, xdp_flags)) {
+ printf("bpf_get_link_xdp_id failed\n");
+ exit(EXIT_FAIL);
+ }
+ if (prog_id == curr_prog_id) {
+ fprintf(stderr,
+ "Interrupted: Removing XDP program on ifindex:%d device:%s\n",
+ ifindex, ifname);
+ bpf_set_link_xdp_fd(ifindex, -1, xdp_flags);
+ } else if (!curr_prog_id) {
+ printf("couldn't find a prog id on a given iface\n");
+ } else {
+ printf("program on interface changed, not removing\n");
+ }
+ }
exit(EXIT_OK);
}
-static void usage(char *argv[])
+static void print_avail_progs(struct bpf_object *obj)
+{
+ struct bpf_program *pos;
+
+ bpf_object__for_each_program(pos, obj) {
+ if (bpf_program__is_xdp(pos))
+ printf(" %s\n", bpf_program__title(pos, false));
+ }
+}
+
+static void usage(char *argv[], struct bpf_object *obj)
{
int i;
@@ -89,6 +118,8 @@ static void usage(char *argv[])
long_options[i].val);
printf("\n");
}
+ printf("\n Programs to be used for --progname:\n");
+ print_avail_progs(obj);
printf("\n");
}
@@ -263,7 +294,7 @@ static __u64 calc_errs_pps(struct datarec *r,
static void stats_print(struct stats_record *stats_rec,
struct stats_record *stats_prev,
- int prog_num)
+ char *prog_name)
{
unsigned int nr_cpus = bpf_num_possible_cpus();
double pps = 0, drop = 0, err = 0;
@@ -273,7 +304,7 @@ static void stats_print(struct stats_record *stats_rec,
int i;
/* Header */
- printf("Running XDP/eBPF prog_num:%d\n", prog_num);
+ printf("Running XDP/eBPF prog_name:%s\n", prog_name);
printf("%-15s %-7s %-14s %-11s %-9s\n",
"XDP-cpumap", "CPU:to", "pps", "drop-pps", "extra-info");
@@ -424,20 +455,20 @@ static void stats_collect(struct stats_record *rec)
{
int fd, i;
- fd = map_fd[1]; /* map: rx_cnt */
+ fd = rx_cnt_map_fd;
map_collect_percpu(fd, 0, &rec->rx_cnt);
- fd = map_fd[2]; /* map: redirect_err_cnt */
+ fd = redirect_err_cnt_map_fd;
map_collect_percpu(fd, 1, &rec->redir_err);
- fd = map_fd[3]; /* map: cpumap_enqueue_cnt */
+ fd = cpumap_enqueue_cnt_map_fd;
for (i = 0; i < MAX_CPUS; i++)
map_collect_percpu(fd, i, &rec->enq[i]);
- fd = map_fd[4]; /* map: cpumap_kthread_cnt */
+ fd = cpumap_kthread_cnt_map_fd;
map_collect_percpu(fd, 0, &rec->kthread);
- fd = map_fd[8]; /* map: exception_cnt */
+ fd = exception_cnt_map_fd;
map_collect_percpu(fd, 0, &rec->exception);
}
@@ -462,7 +493,7 @@ static int create_cpu_entry(__u32 cpu, __u32 queue_size,
/* Add a CPU entry to cpumap, as this allocate a cpu entry in
* the kernel for the cpu.
*/
- ret = bpf_map_update_elem(map_fd[0], &cpu, &queue_size, 0);
+ ret = bpf_map_update_elem(cpu_map_fd, &cpu, &queue_size, 0);
if (ret) {
fprintf(stderr, "Create CPU entry failed (err:%d)\n", ret);
exit(EXIT_FAIL_BPF);
@@ -471,23 +502,22 @@ static int create_cpu_entry(__u32 cpu, __u32 queue_size,
/* Inform bpf_prog's that a new CPU is available to select
* from via some control maps.
*/
- /* map_fd[5] = cpus_available */
- ret = bpf_map_update_elem(map_fd[5], &avail_idx, &cpu, 0);
+ ret = bpf_map_update_elem(cpus_available_map_fd, &avail_idx, &cpu, 0);
if (ret) {
fprintf(stderr, "Add to avail CPUs failed\n");
exit(EXIT_FAIL_BPF);
}
/* When not replacing/updating existing entry, bump the count */
- /* map_fd[6] = cpus_count */
- ret = bpf_map_lookup_elem(map_fd[6], &key, &curr_cpus_count);
+ ret = bpf_map_lookup_elem(cpus_count_map_fd, &key, &curr_cpus_count);
if (ret) {
fprintf(stderr, "Failed reading curr cpus_count\n");
exit(EXIT_FAIL_BPF);
}
if (new) {
curr_cpus_count++;
- ret = bpf_map_update_elem(map_fd[6], &key, &curr_cpus_count, 0);
+ ret = bpf_map_update_elem(cpus_count_map_fd, &key,
+ &curr_cpus_count, 0);
if (ret) {
fprintf(stderr, "Failed write curr cpus_count\n");
exit(EXIT_FAIL_BPF);
@@ -510,8 +540,8 @@ static void mark_cpus_unavailable(void)
int ret, i;
for (i = 0; i < MAX_CPUS; i++) {
- /* map_fd[5] = cpus_available */
- ret = bpf_map_update_elem(map_fd[5], &i, &invalid_cpu, 0);
+ ret = bpf_map_update_elem(cpus_available_map_fd, &i,
+ &invalid_cpu, 0);
if (ret) {
fprintf(stderr, "Failed marking CPU unavailable\n");
exit(EXIT_FAIL_BPF);
@@ -531,7 +561,7 @@ static void stress_cpumap(void)
create_cpu_entry(1, 16000, 0, false);
}
-static void stats_poll(int interval, bool use_separators, int prog_num,
+static void stats_poll(int interval, bool use_separators, char *prog_name,
bool stress_mode)
{
struct stats_record *record, *prev;
@@ -547,7 +577,7 @@ static void stats_poll(int interval, bool use_separators, int prog_num,
while (1) {
swap(&prev, &record);
stats_collect(record);
- stats_print(record, prev, prog_num);
+ stats_print(record, prev, prog_name);
sleep(interval);
if (stress_mode)
stress_cpumap();
@@ -557,20 +587,55 @@ static void stats_poll(int interval, bool use_separators, int prog_num,
free_stats_record(prev);
}
+static int init_map_fds(struct bpf_object *obj)
+{
+ cpu_map_fd = bpf_object__find_map_fd_by_name(obj, "cpu_map");
+ rx_cnt_map_fd = bpf_object__find_map_fd_by_name(obj, "rx_cnt");
+ redirect_err_cnt_map_fd =
+ bpf_object__find_map_fd_by_name(obj, "redirect_err_cnt");
+ cpumap_enqueue_cnt_map_fd =
+ bpf_object__find_map_fd_by_name(obj, "cpumap_enqueue_cnt");
+ cpumap_kthread_cnt_map_fd =
+ bpf_object__find_map_fd_by_name(obj, "cpumap_kthread_cnt");
+ cpus_available_map_fd =
+ bpf_object__find_map_fd_by_name(obj, "cpus_available");
+ cpus_count_map_fd = bpf_object__find_map_fd_by_name(obj, "cpus_count");
+ cpus_iterator_map_fd =
+ bpf_object__find_map_fd_by_name(obj, "cpus_iterator");
+ exception_cnt_map_fd =
+ bpf_object__find_map_fd_by_name(obj, "exception_cnt");
+
+ if (cpu_map_fd < 0 || rx_cnt_map_fd < 0 ||
+ redirect_err_cnt_map_fd < 0 || cpumap_enqueue_cnt_map_fd < 0 ||
+ cpumap_kthread_cnt_map_fd < 0 || cpus_available_map_fd < 0 ||
+ cpus_count_map_fd < 0 || cpus_iterator_map_fd < 0 ||
+ exception_cnt_map_fd < 0)
+ return -ENOENT;
+
+ return 0;
+}
+
int main(int argc, char **argv)
{
struct rlimit r = {10 * 1024 * 1024, RLIM_INFINITY};
+ char *prog_name = "xdp_cpu_map5_lb_hash_ip_pairs";
+ struct bpf_prog_load_attr prog_load_attr = {
+ .prog_type = BPF_PROG_TYPE_UNSPEC,
+ };
+ struct bpf_prog_info info = {};
+ __u32 info_len = sizeof(info);
bool use_separators = true;
bool stress_mode = false;
+ struct bpf_program *prog;
+ struct bpf_object *obj;
char filename[256];
- bool debug = false;
int added_cpus = 0;
int longindex = 0;
int interval = 2;
- int prog_num = 5;
int add_cpu = -1;
+ int opt, err;
+ int prog_fd;
__u32 qsize;
- int opt;
/* Notice: choosing he queue size is very important with the
* ixgbe driver, because it's driver page recycling trick is
@@ -581,26 +646,29 @@ int main(int argc, char **argv)
qsize = 128+64;
snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
+ prog_load_attr.file = filename;
if (setrlimit(RLIMIT_MEMLOCK, &r)) {
perror("setrlimit(RLIMIT_MEMLOCK)");
return 1;
}
- if (load_bpf_file(filename)) {
- fprintf(stderr, "ERR in load_bpf_file(): %s", bpf_log_buf);
+ if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd))
return EXIT_FAIL;
- }
- if (!prog_fd[0]) {
- fprintf(stderr, "ERR: load_bpf_file: %s\n", strerror(errno));
+ if (prog_fd < 0) {
+ fprintf(stderr, "ERR: bpf_prog_load_xattr: %s\n",
+ strerror(errno));
+ return EXIT_FAIL;
+ }
+ if (init_map_fds(obj) < 0) {
+ fprintf(stderr, "bpf_object__find_map_fd_by_name failed\n");
return EXIT_FAIL;
}
-
mark_cpus_unavailable();
/* Parse commands line args */
- while ((opt = getopt_long(argc, argv, "hSd:",
+ while ((opt = getopt_long(argc, argv, "hSd:s:p:q:c:xzF",
long_options, &longindex)) != -1) {
switch (opt) {
case 'd':
@@ -624,9 +692,6 @@ int main(int argc, char **argv)
case 'S':
xdp_flags |= XDP_FLAGS_SKB_MODE;
break;
- case 'D':
- debug = true;
- break;
case 'x':
stress_mode = true;
break;
@@ -635,13 +700,7 @@ int main(int argc, char **argv)
break;
case 'p':
/* Selecting eBPF prog to load */
- prog_num = atoi(optarg);
- if (prog_num < 0 || prog_num >= MAX_PROG) {
- fprintf(stderr,
- "--prognum too large err(%d):%s\n",
- errno, strerror(errno));
- goto error;
- }
+ prog_name = optarg;
break;
case 'c':
/* Add multiple CPUs */
@@ -658,24 +717,27 @@ int main(int argc, char **argv)
case 'q':
qsize = atoi(optarg);
break;
+ case 'F':
+ xdp_flags &= ~XDP_FLAGS_UPDATE_IF_NOEXIST;
+ break;
case 'h':
error:
default:
- usage(argv);
+ usage(argv, obj);
return EXIT_FAIL_OPTION;
}
}
/* Required option */
if (ifindex == -1) {
fprintf(stderr, "ERR: required option --dev missing\n");
- usage(argv);
+ usage(argv, obj);
return EXIT_FAIL_OPTION;
}
/* Required option */
if (add_cpu == -1) {
fprintf(stderr, "ERR: required option --cpu missing\n");
fprintf(stderr, " Specify multiple --cpu option to add more\n");
- usage(argv);
+ usage(argv, obj);
return EXIT_FAIL_OPTION;
}
@@ -683,16 +745,30 @@ int main(int argc, char **argv)
signal(SIGINT, int_exit);
signal(SIGTERM, int_exit);
- if (bpf_set_link_xdp_fd(ifindex, prog_fd[prog_num], xdp_flags) < 0) {
+ prog = bpf_object__find_program_by_title(obj, prog_name);
+ if (!prog) {
+ fprintf(stderr, "bpf_object__find_program_by_title failed\n");
+ return EXIT_FAIL;
+ }
+
+ prog_fd = bpf_program__fd(prog);
+ if (prog_fd < 0) {
+ fprintf(stderr, "bpf_program__fd failed\n");
+ return EXIT_FAIL;
+ }
+
+ if (bpf_set_link_xdp_fd(ifindex, prog_fd, xdp_flags) < 0) {
fprintf(stderr, "link set xdp fd failed\n");
return EXIT_FAIL_XDP;
}
- if (debug) {
- printf("Debug-mode reading trace pipe (fix #define DEBUG)\n");
- read_trace_pipe();
+ err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len);
+ if (err) {
+ printf("can't get prog info - %s\n", strerror(errno));
+ return err;
}
+ prog_id = info.id;
- stats_poll(interval, use_separators, prog_num, stress_mode);
+ stats_poll(interval, use_separators, prog_name, stress_mode);
return EXIT_OK;
}