Commit b6803408 authored by David S. Miller's avatar David S. Miller

Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next

Daniel Borkmann says:

====================
pull-request: bpf-next 2018-07-03

The following pull-request contains BPF updates for your *net-next* tree.

The main changes are:

1) Various improvements to bpftool and libbpf, that is, bpftool build
   speed improvements, missing BPF program types added for detection
   by section name, ability to load programs from '.text' section is
   made to work again, and better bash completion handling, from Jakub.

2) Improvements to nfp JIT's map read handling which allows for optimizing
   memcpy from map to packet, from Jiong.

3) New BPF sample is added which demonstrates XDP in combination with
   bpf_perf_event_output() helper to sample packets on all CPUs, from Toke.

4) Add a new BPF kselftest case for tracking connect(2) BPF hooks
   infrastructure in combination with TFO, from Andrey.

5) Extend the XDP/BPF xdp_rxq_info sample code with a cmdline option to
   read payload from packet data in order to use it for benchmarking.
   Also for '--action XDP_TX' option implement swapping of MAC addresses
   to avoid drops on some hardware seen during testing, from Jesper.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 44a4c469 0b9e3d54
...@@ -670,7 +670,7 @@ static int nfp_cpp_memcpy(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) ...@@ -670,7 +670,7 @@ static int nfp_cpp_memcpy(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
xfer_num = round_up(len, 4) / 4; xfer_num = round_up(len, 4) / 4;
if (src_40bit_addr) if (src_40bit_addr)
addr40_offset(nfp_prog, meta->insn.src_reg, off, &src_base, addr40_offset(nfp_prog, meta->insn.src_reg * 2, off, &src_base,
&off); &off);
/* Setup PREV_ALU fields to override memory read length. */ /* Setup PREV_ALU fields to override memory read length. */
...@@ -3299,7 +3299,8 @@ curr_pair_is_memcpy(struct nfp_insn_meta *ld_meta, ...@@ -3299,7 +3299,8 @@ curr_pair_is_memcpy(struct nfp_insn_meta *ld_meta,
if (!is_mbpf_load(ld_meta) || !is_mbpf_store(st_meta)) if (!is_mbpf_load(ld_meta) || !is_mbpf_store(st_meta))
return false; return false;
if (ld_meta->ptr.type != PTR_TO_PACKET) if (ld_meta->ptr.type != PTR_TO_PACKET &&
ld_meta->ptr.type != PTR_TO_MAP_VALUE)
return false; return false;
if (st_meta->ptr.type != PTR_TO_PACKET) if (st_meta->ptr.type != PTR_TO_PACKET)
......
...@@ -52,6 +52,7 @@ hostprogs-y += xdp_adjust_tail ...@@ -52,6 +52,7 @@ hostprogs-y += xdp_adjust_tail
hostprogs-y += xdpsock hostprogs-y += xdpsock
hostprogs-y += xdp_fwd hostprogs-y += xdp_fwd
hostprogs-y += task_fd_query hostprogs-y += task_fd_query
hostprogs-y += xdp_sample_pkts
# Libbpf dependencies # Libbpf dependencies
LIBBPF = $(TOOLS_PATH)/lib/bpf/libbpf.a LIBBPF = $(TOOLS_PATH)/lib/bpf/libbpf.a
...@@ -107,6 +108,7 @@ xdp_adjust_tail-objs := xdp_adjust_tail_user.o ...@@ -107,6 +108,7 @@ xdp_adjust_tail-objs := xdp_adjust_tail_user.o
xdpsock-objs := bpf_load.o xdpsock_user.o xdpsock-objs := bpf_load.o xdpsock_user.o
xdp_fwd-objs := bpf_load.o xdp_fwd_user.o xdp_fwd-objs := bpf_load.o xdp_fwd_user.o
task_fd_query-objs := bpf_load.o task_fd_query_user.o $(TRACE_HELPERS) 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)
# Tell kbuild to always build the programs # Tell kbuild to always build the programs
always := $(hostprogs-y) always := $(hostprogs-y)
...@@ -163,6 +165,7 @@ always += xdp_adjust_tail_kern.o ...@@ -163,6 +165,7 @@ always += xdp_adjust_tail_kern.o
always += xdpsock_kern.o always += xdpsock_kern.o
always += xdp_fwd_kern.o always += xdp_fwd_kern.o
always += task_fd_query_kern.o always += task_fd_query_kern.o
always += xdp_sample_pkts_kern.o
HOSTCFLAGS += -I$(objtree)/usr/include HOSTCFLAGS += -I$(objtree)/usr/include
HOSTCFLAGS += -I$(srctree)/tools/lib/ HOSTCFLAGS += -I$(srctree)/tools/lib/
...@@ -179,6 +182,7 @@ HOSTCFLAGS_spintest_user.o += -I$(srctree)/tools/lib/bpf/ ...@@ -179,6 +182,7 @@ HOSTCFLAGS_spintest_user.o += -I$(srctree)/tools/lib/bpf/
HOSTCFLAGS_trace_event_user.o += -I$(srctree)/tools/lib/bpf/ HOSTCFLAGS_trace_event_user.o += -I$(srctree)/tools/lib/bpf/
HOSTCFLAGS_sampleip_user.o += -I$(srctree)/tools/lib/bpf/ HOSTCFLAGS_sampleip_user.o += -I$(srctree)/tools/lib/bpf/
HOSTCFLAGS_task_fd_query_user.o += -I$(srctree)/tools/lib/bpf/ HOSTCFLAGS_task_fd_query_user.o += -I$(srctree)/tools/lib/bpf/
HOSTCFLAGS_xdp_sample_pkts_user.o += -I$(srctree)/tools/lib/bpf/
HOST_LOADLIBES += $(LIBBPF) -lelf HOST_LOADLIBES += $(LIBBPF) -lelf
HOSTLOADLIBES_tracex4 += -lrt HOSTLOADLIBES_tracex4 += -lrt
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
* Example howto extract XDP RX-queue info * Example howto extract XDP RX-queue info
*/ */
#include <uapi/linux/bpf.h> #include <uapi/linux/bpf.h>
#include <uapi/linux/if_ether.h>
#include <uapi/linux/in.h>
#include "bpf_helpers.h" #include "bpf_helpers.h"
/* Config setup from with userspace /* Config setup from with userspace
...@@ -14,6 +16,12 @@ ...@@ -14,6 +16,12 @@
struct config { struct config {
__u32 action; __u32 action;
int ifindex; int ifindex;
__u32 options;
};
enum cfg_options_flags {
NO_TOUCH = 0x0U,
READ_MEM = 0x1U,
SWAP_MAC = 0x2U,
}; };
struct bpf_map_def SEC("maps") config_map = { struct bpf_map_def SEC("maps") config_map = {
.type = BPF_MAP_TYPE_ARRAY, .type = BPF_MAP_TYPE_ARRAY,
...@@ -45,6 +53,23 @@ struct bpf_map_def SEC("maps") rx_queue_index_map = { ...@@ -45,6 +53,23 @@ struct bpf_map_def SEC("maps") rx_queue_index_map = {
.max_entries = MAX_RXQs + 1, .max_entries = MAX_RXQs + 1,
}; };
static __always_inline
void swap_src_dst_mac(void *data)
{
unsigned short *p = data;
unsigned short dst[3];
dst[0] = p[0];
dst[1] = p[1];
dst[2] = p[2];
p[0] = p[3];
p[1] = p[4];
p[2] = p[5];
p[3] = dst[0];
p[4] = dst[1];
p[5] = dst[2];
}
SEC("xdp_prog0") SEC("xdp_prog0")
int xdp_prognum0(struct xdp_md *ctx) int xdp_prognum0(struct xdp_md *ctx)
{ {
...@@ -90,6 +115,24 @@ int xdp_prognum0(struct xdp_md *ctx) ...@@ -90,6 +115,24 @@ int xdp_prognum0(struct xdp_md *ctx)
if (key == MAX_RXQs) if (key == MAX_RXQs)
rxq_rec->issue++; rxq_rec->issue++;
/* Default: Don't touch packet data, only count packets */
if (unlikely(config->options & (READ_MEM|SWAP_MAC))) {
struct ethhdr *eth = data;
if (eth + 1 > data_end)
return XDP_ABORTED;
/* Avoid compiler removing this: Drop non 802.3 Ethertypes */
if (ntohs(eth->h_proto) < ETH_P_802_3_MIN)
return XDP_ABORTED;
/* XDP_TX requires changing MAC-addrs, else HW may drop.
* Can also be enabled with --swapmac (for test purposes)
*/
if (unlikely(config->options & SWAP_MAC))
swap_src_dst_mac(data);
}
return config->action; return config->action;
} }
......
...@@ -50,6 +50,8 @@ static const struct option long_options[] = { ...@@ -50,6 +50,8 @@ static const struct option long_options[] = {
{"sec", required_argument, NULL, 's' }, {"sec", required_argument, NULL, 's' },
{"no-separators", no_argument, NULL, 'z' }, {"no-separators", no_argument, NULL, 'z' },
{"action", required_argument, NULL, 'a' }, {"action", required_argument, NULL, 'a' },
{"readmem", no_argument, NULL, 'r' },
{"swapmac", no_argument, NULL, 'm' },
{0, 0, NULL, 0 } {0, 0, NULL, 0 }
}; };
...@@ -66,6 +68,12 @@ static void int_exit(int sig) ...@@ -66,6 +68,12 @@ static void int_exit(int sig)
struct config { struct config {
__u32 action; __u32 action;
int ifindex; int ifindex;
__u32 options;
};
enum cfg_options_flags {
NO_TOUCH = 0x0U,
READ_MEM = 0x1U,
SWAP_MAC = 0x2U,
}; };
#define XDP_ACTION_MAX (XDP_TX + 1) #define XDP_ACTION_MAX (XDP_TX + 1)
#define XDP_ACTION_MAX_STRLEN 11 #define XDP_ACTION_MAX_STRLEN 11
...@@ -109,6 +117,18 @@ static void list_xdp_actions(void) ...@@ -109,6 +117,18 @@ static void list_xdp_actions(void)
printf("\n"); printf("\n");
} }
static char* options2str(enum cfg_options_flags flag)
{
if (flag == NO_TOUCH)
return "no_touch";
if (flag & SWAP_MAC)
return "swapmac";
if (flag & READ_MEM)
return "read";
fprintf(stderr, "ERR: Unknown config option flags");
exit(EXIT_FAIL);
}
static void usage(char *argv[]) static void usage(char *argv[])
{ {
int i; int i;
...@@ -305,7 +325,7 @@ static __u64 calc_errs_pps(struct datarec *r, ...@@ -305,7 +325,7 @@ static __u64 calc_errs_pps(struct datarec *r,
static void stats_print(struct stats_record *stats_rec, static void stats_print(struct stats_record *stats_rec,
struct stats_record *stats_prev, struct stats_record *stats_prev,
int action) int action, __u32 cfg_opt)
{ {
unsigned int nr_rxqs = bpf_map__def(rx_queue_index_map)->max_entries; unsigned int nr_rxqs = bpf_map__def(rx_queue_index_map)->max_entries;
unsigned int nr_cpus = bpf_num_possible_cpus(); unsigned int nr_cpus = bpf_num_possible_cpus();
...@@ -316,8 +336,8 @@ static void stats_print(struct stats_record *stats_rec, ...@@ -316,8 +336,8 @@ static void stats_print(struct stats_record *stats_rec,
int i; int i;
/* Header */ /* Header */
printf("\nRunning XDP on dev:%s (ifindex:%d) action:%s\n", printf("\nRunning XDP on dev:%s (ifindex:%d) action:%s options:%s\n",
ifname, ifindex, action2str(action)); ifname, ifindex, action2str(action), options2str(cfg_opt));
/* stats_global_map */ /* stats_global_map */
{ {
...@@ -399,7 +419,7 @@ static inline void swap(struct stats_record **a, struct stats_record **b) ...@@ -399,7 +419,7 @@ static inline void swap(struct stats_record **a, struct stats_record **b)
*b = tmp; *b = tmp;
} }
static void stats_poll(int interval, int action) static void stats_poll(int interval, int action, __u32 cfg_opt)
{ {
struct stats_record *record, *prev; struct stats_record *record, *prev;
...@@ -410,7 +430,7 @@ static void stats_poll(int interval, int action) ...@@ -410,7 +430,7 @@ static void stats_poll(int interval, int action)
while (1) { while (1) {
swap(&prev, &record); swap(&prev, &record);
stats_collect(record); stats_collect(record);
stats_print(record, prev, action); stats_print(record, prev, action, cfg_opt);
sleep(interval); sleep(interval);
} }
...@@ -421,6 +441,7 @@ static void stats_poll(int interval, int action) ...@@ -421,6 +441,7 @@ static void stats_poll(int interval, int action)
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
__u32 cfg_options= NO_TOUCH ; /* Default: Don't touch packet memory */
struct rlimit r = {10 * 1024 * 1024, RLIM_INFINITY}; struct rlimit r = {10 * 1024 * 1024, RLIM_INFINITY};
struct bpf_prog_load_attr prog_load_attr = { struct bpf_prog_load_attr prog_load_attr = {
.prog_type = BPF_PROG_TYPE_XDP, .prog_type = BPF_PROG_TYPE_XDP,
...@@ -435,6 +456,7 @@ int main(int argc, char **argv) ...@@ -435,6 +456,7 @@ int main(int argc, char **argv)
int interval = 2; int interval = 2;
__u32 key = 0; __u32 key = 0;
char action_str_buf[XDP_ACTION_MAX_STRLEN + 1 /* for \0 */] = { 0 }; char action_str_buf[XDP_ACTION_MAX_STRLEN + 1 /* for \0 */] = { 0 };
int action = XDP_PASS; /* Default action */ int action = XDP_PASS; /* Default action */
char *action_str = NULL; char *action_str = NULL;
...@@ -496,6 +518,12 @@ int main(int argc, char **argv) ...@@ -496,6 +518,12 @@ int main(int argc, char **argv)
action_str = (char *)&action_str_buf; action_str = (char *)&action_str_buf;
strncpy(action_str, optarg, XDP_ACTION_MAX_STRLEN); strncpy(action_str, optarg, XDP_ACTION_MAX_STRLEN);
break; break;
case 'r':
cfg_options |= READ_MEM;
break;
case 'm':
cfg_options |= SWAP_MAC;
break;
case 'h': case 'h':
error: error:
default: default:
...@@ -523,6 +551,11 @@ int main(int argc, char **argv) ...@@ -523,6 +551,11 @@ int main(int argc, char **argv)
} }
cfg.action = action; cfg.action = action;
/* XDP_TX requires changing MAC-addrs, else HW may drop */
if (action == XDP_TX)
cfg_options |= SWAP_MAC;
cfg.options = cfg_options;
/* Trick to pretty printf with thousands separators use %' */ /* Trick to pretty printf with thousands separators use %' */
if (use_separators) if (use_separators)
setlocale(LC_NUMERIC, "en_US"); setlocale(LC_NUMERIC, "en_US");
...@@ -542,6 +575,6 @@ int main(int argc, char **argv) ...@@ -542,6 +575,6 @@ int main(int argc, char **argv)
return EXIT_FAIL_XDP; return EXIT_FAIL_XDP;
} }
stats_poll(interval, action); stats_poll(interval, action, cfg_options);
return EXIT_OK; return EXIT_OK;
} }
// SPDX-License-Identifier: GPL-2.0
#include <linux/ptrace.h>
#include <linux/version.h>
#include <uapi/linux/bpf.h>
#include "bpf_helpers.h"
#define SAMPLE_SIZE 64ul
#define MAX_CPUS 128
#define bpf_printk(fmt, ...) \
({ \
char ____fmt[] = fmt; \
bpf_trace_printk(____fmt, sizeof(____fmt), \
##__VA_ARGS__); \
})
struct bpf_map_def SEC("maps") my_map = {
.type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
.key_size = sizeof(int),
.value_size = sizeof(u32),
.max_entries = MAX_CPUS,
};
SEC("xdp_sample")
int xdp_sample_prog(struct xdp_md *ctx)
{
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;
/* Metadata will be in the perf event before the packet data. */
struct S {
u16 cookie;
u16 pkt_len;
} __packed metadata;
if (data < data_end) {
/* The XDP perf_event_output handler will use the upper 32 bits
* of the flags argument as a number of bytes to include of the
* packet payload in the event data. If the size is too big, the
* call to bpf_perf_event_output will fail and return -EFAULT.
*
* See bpf_xdp_event_output in net/core/filter.c.
*
* The BPF_F_CURRENT_CPU flag means that the event output fd
* will be indexed by the CPU number in the event map.
*/
u64 flags = BPF_F_CURRENT_CPU;
u16 sample_size;
int ret;
metadata.cookie = 0xdead;
metadata.pkt_len = (u16)(data_end - data);
sample_size = min(metadata.pkt_len, SAMPLE_SIZE);
flags |= (u64)sample_size << 32;
ret = bpf_perf_event_output(ctx, &my_map, flags,
&metadata, sizeof(metadata));
if (ret)
bpf_printk("perf_event_output failed: %d\n", ret);
}
return XDP_PASS;
}
char _license[] SEC("license") = "GPL";
u32 _version SEC("version") = LINUX_VERSION_CODE;
// SPDX-License-Identifier: GPL-2.0
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <linux/perf_event.h>
#include <linux/bpf.h>
#include <net/if.h>
#include <errno.h>
#include <assert.h>
#include <sys/sysinfo.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <libbpf.h>
#include <bpf/bpf.h>
#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 char *if_name;
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;
}
#define SAMPLE_SIZE 64
static int print_bpf_output(void *data, int size)
{
struct {
__u16 cookie;
__u16 pkt_len;
__u8 pkt_data[SAMPLE_SIZE];
} __packed *e = data;
int i;
if (e->cookie != 0xdead) {
printf("BUG cookie %x sized %d\n",
e->cookie, size);
return LIBBPF_PERF_EVENT_ERROR;
}
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);
exit(0);
}
int main(int argc, char **argv)
{
struct bpf_prog_load_attr prog_load_attr = {
.prog_type = BPF_PROG_TYPE_XDP,
};
struct bpf_object *obj;
struct bpf_map *map;
int prog_fd, map_fd;
char filename[256];
int ret, err, i;
int numcpus;
if (argc < 2) {
printf("Usage: %s <ifname>\n", argv[0]);
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;
if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd))
return 1;
if (!prog_fd) {
printf("load_bpf_file: %s\n", strerror(errno));
return 1;
}
map = bpf_map__next(NULL, obj);
if (!map) {
printf("finding a map in obj file failed\n");
return 1;
}
map_fd = bpf_map__fd(map);
if_idx = if_nametoindex(argv[1]);
if (!if_idx)
if_idx = strtoul(argv[1], NULL, 0);
if (!if_idx) {
fprintf(stderr, "Invalid ifname\n");
return 1;
}
if_name = argv[1];
err = do_attach(if_idx, prog_fd, argv[1]);
if (err)
return err;
if (signal(SIGINT, sig_handler) ||
signal(SIGHUP, sig_handler) ||
signal(SIGTERM, sig_handler)) {
perror("signal");
return 1;
}
test_bpf_perf_event(map_fd, numcpus);
for (i = 0; i < numcpus; i++)
if (perf_event_mmap_header(pmu_fds[i], &headers[i]) < 0)
return 1;
ret = perf_event_poller_multi(pmu_fds, headers, numcpus,
print_bpf_output);
kill(0, SIGINT);
return ret;
}
...@@ -23,7 +23,7 @@ endif ...@@ -23,7 +23,7 @@ endif
LIBBPF = $(BPF_PATH)libbpf.a LIBBPF = $(BPF_PATH)libbpf.a
BPFTOOL_VERSION=$(shell make --no-print-directory -sC ../../.. kernelversion) BPFTOOL_VERSION := $(shell make --no-print-directory -sC ../../.. kernelversion)
$(LIBBPF): FORCE $(LIBBPF): FORCE
$(Q)$(MAKE) -C $(BPF_DIR) OUTPUT=$(OUTPUT) $(OUTPUT)libbpf.a FEATURES_DUMP=$(FEATURE_DUMP_EXPORT) $(Q)$(MAKE) -C $(BPF_DIR) OUTPUT=$(OUTPUT) $(OUTPUT)libbpf.a FEATURES_DUMP=$(FEATURE_DUMP_EXPORT)
......
...@@ -153,6 +153,13 @@ _bpftool() ...@@ -153,6 +153,13 @@ _bpftool()
local cur prev words objword local cur prev words objword
_init_completion || return _init_completion || return
# Deal with options
if [[ ${words[cword]} == -* ]]; then
local c='--version --json --pretty --bpffs'
COMPREPLY=( $( compgen -W "$c" -- "$cur" ) )
return 0
fi
# Deal with simplest keywords # Deal with simplest keywords
case $prev in case $prev in
help|hex|opcodes|visual) help|hex|opcodes|visual)
...@@ -172,20 +179,23 @@ _bpftool() ...@@ -172,20 +179,23 @@ _bpftool()
;; ;;
esac esac
# Search for object and command # Remove all options so completions don't have to deal with them.
local object command cmdword local i
for (( cmdword=1; cmdword < ${#words[@]}-1; cmdword++ )); do for (( i=1; i < ${#words[@]}; )); do
[[ -n $object ]] && command=${words[cmdword]} && break if [[ ${words[i]::1} == - ]]; then
[[ ${words[cmdword]} != -* ]] && object=${words[cmdword]} words=( "${words[@]:0:i}" "${words[@]:i+1}" )
[[ $i -le $cword ]] && cword=$(( cword - 1 ))
else
i=$(( ++i ))
fi
done done
cur=${words[cword]}
prev=${words[cword - 1]}
if [[ -z $object ]]; then local object=${words[1]} command=${words[2]}
if [[ -z $object || $cword -eq 1 ]]; then
case $cur in case $cur in
-*)
local c='--version --json --pretty'
COMPREPLY=( $( compgen -W "$c" -- "$cur" ) )
return 0
;;
*) *)
COMPREPLY=( $( compgen -W "$( bpftool help 2>&1 | \ COMPREPLY=( $( compgen -W "$( bpftool help 2>&1 | \
command sed \ command sed \
......
...@@ -31,8 +31,6 @@ ...@@ -31,8 +31,6 @@
* SOFTWARE. * SOFTWARE.
*/ */
/* Author: Jakub Kicinski <kubakici@wp.pl> */
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
......
/* /*
* Copyright (C) 2017 Netronome Systems, Inc. * Copyright (C) 2017-2018 Netronome Systems, Inc.
* *
* This software is dual licensed under the GNU General License Version 2, * This software is dual licensed under the GNU General License Version 2,
* June 1991 as shown in the file COPYING in the top-level directory of this * June 1991 as shown in the file COPYING in the top-level directory of this
...@@ -31,8 +31,6 @@ ...@@ -31,8 +31,6 @@
* SOFTWARE. * SOFTWARE.
*/ */
/* Author: Jakub Kicinski <kubakici@wp.pl> */
#include <bfd.h> #include <bfd.h>
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
......
...@@ -31,8 +31,6 @@ ...@@ -31,8 +31,6 @@
* SOFTWARE. * SOFTWARE.
*/ */
/* Author: Jakub Kicinski <kubakici@wp.pl> */
#ifndef __BPF_TOOL_H #ifndef __BPF_TOOL_H
#define __BPF_TOOL_H #define __BPF_TOOL_H
......
...@@ -31,8 +31,6 @@ ...@@ -31,8 +31,6 @@
* SOFTWARE. * SOFTWARE.
*/ */
/* Author: Jakub Kicinski <kubakici@wp.pl> */
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
......
/* /*
* Copyright (C) 2017 Netronome Systems, Inc. * Copyright (C) 2017-2018 Netronome Systems, Inc.
* *
* This software is dual licensed under the GNU General License Version 2, * This software is dual licensed under the GNU General License Version 2,
* June 1991 as shown in the file COPYING in the top-level directory of this * June 1991 as shown in the file COPYING in the top-level directory of this
...@@ -31,8 +31,6 @@ ...@@ -31,8 +31,6 @@
* SOFTWARE. * SOFTWARE.
*/ */
/* Author: Jakub Kicinski <kubakici@wp.pl> */
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdarg.h> #include <stdarg.h>
......
...@@ -234,6 +234,7 @@ struct bpf_object { ...@@ -234,6 +234,7 @@ struct bpf_object {
size_t nr_maps; size_t nr_maps;
bool loaded; bool loaded;
bool has_pseudo_calls;
/* /*
* Information when doing elf related work. Only valid if fd * Information when doing elf related work. Only valid if fd
...@@ -400,10 +401,6 @@ bpf_object__init_prog_names(struct bpf_object *obj) ...@@ -400,10 +401,6 @@ bpf_object__init_prog_names(struct bpf_object *obj)
const char *name = NULL; const char *name = NULL;
prog = &obj->programs[pi]; prog = &obj->programs[pi];
if (prog->idx == obj->efile.text_shndx) {
name = ".text";
goto skip_search;
}
for (si = 0; si < symbols->d_size / sizeof(GElf_Sym) && !name; for (si = 0; si < symbols->d_size / sizeof(GElf_Sym) && !name;
si++) { si++) {
...@@ -426,12 +423,15 @@ bpf_object__init_prog_names(struct bpf_object *obj) ...@@ -426,12 +423,15 @@ bpf_object__init_prog_names(struct bpf_object *obj)
} }
} }
if (!name && prog->idx == obj->efile.text_shndx)
name = ".text";
if (!name) { if (!name) {
pr_warning("failed to find sym for prog %s\n", pr_warning("failed to find sym for prog %s\n",
prog->section_name); prog->section_name);
return -EINVAL; return -EINVAL;
} }
skip_search:
prog->name = strdup(name); prog->name = strdup(name);
if (!prog->name) { if (!prog->name) {
pr_warning("failed to allocate memory for prog sym %s\n", pr_warning("failed to allocate memory for prog sym %s\n",
...@@ -981,6 +981,7 @@ bpf_program__collect_reloc(struct bpf_program *prog, GElf_Shdr *shdr, ...@@ -981,6 +981,7 @@ bpf_program__collect_reloc(struct bpf_program *prog, GElf_Shdr *shdr,
prog->reloc_desc[i].type = RELO_CALL; prog->reloc_desc[i].type = RELO_CALL;
prog->reloc_desc[i].insn_idx = insn_idx; prog->reloc_desc[i].insn_idx = insn_idx;
prog->reloc_desc[i].text_off = sym.st_value; prog->reloc_desc[i].text_off = sym.st_value;
obj->has_pseudo_calls = true;
continue; continue;
} }
...@@ -1426,6 +1427,12 @@ bpf_program__load(struct bpf_program *prog, ...@@ -1426,6 +1427,12 @@ bpf_program__load(struct bpf_program *prog,
return err; return err;
} }
static bool bpf_program__is_function_storage(struct bpf_program *prog,
struct bpf_object *obj)
{
return prog->idx == obj->efile.text_shndx && obj->has_pseudo_calls;
}
static int static int
bpf_object__load_progs(struct bpf_object *obj) bpf_object__load_progs(struct bpf_object *obj)
{ {
...@@ -1433,7 +1440,7 @@ bpf_object__load_progs(struct bpf_object *obj) ...@@ -1433,7 +1440,7 @@ bpf_object__load_progs(struct bpf_object *obj)
int err; int err;
for (i = 0; i < obj->nr_programs; i++) { for (i = 0; i < obj->nr_programs; i++) {
if (obj->programs[i].idx == obj->efile.text_shndx) if (bpf_program__is_function_storage(&obj->programs[i], obj))
continue; continue;
err = bpf_program__load(&obj->programs[i], err = bpf_program__load(&obj->programs[i],
obj->license, obj->license,
...@@ -1858,8 +1865,8 @@ void *bpf_object__priv(struct bpf_object *obj) ...@@ -1858,8 +1865,8 @@ void *bpf_object__priv(struct bpf_object *obj)
return obj ? obj->priv : ERR_PTR(-EINVAL); return obj ? obj->priv : ERR_PTR(-EINVAL);
} }
struct bpf_program * static struct bpf_program *
bpf_program__next(struct bpf_program *prev, struct bpf_object *obj) __bpf_program__next(struct bpf_program *prev, struct bpf_object *obj)
{ {
size_t idx; size_t idx;
...@@ -1880,6 +1887,18 @@ bpf_program__next(struct bpf_program *prev, struct bpf_object *obj) ...@@ -1880,6 +1887,18 @@ bpf_program__next(struct bpf_program *prev, struct bpf_object *obj)
return &obj->programs[idx]; return &obj->programs[idx];
} }
struct bpf_program *
bpf_program__next(struct bpf_program *prev, struct bpf_object *obj)
{
struct bpf_program *prog = prev;
do {
prog = __bpf_program__next(prog, obj);
} while (prog && bpf_program__is_function_storage(prog, obj));
return prog;
}
int bpf_program__set_priv(struct bpf_program *prog, void *priv, int bpf_program__set_priv(struct bpf_program *prog, void *priv,
bpf_program_clear_priv_t clear_priv) bpf_program_clear_priv_t clear_priv)
{ {
...@@ -1896,6 +1915,11 @@ void *bpf_program__priv(struct bpf_program *prog) ...@@ -1896,6 +1915,11 @@ void *bpf_program__priv(struct bpf_program *prog)
return prog ? prog->priv : ERR_PTR(-EINVAL); return prog ? prog->priv : ERR_PTR(-EINVAL);
} }
void bpf_program__set_ifindex(struct bpf_program *prog, __u32 ifindex)
{
prog->prog_ifindex = ifindex;
}
const char *bpf_program__title(struct bpf_program *prog, bool needs_copy) const char *bpf_program__title(struct bpf_program *prog, bool needs_copy)
{ {
const char *title; const char *title;
...@@ -2037,9 +2061,11 @@ static const struct { ...@@ -2037,9 +2061,11 @@ static const struct {
BPF_PROG_SEC("lwt_in", BPF_PROG_TYPE_LWT_IN), BPF_PROG_SEC("lwt_in", BPF_PROG_TYPE_LWT_IN),
BPF_PROG_SEC("lwt_out", BPF_PROG_TYPE_LWT_OUT), BPF_PROG_SEC("lwt_out", BPF_PROG_TYPE_LWT_OUT),
BPF_PROG_SEC("lwt_xmit", BPF_PROG_TYPE_LWT_XMIT), BPF_PROG_SEC("lwt_xmit", BPF_PROG_TYPE_LWT_XMIT),
BPF_PROG_SEC("lwt_seg6local", BPF_PROG_TYPE_LWT_SEG6LOCAL),
BPF_PROG_SEC("sockops", BPF_PROG_TYPE_SOCK_OPS), BPF_PROG_SEC("sockops", BPF_PROG_TYPE_SOCK_OPS),
BPF_PROG_SEC("sk_skb", BPF_PROG_TYPE_SK_SKB), BPF_PROG_SEC("sk_skb", BPF_PROG_TYPE_SK_SKB),
BPF_PROG_SEC("sk_msg", BPF_PROG_TYPE_SK_MSG), BPF_PROG_SEC("sk_msg", BPF_PROG_TYPE_SK_MSG),
BPF_PROG_SEC("lirc_mode2", BPF_PROG_TYPE_LIRC_MODE2),
BPF_SA_PROG_SEC("cgroup/bind4", BPF_CGROUP_INET4_BIND), BPF_SA_PROG_SEC("cgroup/bind4", BPF_CGROUP_INET4_BIND),
BPF_SA_PROG_SEC("cgroup/bind6", BPF_CGROUP_INET6_BIND), BPF_SA_PROG_SEC("cgroup/bind6", BPF_CGROUP_INET6_BIND),
BPF_SA_PROG_SEC("cgroup/connect4", BPF_CGROUP_INET4_CONNECT), BPF_SA_PROG_SEC("cgroup/connect4", BPF_CGROUP_INET4_CONNECT),
...@@ -2120,6 +2146,11 @@ void *bpf_map__priv(struct bpf_map *map) ...@@ -2120,6 +2146,11 @@ void *bpf_map__priv(struct bpf_map *map)
return map ? map->priv : ERR_PTR(-EINVAL); return map ? map->priv : ERR_PTR(-EINVAL);
} }
void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex)
{
map->map_ifindex = ifindex;
}
struct bpf_map * struct bpf_map *
bpf_map__next(struct bpf_map *prev, struct bpf_object *obj) bpf_map__next(struct bpf_map *prev, struct bpf_object *obj)
{ {
...@@ -2235,7 +2266,7 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr, ...@@ -2235,7 +2266,7 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,
bpf_program__set_expected_attach_type(prog, bpf_program__set_expected_attach_type(prog,
expected_attach_type); expected_attach_type);
if (prog->idx != obj->efile.text_shndx && !first_prog) if (!bpf_program__is_function_storage(prog, obj) && !first_prog)
first_prog = prog; first_prog = prog;
} }
......
...@@ -109,6 +109,7 @@ int bpf_program__set_priv(struct bpf_program *prog, void *priv, ...@@ -109,6 +109,7 @@ int bpf_program__set_priv(struct bpf_program *prog, void *priv,
bpf_program_clear_priv_t clear_priv); bpf_program_clear_priv_t clear_priv);
void *bpf_program__priv(struct bpf_program *prog); void *bpf_program__priv(struct bpf_program *prog);
void bpf_program__set_ifindex(struct bpf_program *prog, __u32 ifindex);
const char *bpf_program__title(struct bpf_program *prog, bool needs_copy); const char *bpf_program__title(struct bpf_program *prog, bool needs_copy);
...@@ -251,6 +252,7 @@ typedef void (*bpf_map_clear_priv_t)(struct bpf_map *, void *); ...@@ -251,6 +252,7 @@ typedef void (*bpf_map_clear_priv_t)(struct bpf_map *, void *);
int bpf_map__set_priv(struct bpf_map *map, void *priv, int bpf_map__set_priv(struct bpf_map *map, void *priv,
bpf_map_clear_priv_t clear_priv); bpf_map_clear_priv_t clear_priv);
void *bpf_map__priv(struct bpf_map *map); void *bpf_map__priv(struct bpf_map *map);
void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex);
int bpf_map__pin(struct bpf_map *map, const char *path); int bpf_map__pin(struct bpf_map *map, const char *path);
long libbpf_get_error(const void *ptr); long libbpf_get_error(const void *ptr);
......
...@@ -998,8 +998,9 @@ int init_pktinfo(int domain, struct cmsghdr *cmsg) ...@@ -998,8 +998,9 @@ int init_pktinfo(int domain, struct cmsghdr *cmsg)
return 0; return 0;
} }
static int sendmsg_to_server(const struct sockaddr_storage *addr, static int sendmsg_to_server(int type, const struct sockaddr_storage *addr,
socklen_t addr_len, int set_cmsg, int *syscall_err) socklen_t addr_len, int set_cmsg, int flags,
int *syscall_err)
{ {
union { union {
char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
...@@ -1022,7 +1023,7 @@ static int sendmsg_to_server(const struct sockaddr_storage *addr, ...@@ -1022,7 +1023,7 @@ static int sendmsg_to_server(const struct sockaddr_storage *addr,
goto err; goto err;
} }
fd = socket(domain, SOCK_DGRAM, 0); fd = socket(domain, type, 0);
if (fd == -1) { if (fd == -1) {
log_err("Failed to create client socket"); log_err("Failed to create client socket");
goto err; goto err;
...@@ -1052,7 +1053,7 @@ static int sendmsg_to_server(const struct sockaddr_storage *addr, ...@@ -1052,7 +1053,7 @@ static int sendmsg_to_server(const struct sockaddr_storage *addr,
} }
} }
if (sendmsg(fd, &hdr, 0) != sizeof(data)) { if (sendmsg(fd, &hdr, flags) != sizeof(data)) {
log_err("Fail to send message to server"); log_err("Fail to send message to server");
*syscall_err = errno; *syscall_err = errno;
goto err; goto err;
...@@ -1066,6 +1067,15 @@ static int sendmsg_to_server(const struct sockaddr_storage *addr, ...@@ -1066,6 +1067,15 @@ static int sendmsg_to_server(const struct sockaddr_storage *addr,
return fd; return fd;
} }
static int fastconnect_to_server(const struct sockaddr_storage *addr,
socklen_t addr_len)
{
int sendmsg_err;
return sendmsg_to_server(SOCK_STREAM, addr, addr_len, /*set_cmsg*/0,
MSG_FASTOPEN, &sendmsg_err);
}
static int recvmsg_from_client(int sockfd, struct sockaddr_storage *src_addr) static int recvmsg_from_client(int sockfd, struct sockaddr_storage *src_addr)
{ {
struct timeval tv; struct timeval tv;
...@@ -1185,6 +1195,20 @@ static int run_connect_test_case(const struct sock_addr_test *test) ...@@ -1185,6 +1195,20 @@ static int run_connect_test_case(const struct sock_addr_test *test)
if (cmp_local_ip(clientfd, &expected_src_addr)) if (cmp_local_ip(clientfd, &expected_src_addr))
goto err; goto err;
if (test->type == SOCK_STREAM) {
/* Test TCP Fast Open scenario */
clientfd = fastconnect_to_server(&requested_addr, addr_len);
if (clientfd == -1)
goto err;
/* Make sure src and dst addrs were overridden properly */
if (cmp_peer_addr(clientfd, &expected_addr))
goto err;
if (cmp_local_ip(clientfd, &expected_src_addr))
goto err;
}
goto out; goto out;
err: err:
err = -1; err = -1;
...@@ -1222,8 +1246,9 @@ static int run_sendmsg_test_case(const struct sock_addr_test *test) ...@@ -1222,8 +1246,9 @@ static int run_sendmsg_test_case(const struct sock_addr_test *test)
if (clientfd >= 0) if (clientfd >= 0)
close(clientfd); close(clientfd);
clientfd = sendmsg_to_server(&requested_addr, addr_len, clientfd = sendmsg_to_server(test->type, &requested_addr,
set_cmsg, &err); addr_len, set_cmsg, /*flags*/0,
&err);
if (err) if (err)
goto out; goto out;
else if (clientfd == -1) else if (clientfd == -1)
......
...@@ -88,7 +88,7 @@ static int page_size; ...@@ -88,7 +88,7 @@ static int page_size;
static int page_cnt = 8; static int page_cnt = 8;
static struct perf_event_mmap_page *header; static struct perf_event_mmap_page *header;
int perf_event_mmap(int fd) int perf_event_mmap_header(int fd, struct perf_event_mmap_page **header)
{ {
void *base; void *base;
int mmap_size; int mmap_size;
...@@ -102,10 +102,15 @@ int perf_event_mmap(int fd) ...@@ -102,10 +102,15 @@ int perf_event_mmap(int fd)
return -1; return -1;
} }
header = base; *header = base;
return 0; return 0;
} }
int perf_event_mmap(int fd)
{
return perf_event_mmap_header(fd, &header);
}
static int perf_event_poll(int fd) static int perf_event_poll(int fd)
{ {
struct pollfd pfd = { .fd = fd, .events = POLLIN }; struct pollfd pfd = { .fd = fd, .events = POLLIN };
...@@ -163,3 +168,42 @@ int perf_event_poller(int fd, perf_event_print_fn output_fn) ...@@ -163,3 +168,42 @@ int perf_event_poller(int fd, perf_event_print_fn output_fn)
return ret; return ret;
} }
int perf_event_poller_multi(int *fds, struct perf_event_mmap_page **headers,
int num_fds, perf_event_print_fn output_fn)
{
enum bpf_perf_event_ret ret;
struct pollfd *pfds;
void *buf = NULL;
size_t len = 0;
int i;
pfds = calloc(num_fds, sizeof(*pfds));
if (!pfds)
return LIBBPF_PERF_EVENT_ERROR;
for (i = 0; i < num_fds; i++) {
pfds[i].fd = fds[i];
pfds[i].events = POLLIN;
}
for (;;) {
poll(pfds, num_fds, 1000);
for (i = 0; i < num_fds; i++) {
if (!pfds[i].revents)
continue;
ret = bpf_perf_event_read_simple(headers[i],
page_cnt * page_size,
page_size, &buf, &len,
bpf_perf_event_print,
output_fn);
if (ret != LIBBPF_PERF_EVENT_CONT)
break;
}
}
free(buf);
free(pfds);
return ret;
}
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#define __TRACE_HELPER_H #define __TRACE_HELPER_H
#include <libbpf.h> #include <libbpf.h>
#include <linux/perf_event.h>
struct ksym { struct ksym {
long addr; long addr;
...@@ -16,6 +17,9 @@ long ksym_get_addr(const char *name); ...@@ -16,6 +17,9 @@ long ksym_get_addr(const char *name);
typedef enum bpf_perf_event_ret (*perf_event_print_fn)(void *data, int size); typedef enum bpf_perf_event_ret (*perf_event_print_fn)(void *data, int size);
int perf_event_mmap(int fd); int perf_event_mmap(int fd);
int perf_event_mmap_header(int fd, struct perf_event_mmap_page **header);
/* return LIBBPF_PERF_EVENT_DONE or LIBBPF_PERF_EVENT_ERROR */ /* return LIBBPF_PERF_EVENT_DONE or LIBBPF_PERF_EVENT_ERROR */
int perf_event_poller(int fd, perf_event_print_fn output_fn); int perf_event_poller(int fd, perf_event_print_fn output_fn);
int perf_event_poller_multi(int *fds, struct perf_event_mmap_page **headers,
int num_fds, perf_event_print_fn output_fn);
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment