aboutsummaryrefslogtreecommitdiffstats
path: root/samples/bpf
diff options
context:
space:
mode:
authorBrenden Blanco <bblanco@plumgrid.com>2016-07-19 15:16:51 -0400
committerDavid S. Miller <davem@davemloft.net>2016-07-20 00:46:32 -0400
commit86af8b4191d20bb17e868d3167f4cf52ca9331d0 (patch)
treec87d8d918254983fe7625ac6edaf0bf6309eb564 /samples/bpf
parent47a38e155037f417c5740e24ccae6482aedf4b68 (diff)
Add sample for adding simple drop program to link
Add a sample program that only drops packets at the BPF_PROG_TYPE_XDP_RX hook of a link. With the drop-only program, observed single core rate is ~20Mpps. Other tests were run, for instance without the dropcnt increment or without reading from the packet header, the packet rate was mostly unchanged. $ perf record -a samples/bpf/xdp1 $(</sys/class/net/eth0/ifindex) proto 17: 20403027 drops/s ./pktgen_sample03_burst_single_flow.sh -i $DEV -d $IP -m $MAC -t 4 Running... ctrl^C to stop Device: eth4@0 Result: OK: 11791017(c11788327+d2689) usec, 59622913 (60byte,0frags) 5056638pps 2427Mb/sec (2427186240bps) errors: 0 Device: eth4@1 Result: OK: 11791012(c11787906+d3106) usec, 60526944 (60byte,0frags) 5133311pps 2463Mb/sec (2463989280bps) errors: 0 Device: eth4@2 Result: OK: 11791019(c11788249+d2769) usec, 59868091 (60byte,0frags) 5077431pps 2437Mb/sec (2437166880bps) errors: 0 Device: eth4@3 Result: OK: 11795039(c11792403+d2636) usec, 59483181 (60byte,0frags) 5043067pps 2420Mb/sec (2420672160bps) errors: 0 perf report --no-children: 26.05% ksoftirqd/0 [mlx4_en] [k] mlx4_en_process_rx_cq 17.84% ksoftirqd/0 [mlx4_en] [k] mlx4_en_alloc_frags 5.52% ksoftirqd/0 [mlx4_en] [k] mlx4_en_free_frag 4.90% swapper [kernel.vmlinux] [k] poll_idle 4.14% ksoftirqd/0 [kernel.vmlinux] [k] get_page_from_freelist 2.78% ksoftirqd/0 [kernel.vmlinux] [k] __free_pages_ok 2.57% ksoftirqd/0 [kernel.vmlinux] [k] bpf_map_lookup_elem 2.51% swapper [mlx4_en] [k] mlx4_en_process_rx_cq 1.94% ksoftirqd/0 [kernel.vmlinux] [k] percpu_array_map_lookup_elem 1.45% swapper [mlx4_en] [k] mlx4_en_alloc_frags 1.35% ksoftirqd/0 [kernel.vmlinux] [k] free_one_page 1.33% swapper [kernel.vmlinux] [k] intel_idle 1.04% ksoftirqd/0 [mlx4_en] [k] 0x000000000001c5c5 0.96% ksoftirqd/0 [mlx4_en] [k] 0x000000000001c58d 0.93% ksoftirqd/0 [mlx4_en] [k] 0x000000000001c6ee 0.92% ksoftirqd/0 [mlx4_en] [k] 0x000000000001c6b9 0.89% ksoftirqd/0 [kernel.vmlinux] [k] __alloc_pages_nodemask 0.83% ksoftirqd/0 [mlx4_en] [k] 0x000000000001c686 0.83% ksoftirqd/0 [mlx4_en] [k] 0x000000000001c5d5 0.78% ksoftirqd/0 [mlx4_en] [k] mlx4_alloc_pages.isra.23 0.77% ksoftirqd/0 [mlx4_en] [k] 0x000000000001c5b4 0.77% ksoftirqd/0 [kernel.vmlinux] [k] net_rx_action machine specs: receiver - Intel E5-1630 v3 @ 3.70GHz sender - Intel E5645 @ 2.40GHz Mellanox ConnectX-3 @40G Signed-off-by: Brenden Blanco <bblanco@plumgrid.com> Acked-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'samples/bpf')
-rw-r--r--samples/bpf/Makefile4
-rw-r--r--samples/bpf/bpf_load.c8
-rw-r--r--samples/bpf/xdp1_kern.c93
-rw-r--r--samples/bpf/xdp1_user.c181
4 files changed, 286 insertions, 0 deletions
diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index a98b780e974c..0e4ab3a9dfa9 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -21,6 +21,7 @@ hostprogs-y += spintest
21hostprogs-y += map_perf_test 21hostprogs-y += map_perf_test
22hostprogs-y += test_overhead 22hostprogs-y += test_overhead
23hostprogs-y += test_cgrp2_array_pin 23hostprogs-y += test_cgrp2_array_pin
24hostprogs-y += xdp1
24 25
25test_verifier-objs := test_verifier.o libbpf.o 26test_verifier-objs := test_verifier.o libbpf.o
26test_maps-objs := test_maps.o libbpf.o 27test_maps-objs := test_maps.o libbpf.o
@@ -42,6 +43,7 @@ spintest-objs := bpf_load.o libbpf.o spintest_user.o
42map_perf_test-objs := bpf_load.o libbpf.o map_perf_test_user.o 43map_perf_test-objs := bpf_load.o libbpf.o map_perf_test_user.o
43test_overhead-objs := bpf_load.o libbpf.o test_overhead_user.o 44test_overhead-objs := bpf_load.o libbpf.o test_overhead_user.o
44test_cgrp2_array_pin-objs := libbpf.o test_cgrp2_array_pin.o 45test_cgrp2_array_pin-objs := libbpf.o test_cgrp2_array_pin.o
46xdp1-objs := bpf_load.o libbpf.o xdp1_user.o
45 47
46# Tell kbuild to always build the programs 48# Tell kbuild to always build the programs
47always := $(hostprogs-y) 49always := $(hostprogs-y)
@@ -64,6 +66,7 @@ always += test_overhead_tp_kern.o
64always += test_overhead_kprobe_kern.o 66always += test_overhead_kprobe_kern.o
65always += parse_varlen.o parse_simple.o parse_ldabs.o 67always += parse_varlen.o parse_simple.o parse_ldabs.o
66always += test_cgrp2_tc_kern.o 68always += test_cgrp2_tc_kern.o
69always += xdp1_kern.o
67 70
68HOSTCFLAGS += -I$(objtree)/usr/include 71HOSTCFLAGS += -I$(objtree)/usr/include
69 72
@@ -84,6 +87,7 @@ HOSTLOADLIBES_offwaketime += -lelf
84HOSTLOADLIBES_spintest += -lelf 87HOSTLOADLIBES_spintest += -lelf
85HOSTLOADLIBES_map_perf_test += -lelf -lrt 88HOSTLOADLIBES_map_perf_test += -lelf -lrt
86HOSTLOADLIBES_test_overhead += -lelf -lrt 89HOSTLOADLIBES_test_overhead += -lelf -lrt
90HOSTLOADLIBES_xdp1 += -lelf
87 91
88# Allows pointing LLC/CLANG to a LLVM backend with bpf support, redefine on cmdline: 92# Allows pointing LLC/CLANG to a LLVM backend with bpf support, redefine on cmdline:
89# make samples/bpf/ LLC=~/git/llvm/build/bin/llc CLANG=~/git/llvm/build/bin/clang 93# make samples/bpf/ LLC=~/git/llvm/build/bin/llc CLANG=~/git/llvm/build/bin/clang
diff --git a/samples/bpf/bpf_load.c b/samples/bpf/bpf_load.c
index 022af71c2bb5..0cfda2320320 100644
--- a/samples/bpf/bpf_load.c
+++ b/samples/bpf/bpf_load.c
@@ -50,6 +50,7 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size)
50 bool is_kprobe = strncmp(event, "kprobe/", 7) == 0; 50 bool is_kprobe = strncmp(event, "kprobe/", 7) == 0;
51 bool is_kretprobe = strncmp(event, "kretprobe/", 10) == 0; 51 bool is_kretprobe = strncmp(event, "kretprobe/", 10) == 0;
52 bool is_tracepoint = strncmp(event, "tracepoint/", 11) == 0; 52 bool is_tracepoint = strncmp(event, "tracepoint/", 11) == 0;
53 bool is_xdp = strncmp(event, "xdp", 3) == 0;
53 enum bpf_prog_type prog_type; 54 enum bpf_prog_type prog_type;
54 char buf[256]; 55 char buf[256];
55 int fd, efd, err, id; 56 int fd, efd, err, id;
@@ -66,6 +67,8 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size)
66 prog_type = BPF_PROG_TYPE_KPROBE; 67 prog_type = BPF_PROG_TYPE_KPROBE;
67 } else if (is_tracepoint) { 68 } else if (is_tracepoint) {
68 prog_type = BPF_PROG_TYPE_TRACEPOINT; 69 prog_type = BPF_PROG_TYPE_TRACEPOINT;
70 } else if (is_xdp) {
71 prog_type = BPF_PROG_TYPE_XDP;
69 } else { 72 } else {
70 printf("Unknown event '%s'\n", event); 73 printf("Unknown event '%s'\n", event);
71 return -1; 74 return -1;
@@ -79,6 +82,9 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size)
79 82
80 prog_fd[prog_cnt++] = fd; 83 prog_fd[prog_cnt++] = fd;
81 84
85 if (is_xdp)
86 return 0;
87
82 if (is_socket) { 88 if (is_socket) {
83 event += 6; 89 event += 6;
84 if (*event != '/') 90 if (*event != '/')
@@ -319,6 +325,7 @@ int load_bpf_file(char *path)
319 if (memcmp(shname_prog, "kprobe/", 7) == 0 || 325 if (memcmp(shname_prog, "kprobe/", 7) == 0 ||
320 memcmp(shname_prog, "kretprobe/", 10) == 0 || 326 memcmp(shname_prog, "kretprobe/", 10) == 0 ||
321 memcmp(shname_prog, "tracepoint/", 11) == 0 || 327 memcmp(shname_prog, "tracepoint/", 11) == 0 ||
328 memcmp(shname_prog, "xdp", 3) == 0 ||
322 memcmp(shname_prog, "socket", 6) == 0) 329 memcmp(shname_prog, "socket", 6) == 0)
323 load_and_attach(shname_prog, insns, data_prog->d_size); 330 load_and_attach(shname_prog, insns, data_prog->d_size);
324 } 331 }
@@ -336,6 +343,7 @@ int load_bpf_file(char *path)
336 if (memcmp(shname, "kprobe/", 7) == 0 || 343 if (memcmp(shname, "kprobe/", 7) == 0 ||
337 memcmp(shname, "kretprobe/", 10) == 0 || 344 memcmp(shname, "kretprobe/", 10) == 0 ||
338 memcmp(shname, "tracepoint/", 11) == 0 || 345 memcmp(shname, "tracepoint/", 11) == 0 ||
346 memcmp(shname, "xdp", 3) == 0 ||
339 memcmp(shname, "socket", 6) == 0) 347 memcmp(shname, "socket", 6) == 0)
340 load_and_attach(shname, data->d_buf, data->d_size); 348 load_and_attach(shname, data->d_buf, data->d_size);
341 } 349 }
diff --git a/samples/bpf/xdp1_kern.c b/samples/bpf/xdp1_kern.c
new file mode 100644
index 000000000000..e7dd8ac40d12
--- /dev/null
+++ b/samples/bpf/xdp1_kern.c
@@ -0,0 +1,93 @@
1/* Copyright (c) 2016 PLUMgrid
2 *
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of version 2 of the GNU General Public
5 * License as published by the Free Software Foundation.
6 */
7#define KBUILD_MODNAME "foo"
8#include <uapi/linux/bpf.h>
9#include <linux/in.h>
10#include <linux/if_ether.h>
11#include <linux/if_packet.h>
12#include <linux/if_vlan.h>
13#include <linux/ip.h>
14#include <linux/ipv6.h>
15#include "bpf_helpers.h"
16
17struct bpf_map_def SEC("maps") dropcnt = {
18 .type = BPF_MAP_TYPE_PERCPU_ARRAY,
19 .key_size = sizeof(u32),
20 .value_size = sizeof(long),
21 .max_entries = 256,
22};
23
24static int parse_ipv4(void *data, u64 nh_off, void *data_end)
25{
26 struct iphdr *iph = data + nh_off;
27
28 if (iph + 1 > data_end)
29 return 0;
30 return iph->protocol;
31}
32
33static int parse_ipv6(void *data, u64 nh_off, void *data_end)
34{
35 struct ipv6hdr *ip6h = data + nh_off;
36
37 if (ip6h + 1 > data_end)
38 return 0;
39 return ip6h->nexthdr;
40}
41
42SEC("xdp1")
43int xdp_prog1(struct xdp_md *ctx)
44{
45 void *data_end = (void *)(long)ctx->data_end;
46 void *data = (void *)(long)ctx->data;
47 struct ethhdr *eth = data;
48 int rc = XDP_DROP;
49 long *value;
50 u16 h_proto;
51 u64 nh_off;
52 u32 index;
53
54 nh_off = sizeof(*eth);
55 if (data + nh_off > data_end)
56 return rc;
57
58 h_proto = eth->h_proto;
59
60 if (h_proto == htons(ETH_P_8021Q) || h_proto == htons(ETH_P_8021AD)) {
61 struct vlan_hdr *vhdr;
62
63 vhdr = data + nh_off;
64 nh_off += sizeof(struct vlan_hdr);
65 if (data + nh_off > data_end)
66 return rc;
67 h_proto = vhdr->h_vlan_encapsulated_proto;
68 }
69 if (h_proto == htons(ETH_P_8021Q) || h_proto == htons(ETH_P_8021AD)) {
70 struct vlan_hdr *vhdr;
71
72 vhdr = data + nh_off;
73 nh_off += sizeof(struct vlan_hdr);
74 if (data + nh_off > data_end)
75 return rc;
76 h_proto = vhdr->h_vlan_encapsulated_proto;
77 }
78
79 if (h_proto == htons(ETH_P_IP))
80 index = parse_ipv4(data, nh_off, data_end);
81 else if (h_proto == htons(ETH_P_IPV6))
82 index = parse_ipv6(data, nh_off, data_end);
83 else
84 index = 0;
85
86 value = bpf_map_lookup_elem(&dropcnt, &index);
87 if (value)
88 *value += 1;
89
90 return rc;
91}
92
93char _license[] SEC("license") = "GPL";
diff --git a/samples/bpf/xdp1_user.c b/samples/bpf/xdp1_user.c
new file mode 100644
index 000000000000..a5e109e398a1
--- /dev/null
+++ b/samples/bpf/xdp1_user.c
@@ -0,0 +1,181 @@
1/* Copyright (c) 2016 PLUMgrid
2 *
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of version 2 of the GNU General Public
5 * License as published by the Free Software Foundation.
6 */
7#include <linux/bpf.h>
8#include <linux/netlink.h>
9#include <linux/rtnetlink.h>
10#include <assert.h>
11#include <errno.h>
12#include <signal.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <sys/socket.h>
17#include <unistd.h>
18#include "bpf_load.h"
19#include "libbpf.h"
20
21static int set_link_xdp_fd(int ifindex, int fd)
22{
23 struct sockaddr_nl sa;
24 int sock, seq = 0, len, ret = -1;
25 char buf[4096];
26 struct nlattr *nla, *nla_xdp;
27 struct {
28 struct nlmsghdr nh;
29 struct ifinfomsg ifinfo;
30 char attrbuf[64];
31 } req;
32 struct nlmsghdr *nh;
33 struct nlmsgerr *err;
34
35 memset(&sa, 0, sizeof(sa));
36 sa.nl_family = AF_NETLINK;
37
38 sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
39 if (sock < 0) {
40 printf("open netlink socket: %s\n", strerror(errno));
41 return -1;
42 }
43
44 if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
45 printf("bind to netlink: %s\n", strerror(errno));
46 goto cleanup;
47 }
48
49 memset(&req, 0, sizeof(req));
50 req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
51 req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
52 req.nh.nlmsg_type = RTM_SETLINK;
53 req.nh.nlmsg_pid = 0;
54 req.nh.nlmsg_seq = ++seq;
55 req.ifinfo.ifi_family = AF_UNSPEC;
56 req.ifinfo.ifi_index = ifindex;
57 nla = (struct nlattr *)(((char *)&req)
58 + NLMSG_ALIGN(req.nh.nlmsg_len));
59 nla->nla_type = NLA_F_NESTED | 43/*IFLA_XDP*/;
60
61 nla_xdp = (struct nlattr *)((char *)nla + NLA_HDRLEN);
62 nla_xdp->nla_type = 1/*IFLA_XDP_FD*/;
63 nla_xdp->nla_len = NLA_HDRLEN + sizeof(int);
64 memcpy((char *)nla_xdp + NLA_HDRLEN, &fd, sizeof(fd));
65 nla->nla_len = NLA_HDRLEN + nla_xdp->nla_len;
66
67 req.nh.nlmsg_len += NLA_ALIGN(nla->nla_len);
68
69 if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) {
70 printf("send to netlink: %s\n", strerror(errno));
71 goto cleanup;
72 }
73
74 len = recv(sock, buf, sizeof(buf), 0);
75 if (len < 0) {
76 printf("recv from netlink: %s\n", strerror(errno));
77 goto cleanup;
78 }
79
80 for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len);
81 nh = NLMSG_NEXT(nh, len)) {
82 if (nh->nlmsg_pid != getpid()) {
83 printf("Wrong pid %d, expected %d\n",
84 nh->nlmsg_pid, getpid());
85 goto cleanup;
86 }
87 if (nh->nlmsg_seq != seq) {
88 printf("Wrong seq %d, expected %d\n",
89 nh->nlmsg_seq, seq);
90 goto cleanup;
91 }
92 switch (nh->nlmsg_type) {
93 case NLMSG_ERROR:
94 err = (struct nlmsgerr *)NLMSG_DATA(nh);
95 if (!err->error)
96 continue;
97 printf("nlmsg error %s\n", strerror(-err->error));
98 goto cleanup;
99 case NLMSG_DONE:
100 break;
101 }
102 }
103
104 ret = 0;
105
106cleanup:
107 close(sock);
108 return ret;
109}
110
111static int ifindex;
112
113static void int_exit(int sig)
114{
115 set_link_xdp_fd(ifindex, -1);
116 exit(0);
117}
118
119/* simple per-protocol drop counter
120 */
121static void poll_stats(int interval)
122{
123 unsigned int nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
124 const unsigned int nr_keys = 256;
125 __u64 values[nr_cpus], prev[nr_keys][nr_cpus];
126 __u32 key;
127 int i;
128
129 memset(prev, 0, sizeof(prev));
130
131 while (1) {
132 sleep(interval);
133
134 for (key = 0; key < nr_keys; key++) {
135 __u64 sum = 0;
136
137 assert(bpf_lookup_elem(map_fd[0], &key, values) == 0);
138 for (i = 0; i < nr_cpus; i++)
139 sum += (values[i] - prev[key][i]);
140 if (sum)
141 printf("proto %u: %10llu pkt/s\n",
142 key, sum / interval);
143 memcpy(prev[key], values, sizeof(values));
144 }
145 }
146}
147
148int main(int ac, char **argv)
149{
150 char filename[256];
151
152 snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
153
154 if (ac != 2) {
155 printf("usage: %s IFINDEX\n", argv[0]);
156 return 1;
157 }
158
159 ifindex = strtoul(argv[1], NULL, 0);
160
161 if (load_bpf_file(filename)) {
162 printf("%s", bpf_log_buf);
163 return 1;
164 }
165
166 if (!prog_fd[0]) {
167 printf("load_bpf_file: %s\n", strerror(errno));
168 return 1;
169 }
170
171 signal(SIGINT, int_exit);
172
173 if (set_link_xdp_fd(ifindex, prog_fd[0]) < 0) {
174 printf("link set xdp fd failed\n");
175 return 1;
176 }
177
178 poll_stats(2);
179
180 return 0;
181}