Skip to content

Commit

Permalink
bpf: Add tests and samples for LWT-BPF
Browse files Browse the repository at this point in the history
Adds a series of tests to verify the functionality of attaching
BPF programs at LWT hooks.

Also adds a sample which collects a histogram of packet sizes which
pass through an LWT hook.

$ ./lwt_len_hist.sh
Starting netserver with host 'IN(6)ADDR_ANY' port '12865' and family AF_UNSPEC
MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 192.168.253.2 () port 0 AF_INET : demo
Recv   Send    Send
Socket Socket  Message  Elapsed
Size   Size    Size     Time     Throughput
bytes  bytes   bytes    secs.    10^6bits/sec

 87380  16384  16384    10.00    39857.69
       1 -> 1        : 0        |                                      |
       2 -> 3        : 0        |                                      |
       4 -> 7        : 0        |                                      |
       8 -> 15       : 0        |                                      |
      16 -> 31       : 0        |                                      |
      32 -> 63       : 22       |                                      |
      64 -> 127      : 98       |                                      |
     128 -> 255      : 213      |                                      |
     256 -> 511      : 1444251  |********                              |
     512 -> 1023     : 660610   |***                                   |
    1024 -> 2047     : 535241   |**                                    |
    2048 -> 4095     : 19       |                                      |
    4096 -> 8191     : 180      |                                      |
    8192 -> 16383    : 5578023  |************************************* |
   16384 -> 32767    : 632099   |***                                   |
   32768 -> 65535    : 6575     |                                      |

Signed-off-by: Thomas Graf <tgraf@suug.ch>
Acked-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
tgraf authored and davem330 committed Dec 2, 2016
1 parent 3a0af8f commit f74599f
Show file tree
Hide file tree
Showing 7 changed files with 855 additions and 0 deletions.
4 changes: 4 additions & 0 deletions samples/bpf/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ hostprogs-y += test_current_task_under_cgroup
hostprogs-y += trace_event
hostprogs-y += sampleip
hostprogs-y += tc_l2_redirect
hostprogs-y += lwt_len_hist

test_lru_dist-objs := test_lru_dist.o libbpf.o
sock_example-objs := sock_example.o libbpf.o
Expand Down Expand Up @@ -59,6 +60,7 @@ test_current_task_under_cgroup-objs := bpf_load.o libbpf.o \
trace_event-objs := bpf_load.o libbpf.o trace_event_user.o
sampleip-objs := bpf_load.o libbpf.o sampleip_user.o
tc_l2_redirect-objs := bpf_load.o libbpf.o tc_l2_redirect_user.o
lwt_len_hist-objs := bpf_load.o libbpf.o lwt_len_hist_user.o

# Tell kbuild to always build the programs
always := $(hostprogs-y)
Expand Down Expand Up @@ -89,6 +91,7 @@ always += xdp2_kern.o
always += test_current_task_under_cgroup_kern.o
always += trace_event_kern.o
always += sampleip_kern.o
always += lwt_len_hist_kern.o

HOSTCFLAGS += -I$(objtree)/usr/include
HOSTCFLAGS += -I$(srctree)/tools/testing/selftests/bpf/
Expand Down Expand Up @@ -117,6 +120,7 @@ HOSTLOADLIBES_test_current_task_under_cgroup += -lelf
HOSTLOADLIBES_trace_event += -lelf
HOSTLOADLIBES_sampleip += -lelf
HOSTLOADLIBES_tc_l2_redirect += -l elf
HOSTLOADLIBES_lwt_len_hist += -l elf

# 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
Expand Down
4 changes: 4 additions & 0 deletions samples/bpf/bpf_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ struct bpf_map_def {
unsigned int map_flags;
};

static int (*bpf_skb_load_bytes)(void *ctx, int off, void *to, int len) =
(void *) BPF_FUNC_skb_load_bytes;
static int (*bpf_skb_store_bytes)(void *ctx, int off, void *from, int len, int flags) =
(void *) BPF_FUNC_skb_store_bytes;
static int (*bpf_l3_csum_replace)(void *ctx, int off, int from, int to, int flags) =
Expand All @@ -88,6 +90,8 @@ static int (*bpf_l4_csum_replace)(void *ctx, int off, int from, int to, int flag
(void *) BPF_FUNC_l4_csum_replace;
static int (*bpf_skb_under_cgroup)(void *ctx, void *map, int index) =
(void *) BPF_FUNC_skb_under_cgroup;
static int (*bpf_skb_change_head)(void *, int len, int flags) =
(void *) BPF_FUNC_skb_change_head;

#if defined(__x86_64__)

Expand Down
37 changes: 37 additions & 0 deletions samples/bpf/lwt_len_hist.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/bin/bash

NS1=lwt_ns1
VETH0=tst_lwt1a
VETH1=tst_lwt1b

TRACE_ROOT=/sys/kernel/debug/tracing

function cleanup {
ip route del 192.168.253.2/32 dev $VETH0 2> /dev/null
ip link del $VETH0 2> /dev/null
ip link del $VETH1 2> /dev/null
ip netns exec $NS1 killall netserver
ip netns delete $NS1 2> /dev/null
}

cleanup

ip netns add $NS1
ip link add $VETH0 type veth peer name $VETH1
ip link set dev $VETH0 up
ip addr add 192.168.253.1/24 dev $VETH0
ip link set $VETH1 netns $NS1
ip netns exec $NS1 ip link set dev $VETH1 up
ip netns exec $NS1 ip addr add 192.168.253.2/24 dev $VETH1
ip netns exec $NS1 netserver

echo 1 > ${TRACE_ROOT}/tracing_on
cp /dev/null ${TRACE_ROOT}/trace
ip route add 192.168.253.2/32 encap bpf out obj lwt_len_hist_kern.o section len_hist dev $VETH0
netperf -H 192.168.253.2 -t TCP_STREAM
cat ${TRACE_ROOT}/trace | grep -v '^#'
./lwt_len_hist
cleanup
echo 0 > ${TRACE_ROOT}/tracing_on

exit 0
82 changes: 82 additions & 0 deletions samples/bpf/lwt_len_hist_kern.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/* Copyright (c) 2016 Thomas Graf <tgraf@tgraf.ch>
*
* 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 <uapi/linux/bpf.h>
#include <uapi/linux/if_ether.h>
#include <uapi/linux/ip.h>
#include <uapi/linux/in.h>
#include "bpf_helpers.h"

# define printk(fmt, ...) \
({ \
char ____fmt[] = fmt; \
bpf_trace_printk(____fmt, sizeof(____fmt), \
##__VA_ARGS__); \
})

struct bpf_elf_map {
__u32 type;
__u32 size_key;
__u32 size_value;
__u32 max_elem;
__u32 flags;
__u32 id;
__u32 pinning;
};

struct bpf_elf_map SEC("maps") lwt_len_hist_map = {
.type = BPF_MAP_TYPE_PERCPU_HASH,
.size_key = sizeof(__u64),
.size_value = sizeof(__u64),
.pinning = 2,
.max_elem = 1024,
};

static unsigned int log2(unsigned int v)
{
unsigned int r;
unsigned int shift;

r = (v > 0xFFFF) << 4; v >>= r;
shift = (v > 0xFF) << 3; v >>= shift; r |= shift;
shift = (v > 0xF) << 2; v >>= shift; r |= shift;
shift = (v > 0x3) << 1; v >>= shift; r |= shift;
r |= (v >> 1);
return r;
}

static unsigned int log2l(unsigned long v)
{
unsigned int hi = v >> 32;
if (hi)
return log2(hi) + 32;
else
return log2(v);
}

SEC("len_hist")
int do_len_hist(struct __sk_buff *skb)
{
__u64 *value, key, init_val = 1;

key = log2l(skb->len);

value = bpf_map_lookup_elem(&lwt_len_hist_map, &key);
if (value)
__sync_fetch_and_add(value, 1);
else
bpf_map_update_elem(&lwt_len_hist_map, &key, &init_val, BPF_ANY);

return BPF_OK;
}

char _license[] SEC("license") = "GPL";
76 changes: 76 additions & 0 deletions samples/bpf/lwt_len_hist_user.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#include <linux/unistd.h>
#include <linux/bpf.h>

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>

#include "libbpf.h"
#include "bpf_util.h"

#define MAX_INDEX 64
#define MAX_STARS 38

static void stars(char *str, long val, long max, int width)
{
int i;

for (i = 0; i < (width * val / max) - 1 && i < width - 1; i++)
str[i] = '*';
if (val > max)
str[i - 1] = '+';
str[i] = '\0';
}

int main(int argc, char **argv)
{
unsigned int nr_cpus = bpf_num_possible_cpus();
const char *map_filename = "/sys/fs/bpf/tc/globals/lwt_len_hist_map";
uint64_t values[nr_cpus], sum, max_value = 0, data[MAX_INDEX] = {};
uint64_t key = 0, next_key, max_key = 0;
char starstr[MAX_STARS];
int i, map_fd;

map_fd = bpf_obj_get(map_filename);
if (map_fd < 0) {
fprintf(stderr, "bpf_obj_get(%s): %s(%d)\n",
map_filename, strerror(errno), errno);
return -1;
}

while (bpf_get_next_key(map_fd, &key, &next_key) == 0) {
if (next_key >= MAX_INDEX) {
fprintf(stderr, "Key %lu out of bounds\n", next_key);
continue;
}

bpf_lookup_elem(map_fd, &next_key, values);

sum = 0;
for (i = 0; i < nr_cpus; i++)
sum += values[i];

data[next_key] = sum;
if (sum && next_key > max_key)
max_key = next_key;

if (sum > max_value)
max_value = sum;

key = next_key;
}

for (i = 1; i <= max_key + 1; i++) {
stars(starstr, data[i - 1], max_value, MAX_STARS);
printf("%8ld -> %-8ld : %-8ld |%-*s|\n",
(1l << i) >> 1, (1l << i) - 1, data[i - 1],
MAX_STARS, starstr);
}

close(map_fd);

return 0;
}

0 comments on commit f74599f

Please sign in to comment.