diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-15 18:04:25 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-15 18:04:25 -0400 |
commit | 9a76aba02a37718242d7cdc294f0a3901928aa57 (patch) | |
tree | 2040d038f85d2120f21af83b0793efd5af1864e3 /samples | |
parent | 0a957467c5fd46142bc9c52758ffc552d4c5e2f7 (diff) | |
parent | 26a1ccc6c117be8e33e0410fce8c5298b0015b99 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
Pull networking updates from David Miller:
"Highlights:
- Gustavo A. R. Silva keeps working on the implicit switch fallthru
changes.
- Support 802.11ax High-Efficiency wireless in cfg80211 et al, From
Luca Coelho.
- Re-enable ASPM in r8169, from Kai-Heng Feng.
- Add virtual XFRM interfaces, which avoids all of the limitations of
existing IPSEC tunnels. From Steffen Klassert.
- Convert GRO over to use a hash table, so that when we have many
flows active we don't traverse a long list during accumluation.
- Many new self tests for routing, TC, tunnels, etc. Too many
contributors to mention them all, but I'm really happy to keep
seeing this stuff.
- Hardware timestamping support for dpaa_eth/fsl-fman from Yangbo Lu.
- Lots of cleanups and fixes in L2TP code from Guillaume Nault.
- Add IPSEC offload support to netdevsim, from Shannon Nelson.
- Add support for slotting with non-uniform distribution to netem
packet scheduler, from Yousuk Seung.
- Add UDP GSO support to mlx5e, from Boris Pismenny.
- Support offloading of Team LAG in NFP, from John Hurley.
- Allow to configure TX queue selection based upon RX queue, from
Amritha Nambiar.
- Support ethtool ring size configuration in aquantia, from Anton
Mikaev.
- Support DSCP and flowlabel per-transport in SCTP, from Xin Long.
- Support list based batching and stack traversal of SKBs, this is
very exciting work. From Edward Cree.
- Busyloop optimizations in vhost_net, from Toshiaki Makita.
- Introduce the ETF qdisc, which allows time based transmissions. IGB
can offload this in hardware. From Vinicius Costa Gomes.
- Add parameter support to devlink, from Moshe Shemesh.
- Several multiplication and division optimizations for BPF JIT in
nfp driver, from Jiong Wang.
- Lots of prepatory work to make more of the packet scheduler layer
lockless, when possible, from Vlad Buslov.
- Add ACK filter and NAT awareness to sch_cake packet scheduler, from
Toke Høiland-Jørgensen.
- Support regions and region snapshots in devlink, from Alex Vesker.
- Allow to attach XDP programs to both HW and SW at the same time on
a given device, with initial support in nfp. From Jakub Kicinski.
- Add TLS RX offload and support in mlx5, from Ilya Lesokhin.
- Use PHYLIB in r8169 driver, from Heiner Kallweit.
- All sorts of changes to support Spectrum 2 in mlxsw driver, from
Ido Schimmel.
- PTP support in mv88e6xxx DSA driver, from Andrew Lunn.
- Make TCP_USER_TIMEOUT socket option more accurate, from Jon
Maxwell.
- Support for templates in packet scheduler classifier, from Jiri
Pirko.
- IPV6 support in RDS, from Ka-Cheong Poon.
- Native tproxy support in nf_tables, from Máté Eckl.
- Maintain IP fragment queue in an rbtree, but optimize properly for
in-order frags. From Peter Oskolkov.
- Improvde handling of ACKs on hole repairs, from Yuchung Cheng"
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1996 commits)
bpf: test: fix spelling mistake "REUSEEPORT" -> "REUSEPORT"
hv/netvsc: Fix NULL dereference at single queue mode fallback
net: filter: mark expected switch fall-through
xen-netfront: fix warn message as irq device name has '/'
cxgb4: Add new T5 PCI device ids 0x50af and 0x50b0
net: dsa: mv88e6xxx: missing unlock on error path
rds: fix building with IPV6=m
inet/connection_sock: prefer _THIS_IP_ to current_text_addr
net: dsa: mv88e6xxx: bitwise vs logical bug
net: sock_diag: Fix spectre v1 gadget in __sock_diag_cmd()
ieee802154: hwsim: using right kind of iteration
net: hns3: Add vlan filter setting by ethtool command -K
net: hns3: Set tx ring' tc info when netdev is up
net: hns3: Remove tx ring BD len register in hns3_enet
net: hns3: Fix desc num set to default when setting channel
net: hns3: Fix for phy link issue when using marvell phy driver
net: hns3: Fix for information of phydev lost problem when down/up
net: hns3: Fix for command format parsing error in hclge_is_all_function_id_zero
net: hns3: Add support for serdes loopback selftest
bnxt_en: take coredump_record structure off stack
...
Diffstat (limited to 'samples')
-rw-r--r-- | samples/bpf/Makefile | 25 | ||||
-rw-r--r-- | samples/bpf/bpf_load.c | 3 | ||||
-rw-r--r-- | samples/bpf/hash_func01.h | 55 | ||||
-rw-r--r-- | samples/bpf/test_cgrp2_attach2.c | 21 | ||||
-rw-r--r-- | samples/bpf/test_cgrp2_sock2.c | 2 | ||||
-rw-r--r-- | samples/bpf/xdp_fwd_user.c | 34 | ||||
-rw-r--r-- | samples/bpf/xdp_redirect_cpu_kern.c | 114 | ||||
-rw-r--r-- | samples/bpf/xdp_redirect_cpu_user.c | 4 | ||||
-rw-r--r-- | samples/bpf/xdp_rxq_info_kern.c | 43 | ||||
-rw-r--r-- | samples/bpf/xdp_rxq_info_user.c | 45 | ||||
-rw-r--r-- | samples/bpf/xdp_sample_pkts_kern.c | 66 | ||||
-rw-r--r-- | samples/bpf/xdp_sample_pkts_user.c | 169 | ||||
-rw-r--r-- | samples/bpf/xdpsock_user.c | 43 |
13 files changed, 590 insertions, 34 deletions
diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index bd9f6c2a808e..36f9f41d094b 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile | |||
@@ -52,6 +52,7 @@ hostprogs-y += xdp_adjust_tail | |||
52 | hostprogs-y += xdpsock | 52 | hostprogs-y += xdpsock |
53 | hostprogs-y += xdp_fwd | 53 | hostprogs-y += xdp_fwd |
54 | hostprogs-y += task_fd_query | 54 | hostprogs-y += task_fd_query |
55 | hostprogs-y += xdp_sample_pkts | ||
55 | 56 | ||
56 | # Libbpf dependencies | 57 | # Libbpf dependencies |
57 | LIBBPF = $(TOOLS_PATH)/lib/bpf/libbpf.a | 58 | LIBBPF = $(TOOLS_PATH)/lib/bpf/libbpf.a |
@@ -104,9 +105,10 @@ xdp_rxq_info-objs := xdp_rxq_info_user.o | |||
104 | syscall_tp-objs := bpf_load.o syscall_tp_user.o | 105 | syscall_tp-objs := bpf_load.o syscall_tp_user.o |
105 | cpustat-objs := bpf_load.o cpustat_user.o | 106 | cpustat-objs := bpf_load.o cpustat_user.o |
106 | xdp_adjust_tail-objs := xdp_adjust_tail_user.o | 107 | xdp_adjust_tail-objs := xdp_adjust_tail_user.o |
107 | xdpsock-objs := bpf_load.o xdpsock_user.o | 108 | xdpsock-objs := xdpsock_user.o |
108 | xdp_fwd-objs := bpf_load.o xdp_fwd_user.o | 109 | xdp_fwd-objs := xdp_fwd_user.o |
109 | task_fd_query-objs := bpf_load.o task_fd_query_user.o $(TRACE_HELPERS) | 110 | task_fd_query-objs := bpf_load.o task_fd_query_user.o $(TRACE_HELPERS) |
111 | xdp_sample_pkts-objs := xdp_sample_pkts_user.o $(TRACE_HELPERS) | ||
110 | 112 | ||
111 | # Tell kbuild to always build the programs | 113 | # Tell kbuild to always build the programs |
112 | always := $(hostprogs-y) | 114 | always := $(hostprogs-y) |
@@ -163,6 +165,7 @@ always += xdp_adjust_tail_kern.o | |||
163 | always += xdpsock_kern.o | 165 | always += xdpsock_kern.o |
164 | always += xdp_fwd_kern.o | 166 | always += xdp_fwd_kern.o |
165 | always += task_fd_query_kern.o | 167 | always += task_fd_query_kern.o |
168 | always += xdp_sample_pkts_kern.o | ||
166 | 169 | ||
167 | KBUILD_HOSTCFLAGS += -I$(objtree)/usr/include | 170 | KBUILD_HOSTCFLAGS += -I$(objtree)/usr/include |
168 | KBUILD_HOSTCFLAGS += -I$(srctree)/tools/lib/ | 171 | KBUILD_HOSTCFLAGS += -I$(srctree)/tools/lib/ |
@@ -179,6 +182,7 @@ HOSTCFLAGS_spintest_user.o += -I$(srctree)/tools/lib/bpf/ | |||
179 | HOSTCFLAGS_trace_event_user.o += -I$(srctree)/tools/lib/bpf/ | 182 | HOSTCFLAGS_trace_event_user.o += -I$(srctree)/tools/lib/bpf/ |
180 | HOSTCFLAGS_sampleip_user.o += -I$(srctree)/tools/lib/bpf/ | 183 | HOSTCFLAGS_sampleip_user.o += -I$(srctree)/tools/lib/bpf/ |
181 | HOSTCFLAGS_task_fd_query_user.o += -I$(srctree)/tools/lib/bpf/ | 184 | HOSTCFLAGS_task_fd_query_user.o += -I$(srctree)/tools/lib/bpf/ |
185 | HOSTCFLAGS_xdp_sample_pkts_user.o += -I$(srctree)/tools/lib/bpf/ | ||
182 | 186 | ||
183 | KBUILD_HOSTLDLIBS += $(LIBBPF) -lelf | 187 | KBUILD_HOSTLDLIBS += $(LIBBPF) -lelf |
184 | HOSTLDLIBS_tracex4 += -lrt | 188 | HOSTLDLIBS_tracex4 += -lrt |
@@ -191,6 +195,8 @@ HOSTLDLIBS_xdpsock += -pthread | |||
191 | # make samples/bpf/ LLC=~/git/llvm/build/bin/llc CLANG=~/git/llvm/build/bin/clang | 195 | # make samples/bpf/ LLC=~/git/llvm/build/bin/llc CLANG=~/git/llvm/build/bin/clang |
192 | LLC ?= llc | 196 | LLC ?= llc |
193 | CLANG ?= clang | 197 | CLANG ?= clang |
198 | LLVM_OBJCOPY ?= llvm-objcopy | ||
199 | BTF_PAHOLE ?= pahole | ||
194 | 200 | ||
195 | # Detect that we're cross compiling and use the cross compiler | 201 | # Detect that we're cross compiling and use the cross compiler |
196 | ifdef CROSS_COMPILE | 202 | ifdef CROSS_COMPILE |
@@ -198,6 +204,16 @@ HOSTCC = $(CROSS_COMPILE)gcc | |||
198 | CLANG_ARCH_ARGS = -target $(ARCH) | 204 | CLANG_ARCH_ARGS = -target $(ARCH) |
199 | endif | 205 | endif |
200 | 206 | ||
207 | BTF_LLC_PROBE := $(shell $(LLC) -march=bpf -mattr=help 2>&1 | grep dwarfris) | ||
208 | BTF_PAHOLE_PROBE := $(shell $(BTF_PAHOLE) --help 2>&1 | grep BTF) | ||
209 | BTF_OBJCOPY_PROBE := $(shell $(LLVM_OBJCOPY) --help 2>&1 | grep -i 'usage.*llvm') | ||
210 | |||
211 | ifneq ($(and $(BTF_LLC_PROBE),$(BTF_PAHOLE_PROBE),$(BTF_OBJCOPY_PROBE)),) | ||
212 | EXTRA_CFLAGS += -g | ||
213 | LLC_FLAGS += -mattr=dwarfris | ||
214 | DWARF2BTF = y | ||
215 | endif | ||
216 | |||
201 | # Trick to allow make to be run from this directory | 217 | # Trick to allow make to be run from this directory |
202 | all: | 218 | all: |
203 | $(MAKE) -C ../../ $(CURDIR)/ BPF_SAMPLES_PATH=$(CURDIR) | 219 | $(MAKE) -C ../../ $(CURDIR)/ BPF_SAMPLES_PATH=$(CURDIR) |
@@ -256,4 +272,7 @@ $(obj)/%.o: $(src)/%.c | |||
256 | -Wno-gnu-variable-sized-type-not-at-end \ | 272 | -Wno-gnu-variable-sized-type-not-at-end \ |
257 | -Wno-address-of-packed-member -Wno-tautological-compare \ | 273 | -Wno-address-of-packed-member -Wno-tautological-compare \ |
258 | -Wno-unknown-warning-option $(CLANG_ARCH_ARGS) \ | 274 | -Wno-unknown-warning-option $(CLANG_ARCH_ARGS) \ |
259 | -O2 -emit-llvm -c $< -o -| $(LLC) -march=bpf -filetype=obj -o $@ | 275 | -O2 -emit-llvm -c $< -o -| $(LLC) -march=bpf $(LLC_FLAGS) -filetype=obj -o $@ |
276 | ifeq ($(DWARF2BTF),y) | ||
277 | $(BTF_PAHOLE) -J $@ | ||
278 | endif | ||
diff --git a/samples/bpf/bpf_load.c b/samples/bpf/bpf_load.c index 89161c9ed466..904e775d1a44 100644 --- a/samples/bpf/bpf_load.c +++ b/samples/bpf/bpf_load.c | |||
@@ -107,6 +107,9 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size) | |||
107 | return -1; | 107 | return -1; |
108 | } | 108 | } |
109 | 109 | ||
110 | if (prog_cnt == MAX_PROGS) | ||
111 | return -1; | ||
112 | |||
110 | fd = bpf_load_program(prog_type, prog, insns_cnt, license, kern_version, | 113 | fd = bpf_load_program(prog_type, prog, insns_cnt, license, kern_version, |
111 | bpf_log_buf, BPF_LOG_BUF_SIZE); | 114 | bpf_log_buf, BPF_LOG_BUF_SIZE); |
112 | if (fd < 0) { | 115 | if (fd < 0) { |
diff --git a/samples/bpf/hash_func01.h b/samples/bpf/hash_func01.h new file mode 100644 index 000000000000..38255812e376 --- /dev/null +++ b/samples/bpf/hash_func01.h | |||
@@ -0,0 +1,55 @@ | |||
1 | /* SPDX-License-Identifier: LGPL-2.1 | ||
2 | * | ||
3 | * Based on Paul Hsieh's (LGPG 2.1) hash function | ||
4 | * From: http://www.azillionmonkeys.com/qed/hash.html | ||
5 | */ | ||
6 | |||
7 | #define get16bits(d) (*((const __u16 *) (d))) | ||
8 | |||
9 | static __always_inline | ||
10 | __u32 SuperFastHash (const char *data, int len, __u32 initval) { | ||
11 | __u32 hash = initval; | ||
12 | __u32 tmp; | ||
13 | int rem; | ||
14 | |||
15 | if (len <= 0 || data == NULL) return 0; | ||
16 | |||
17 | rem = len & 3; | ||
18 | len >>= 2; | ||
19 | |||
20 | /* Main loop */ | ||
21 | #pragma clang loop unroll(full) | ||
22 | for (;len > 0; len--) { | ||
23 | hash += get16bits (data); | ||
24 | tmp = (get16bits (data+2) << 11) ^ hash; | ||
25 | hash = (hash << 16) ^ tmp; | ||
26 | data += 2*sizeof (__u16); | ||
27 | hash += hash >> 11; | ||
28 | } | ||
29 | |||
30 | /* Handle end cases */ | ||
31 | switch (rem) { | ||
32 | case 3: hash += get16bits (data); | ||
33 | hash ^= hash << 16; | ||
34 | hash ^= ((signed char)data[sizeof (__u16)]) << 18; | ||
35 | hash += hash >> 11; | ||
36 | break; | ||
37 | case 2: hash += get16bits (data); | ||
38 | hash ^= hash << 11; | ||
39 | hash += hash >> 17; | ||
40 | break; | ||
41 | case 1: hash += (signed char)*data; | ||
42 | hash ^= hash << 10; | ||
43 | hash += hash >> 1; | ||
44 | } | ||
45 | |||
46 | /* Force "avalanching" of final 127 bits */ | ||
47 | hash ^= hash << 3; | ||
48 | hash += hash >> 5; | ||
49 | hash ^= hash << 4; | ||
50 | hash += hash >> 17; | ||
51 | hash ^= hash << 25; | ||
52 | hash += hash >> 6; | ||
53 | |||
54 | return hash; | ||
55 | } | ||
diff --git a/samples/bpf/test_cgrp2_attach2.c b/samples/bpf/test_cgrp2_attach2.c index b453e6a161be..180f9d813bca 100644 --- a/samples/bpf/test_cgrp2_attach2.c +++ b/samples/bpf/test_cgrp2_attach2.c | |||
@@ -8,7 +8,8 @@ | |||
8 | * information. The number of invocations of the program, which maps | 8 | * information. The number of invocations of the program, which maps |
9 | * to the number of packets received, is stored to key 0. Key 1 is | 9 | * to the number of packets received, is stored to key 0. Key 1 is |
10 | * incremented on each iteration by the number of bytes stored in | 10 | * incremented on each iteration by the number of bytes stored in |
11 | * the skb. | 11 | * the skb. The program also stores the number of received bytes |
12 | * in the cgroup storage. | ||
12 | * | 13 | * |
13 | * - Attaches the new program to a cgroup using BPF_PROG_ATTACH | 14 | * - Attaches the new program to a cgroup using BPF_PROG_ATTACH |
14 | * | 15 | * |
@@ -21,12 +22,15 @@ | |||
21 | #include <stdio.h> | 22 | #include <stdio.h> |
22 | #include <stdlib.h> | 23 | #include <stdlib.h> |
23 | #include <assert.h> | 24 | #include <assert.h> |
25 | #include <sys/resource.h> | ||
26 | #include <sys/time.h> | ||
24 | #include <unistd.h> | 27 | #include <unistd.h> |
25 | 28 | ||
26 | #include <linux/bpf.h> | 29 | #include <linux/bpf.h> |
27 | #include <bpf/bpf.h> | 30 | #include <bpf/bpf.h> |
28 | 31 | ||
29 | #include "bpf_insn.h" | 32 | #include "bpf_insn.h" |
33 | #include "bpf_rlimit.h" | ||
30 | #include "cgroup_helpers.h" | 34 | #include "cgroup_helpers.h" |
31 | 35 | ||
32 | #define FOO "/foo" | 36 | #define FOO "/foo" |
@@ -205,6 +209,8 @@ static int map_fd = -1; | |||
205 | 209 | ||
206 | static int prog_load_cnt(int verdict, int val) | 210 | static int prog_load_cnt(int verdict, int val) |
207 | { | 211 | { |
212 | int cgroup_storage_fd; | ||
213 | |||
208 | if (map_fd < 0) | 214 | if (map_fd < 0) |
209 | map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, 4, 8, 1, 0); | 215 | map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, 4, 8, 1, 0); |
210 | if (map_fd < 0) { | 216 | if (map_fd < 0) { |
@@ -212,6 +218,13 @@ static int prog_load_cnt(int verdict, int val) | |||
212 | return -1; | 218 | return -1; |
213 | } | 219 | } |
214 | 220 | ||
221 | cgroup_storage_fd = bpf_create_map(BPF_MAP_TYPE_CGROUP_STORAGE, | ||
222 | sizeof(struct bpf_cgroup_storage_key), 8, 0, 0); | ||
223 | if (cgroup_storage_fd < 0) { | ||
224 | printf("failed to create map '%s'\n", strerror(errno)); | ||
225 | return -1; | ||
226 | } | ||
227 | |||
215 | struct bpf_insn prog[] = { | 228 | struct bpf_insn prog[] = { |
216 | BPF_MOV32_IMM(BPF_REG_0, 0), | 229 | BPF_MOV32_IMM(BPF_REG_0, 0), |
217 | BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -4), /* *(u32 *)(fp - 4) = r0 */ | 230 | BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -4), /* *(u32 *)(fp - 4) = r0 */ |
@@ -222,6 +235,11 @@ static int prog_load_cnt(int verdict, int val) | |||
222 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), | 235 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), |
223 | BPF_MOV64_IMM(BPF_REG_1, val), /* r1 = 1 */ | 236 | BPF_MOV64_IMM(BPF_REG_1, val), /* r1 = 1 */ |
224 | BPF_RAW_INSN(BPF_STX | BPF_XADD | BPF_DW, BPF_REG_0, BPF_REG_1, 0, 0), /* xadd r0 += r1 */ | 237 | BPF_RAW_INSN(BPF_STX | BPF_XADD | BPF_DW, BPF_REG_0, BPF_REG_1, 0, 0), /* xadd r0 += r1 */ |
238 | BPF_LD_MAP_FD(BPF_REG_1, cgroup_storage_fd), | ||
239 | BPF_MOV64_IMM(BPF_REG_2, 0), | ||
240 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_local_storage), | ||
241 | BPF_MOV64_IMM(BPF_REG_1, val), | ||
242 | BPF_RAW_INSN(BPF_STX | BPF_XADD | BPF_W, BPF_REG_0, BPF_REG_1, 0, 0), | ||
225 | BPF_MOV64_IMM(BPF_REG_0, verdict), /* r0 = verdict */ | 243 | BPF_MOV64_IMM(BPF_REG_0, verdict), /* r0 = verdict */ |
226 | BPF_EXIT_INSN(), | 244 | BPF_EXIT_INSN(), |
227 | }; | 245 | }; |
@@ -237,6 +255,7 @@ static int prog_load_cnt(int verdict, int val) | |||
237 | printf("Output from verifier:\n%s\n-------\n", bpf_log_buf); | 255 | printf("Output from verifier:\n%s\n-------\n", bpf_log_buf); |
238 | return 0; | 256 | return 0; |
239 | } | 257 | } |
258 | close(cgroup_storage_fd); | ||
240 | return ret; | 259 | return ret; |
241 | } | 260 | } |
242 | 261 | ||
diff --git a/samples/bpf/test_cgrp2_sock2.c b/samples/bpf/test_cgrp2_sock2.c index 3b5be2364975..a9277b118c33 100644 --- a/samples/bpf/test_cgrp2_sock2.c +++ b/samples/bpf/test_cgrp2_sock2.c | |||
@@ -51,7 +51,7 @@ int main(int argc, char **argv) | |||
51 | if (argc > 3) | 51 | if (argc > 3) |
52 | filter_id = atoi(argv[3]); | 52 | filter_id = atoi(argv[3]); |
53 | 53 | ||
54 | if (filter_id > prog_cnt) { | 54 | if (filter_id >= prog_cnt) { |
55 | printf("Invalid program id; program not found in file\n"); | 55 | printf("Invalid program id; program not found in file\n"); |
56 | return EXIT_FAILURE; | 56 | return EXIT_FAILURE; |
57 | } | 57 | } |
diff --git a/samples/bpf/xdp_fwd_user.c b/samples/bpf/xdp_fwd_user.c index a87a2048ed32..f88e1d7093d6 100644 --- a/samples/bpf/xdp_fwd_user.c +++ b/samples/bpf/xdp_fwd_user.c | |||
@@ -24,8 +24,7 @@ | |||
24 | #include <fcntl.h> | 24 | #include <fcntl.h> |
25 | #include <libgen.h> | 25 | #include <libgen.h> |
26 | 26 | ||
27 | #include "bpf_load.h" | 27 | #include "bpf/libbpf.h" |
28 | #include "bpf_util.h" | ||
29 | #include <bpf/bpf.h> | 28 | #include <bpf/bpf.h> |
30 | 29 | ||
31 | 30 | ||
@@ -63,9 +62,15 @@ static void usage(const char *prog) | |||
63 | 62 | ||
64 | int main(int argc, char **argv) | 63 | int main(int argc, char **argv) |
65 | { | 64 | { |
65 | struct bpf_prog_load_attr prog_load_attr = { | ||
66 | .prog_type = BPF_PROG_TYPE_XDP, | ||
67 | }; | ||
68 | const char *prog_name = "xdp_fwd"; | ||
69 | struct bpf_program *prog; | ||
66 | char filename[PATH_MAX]; | 70 | char filename[PATH_MAX]; |
71 | struct bpf_object *obj; | ||
67 | int opt, i, idx, err; | 72 | int opt, i, idx, err; |
68 | int prog_id = 0; | 73 | int prog_fd, map_fd; |
69 | int attach = 1; | 74 | int attach = 1; |
70 | int ret = 0; | 75 | int ret = 0; |
71 | 76 | ||
@@ -75,7 +80,7 @@ int main(int argc, char **argv) | |||
75 | attach = 0; | 80 | attach = 0; |
76 | break; | 81 | break; |
77 | case 'D': | 82 | case 'D': |
78 | prog_id = 1; | 83 | prog_name = "xdp_fwd_direct"; |
79 | break; | 84 | break; |
80 | default: | 85 | default: |
81 | usage(basename(argv[0])); | 86 | usage(basename(argv[0])); |
@@ -90,6 +95,7 @@ int main(int argc, char **argv) | |||
90 | 95 | ||
91 | if (attach) { | 96 | if (attach) { |
92 | snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); | 97 | snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); |
98 | prog_load_attr.file = filename; | ||
93 | 99 | ||
94 | if (access(filename, O_RDONLY) < 0) { | 100 | if (access(filename, O_RDONLY) < 0) { |
95 | printf("error accessing file %s: %s\n", | 101 | printf("error accessing file %s: %s\n", |
@@ -97,19 +103,25 @@ int main(int argc, char **argv) | |||
97 | return 1; | 103 | return 1; |
98 | } | 104 | } |
99 | 105 | ||
100 | if (load_bpf_file(filename)) { | 106 | if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd)) |
101 | printf("%s", bpf_log_buf); | ||
102 | return 1; | 107 | return 1; |
103 | } | ||
104 | 108 | ||
105 | if (!prog_fd[prog_id]) { | 109 | prog = bpf_object__find_program_by_title(obj, prog_name); |
106 | printf("load_bpf_file: %s\n", strerror(errno)); | 110 | prog_fd = bpf_program__fd(prog); |
111 | if (prog_fd < 0) { | ||
112 | printf("program not found: %s\n", strerror(prog_fd)); | ||
113 | return 1; | ||
114 | } | ||
115 | map_fd = bpf_map__fd(bpf_object__find_map_by_name(obj, | ||
116 | "tx_port")); | ||
117 | if (map_fd < 0) { | ||
118 | printf("map not found: %s\n", strerror(map_fd)); | ||
107 | return 1; | 119 | return 1; |
108 | } | 120 | } |
109 | } | 121 | } |
110 | if (attach) { | 122 | if (attach) { |
111 | for (i = 1; i < 64; ++i) | 123 | for (i = 1; i < 64; ++i) |
112 | bpf_map_update_elem(map_fd[0], &i, &i, 0); | 124 | bpf_map_update_elem(map_fd, &i, &i, 0); |
113 | } | 125 | } |
114 | 126 | ||
115 | for (i = optind; i < argc; ++i) { | 127 | for (i = optind; i < argc; ++i) { |
@@ -126,7 +138,7 @@ int main(int argc, char **argv) | |||
126 | if (err) | 138 | if (err) |
127 | ret = err; | 139 | ret = err; |
128 | } else { | 140 | } else { |
129 | err = do_attach(idx, prog_fd[prog_id], argv[i]); | 141 | err = do_attach(idx, prog_fd, argv[i]); |
130 | if (err) | 142 | if (err) |
131 | ret = err; | 143 | ret = err; |
132 | } | 144 | } |
diff --git a/samples/bpf/xdp_redirect_cpu_kern.c b/samples/bpf/xdp_redirect_cpu_kern.c index 4938dcbaecbf..a306d1c75622 100644 --- a/samples/bpf/xdp_redirect_cpu_kern.c +++ b/samples/bpf/xdp_redirect_cpu_kern.c | |||
@@ -13,6 +13,7 @@ | |||
13 | 13 | ||
14 | #include <uapi/linux/bpf.h> | 14 | #include <uapi/linux/bpf.h> |
15 | #include "bpf_helpers.h" | 15 | #include "bpf_helpers.h" |
16 | #include "hash_func01.h" | ||
16 | 17 | ||
17 | #define MAX_CPUS 64 /* WARNING - sync with _user.c */ | 18 | #define MAX_CPUS 64 /* WARNING - sync with _user.c */ |
18 | 19 | ||
@@ -134,7 +135,16 @@ bool parse_eth(struct ethhdr *eth, void *data_end, | |||
134 | return false; | 135 | return false; |
135 | eth_type = vlan_hdr->h_vlan_encapsulated_proto; | 136 | eth_type = vlan_hdr->h_vlan_encapsulated_proto; |
136 | } | 137 | } |
137 | /* TODO: Handle double VLAN tagged packet */ | 138 | /* Handle double VLAN tagged packet */ |
139 | if (eth_type == htons(ETH_P_8021Q) || eth_type == htons(ETH_P_8021AD)) { | ||
140 | struct vlan_hdr *vlan_hdr; | ||
141 | |||
142 | vlan_hdr = (void *)eth + offset; | ||
143 | offset += sizeof(*vlan_hdr); | ||
144 | if ((void *)eth + offset > data_end) | ||
145 | return false; | ||
146 | eth_type = vlan_hdr->h_vlan_encapsulated_proto; | ||
147 | } | ||
138 | 148 | ||
139 | *eth_proto = ntohs(eth_type); | 149 | *eth_proto = ntohs(eth_type); |
140 | *l3_offset = offset; | 150 | *l3_offset = offset; |
@@ -452,6 +462,108 @@ int xdp_prognum4_ddos_filter_pktgen(struct xdp_md *ctx) | |||
452 | return bpf_redirect_map(&cpu_map, cpu_dest, 0); | 462 | return bpf_redirect_map(&cpu_map, cpu_dest, 0); |
453 | } | 463 | } |
454 | 464 | ||
465 | /* Hashing initval */ | ||
466 | #define INITVAL 15485863 | ||
467 | |||
468 | static __always_inline | ||
469 | u32 get_ipv4_hash_ip_pair(struct xdp_md *ctx, u64 nh_off) | ||
470 | { | ||
471 | void *data_end = (void *)(long)ctx->data_end; | ||
472 | void *data = (void *)(long)ctx->data; | ||
473 | struct iphdr *iph = data + nh_off; | ||
474 | u32 cpu_hash; | ||
475 | |||
476 | if (iph + 1 > data_end) | ||
477 | return 0; | ||
478 | |||
479 | cpu_hash = iph->saddr + iph->daddr; | ||
480 | cpu_hash = SuperFastHash((char *)&cpu_hash, 4, INITVAL + iph->protocol); | ||
481 | |||
482 | return cpu_hash; | ||
483 | } | ||
484 | |||
485 | static __always_inline | ||
486 | u32 get_ipv6_hash_ip_pair(struct xdp_md *ctx, u64 nh_off) | ||
487 | { | ||
488 | void *data_end = (void *)(long)ctx->data_end; | ||
489 | void *data = (void *)(long)ctx->data; | ||
490 | struct ipv6hdr *ip6h = data + nh_off; | ||
491 | u32 cpu_hash; | ||
492 | |||
493 | if (ip6h + 1 > data_end) | ||
494 | return 0; | ||
495 | |||
496 | cpu_hash = ip6h->saddr.s6_addr32[0] + ip6h->daddr.s6_addr32[0]; | ||
497 | cpu_hash += ip6h->saddr.s6_addr32[1] + ip6h->daddr.s6_addr32[1]; | ||
498 | cpu_hash += ip6h->saddr.s6_addr32[2] + ip6h->daddr.s6_addr32[2]; | ||
499 | cpu_hash += ip6h->saddr.s6_addr32[3] + ip6h->daddr.s6_addr32[3]; | ||
500 | cpu_hash = SuperFastHash((char *)&cpu_hash, 4, INITVAL + ip6h->nexthdr); | ||
501 | |||
502 | return cpu_hash; | ||
503 | } | ||
504 | |||
505 | /* Load-Balance traffic based on hashing IP-addrs + L4-proto. The | ||
506 | * hashing scheme is symmetric, meaning swapping IP src/dest still hit | ||
507 | * same CPU. | ||
508 | */ | ||
509 | SEC("xdp_cpu_map5_lb_hash_ip_pairs") | ||
510 | int xdp_prognum5_lb_hash_ip_pairs(struct xdp_md *ctx) | ||
511 | { | ||
512 | void *data_end = (void *)(long)ctx->data_end; | ||
513 | void *data = (void *)(long)ctx->data; | ||
514 | struct ethhdr *eth = data; | ||
515 | u8 ip_proto = IPPROTO_UDP; | ||
516 | struct datarec *rec; | ||
517 | u16 eth_proto = 0; | ||
518 | u64 l3_offset = 0; | ||
519 | u32 cpu_dest = 0; | ||
520 | u32 cpu_idx = 0; | ||
521 | u32 *cpu_lookup; | ||
522 | u32 *cpu_max; | ||
523 | u32 cpu_hash; | ||
524 | u32 key = 0; | ||
525 | |||
526 | /* Count RX packet in map */ | ||
527 | rec = bpf_map_lookup_elem(&rx_cnt, &key); | ||
528 | if (!rec) | ||
529 | return XDP_ABORTED; | ||
530 | rec->processed++; | ||
531 | |||
532 | cpu_max = bpf_map_lookup_elem(&cpus_count, &key); | ||
533 | if (!cpu_max) | ||
534 | return XDP_ABORTED; | ||
535 | |||
536 | if (!(parse_eth(eth, data_end, ð_proto, &l3_offset))) | ||
537 | return XDP_PASS; /* Just skip */ | ||
538 | |||
539 | /* Hash for IPv4 and IPv6 */ | ||
540 | switch (eth_proto) { | ||
541 | case ETH_P_IP: | ||
542 | cpu_hash = get_ipv4_hash_ip_pair(ctx, l3_offset); | ||
543 | break; | ||
544 | case ETH_P_IPV6: | ||
545 | cpu_hash = get_ipv6_hash_ip_pair(ctx, l3_offset); | ||
546 | break; | ||
547 | case ETH_P_ARP: /* ARP packet handled on CPU idx 0 */ | ||
548 | default: | ||
549 | cpu_hash = 0; | ||
550 | } | ||
551 | |||
552 | /* Choose CPU based on hash */ | ||
553 | cpu_idx = cpu_hash % *cpu_max; | ||
554 | |||
555 | cpu_lookup = bpf_map_lookup_elem(&cpus_available, &cpu_idx); | ||
556 | if (!cpu_lookup) | ||
557 | return XDP_ABORTED; | ||
558 | cpu_dest = *cpu_lookup; | ||
559 | |||
560 | if (cpu_dest >= MAX_CPUS) { | ||
561 | rec->issue++; | ||
562 | return XDP_ABORTED; | ||
563 | } | ||
564 | |||
565 | return bpf_redirect_map(&cpu_map, cpu_dest, 0); | ||
566 | } | ||
455 | 567 | ||
456 | char _license[] SEC("license") = "GPL"; | 568 | char _license[] SEC("license") = "GPL"; |
457 | 569 | ||
diff --git a/samples/bpf/xdp_redirect_cpu_user.c b/samples/bpf/xdp_redirect_cpu_user.c index 4b4d78fffe30..9a6c7e0a6dd1 100644 --- a/samples/bpf/xdp_redirect_cpu_user.c +++ b/samples/bpf/xdp_redirect_cpu_user.c | |||
@@ -22,7 +22,7 @@ static const char *__doc__ = | |||
22 | #define MAX_CPUS 64 /* WARNING - sync with _kern.c */ | 22 | #define MAX_CPUS 64 /* WARNING - sync with _kern.c */ |
23 | 23 | ||
24 | /* How many xdp_progs are defined in _kern.c */ | 24 | /* How many xdp_progs are defined in _kern.c */ |
25 | #define MAX_PROG 5 | 25 | #define MAX_PROG 6 |
26 | 26 | ||
27 | /* Wanted to get rid of bpf_load.h and fake-"libbpf.h" (and instead | 27 | /* Wanted to get rid of bpf_load.h and fake-"libbpf.h" (and instead |
28 | * use bpf/libbpf.h), but cannot as (currently) needed for XDP | 28 | * use bpf/libbpf.h), but cannot as (currently) needed for XDP |
@@ -567,7 +567,7 @@ int main(int argc, char **argv) | |||
567 | int added_cpus = 0; | 567 | int added_cpus = 0; |
568 | int longindex = 0; | 568 | int longindex = 0; |
569 | int interval = 2; | 569 | int interval = 2; |
570 | int prog_num = 0; | 570 | int prog_num = 5; |
571 | int add_cpu = -1; | 571 | int add_cpu = -1; |
572 | __u32 qsize; | 572 | __u32 qsize; |
573 | int opt; | 573 | int opt; |
diff --git a/samples/bpf/xdp_rxq_info_kern.c b/samples/bpf/xdp_rxq_info_kern.c index 3fd209291653..222a83eed1cb 100644 --- a/samples/bpf/xdp_rxq_info_kern.c +++ b/samples/bpf/xdp_rxq_info_kern.c | |||
@@ -4,6 +4,8 @@ | |||
4 | * Example howto extract XDP RX-queue info | 4 | * Example howto extract XDP RX-queue info |
5 | */ | 5 | */ |
6 | #include <uapi/linux/bpf.h> | 6 | #include <uapi/linux/bpf.h> |
7 | #include <uapi/linux/if_ether.h> | ||
8 | #include <uapi/linux/in.h> | ||
7 | #include "bpf_helpers.h" | 9 | #include "bpf_helpers.h" |
8 | 10 | ||
9 | /* Config setup from with userspace | 11 | /* Config setup from with userspace |
@@ -14,6 +16,12 @@ | |||
14 | struct config { | 16 | struct config { |
15 | __u32 action; | 17 | __u32 action; |
16 | int ifindex; | 18 | int ifindex; |
19 | __u32 options; | ||
20 | }; | ||
21 | enum cfg_options_flags { | ||
22 | NO_TOUCH = 0x0U, | ||
23 | READ_MEM = 0x1U, | ||
24 | SWAP_MAC = 0x2U, | ||
17 | }; | 25 | }; |
18 | struct bpf_map_def SEC("maps") config_map = { | 26 | struct bpf_map_def SEC("maps") config_map = { |
19 | .type = BPF_MAP_TYPE_ARRAY, | 27 | .type = BPF_MAP_TYPE_ARRAY, |
@@ -45,6 +53,23 @@ struct bpf_map_def SEC("maps") rx_queue_index_map = { | |||
45 | .max_entries = MAX_RXQs + 1, | 53 | .max_entries = MAX_RXQs + 1, |
46 | }; | 54 | }; |
47 | 55 | ||
56 | static __always_inline | ||
57 | void swap_src_dst_mac(void *data) | ||
58 | { | ||
59 | unsigned short *p = data; | ||
60 | unsigned short dst[3]; | ||
61 | |||
62 | dst[0] = p[0]; | ||
63 | dst[1] = p[1]; | ||
64 | dst[2] = p[2]; | ||
65 | p[0] = p[3]; | ||
66 | p[1] = p[4]; | ||
67 | p[2] = p[5]; | ||
68 | p[3] = dst[0]; | ||
69 | p[4] = dst[1]; | ||
70 | p[5] = dst[2]; | ||
71 | } | ||
72 | |||
48 | SEC("xdp_prog0") | 73 | SEC("xdp_prog0") |
49 | int xdp_prognum0(struct xdp_md *ctx) | 74 | int xdp_prognum0(struct xdp_md *ctx) |
50 | { | 75 | { |
@@ -90,6 +115,24 @@ int xdp_prognum0(struct xdp_md *ctx) | |||
90 | if (key == MAX_RXQs) | 115 | if (key == MAX_RXQs) |
91 | rxq_rec->issue++; | 116 | rxq_rec->issue++; |
92 | 117 | ||
118 | /* Default: Don't touch packet data, only count packets */ | ||
119 | if (unlikely(config->options & (READ_MEM|SWAP_MAC))) { | ||
120 | struct ethhdr *eth = data; | ||
121 | |||
122 | if (eth + 1 > data_end) | ||
123 | return XDP_ABORTED; | ||
124 | |||
125 | /* Avoid compiler removing this: Drop non 802.3 Ethertypes */ | ||
126 | if (ntohs(eth->h_proto) < ETH_P_802_3_MIN) | ||
127 | return XDP_ABORTED; | ||
128 | |||
129 | /* XDP_TX requires changing MAC-addrs, else HW may drop. | ||
130 | * Can also be enabled with --swapmac (for test purposes) | ||
131 | */ | ||
132 | if (unlikely(config->options & SWAP_MAC)) | ||
133 | swap_src_dst_mac(data); | ||
134 | } | ||
135 | |||
93 | return config->action; | 136 | return config->action; |
94 | } | 137 | } |
95 | 138 | ||
diff --git a/samples/bpf/xdp_rxq_info_user.c b/samples/bpf/xdp_rxq_info_user.c index e4e9ba52bff0..248a7eab9531 100644 --- a/samples/bpf/xdp_rxq_info_user.c +++ b/samples/bpf/xdp_rxq_info_user.c | |||
@@ -50,6 +50,8 @@ static const struct option long_options[] = { | |||
50 | {"sec", required_argument, NULL, 's' }, | 50 | {"sec", required_argument, NULL, 's' }, |
51 | {"no-separators", no_argument, NULL, 'z' }, | 51 | {"no-separators", no_argument, NULL, 'z' }, |
52 | {"action", required_argument, NULL, 'a' }, | 52 | {"action", required_argument, NULL, 'a' }, |
53 | {"readmem", no_argument, NULL, 'r' }, | ||
54 | {"swapmac", no_argument, NULL, 'm' }, | ||
53 | {0, 0, NULL, 0 } | 55 | {0, 0, NULL, 0 } |
54 | }; | 56 | }; |
55 | 57 | ||
@@ -66,6 +68,12 @@ static void int_exit(int sig) | |||
66 | struct config { | 68 | struct config { |
67 | __u32 action; | 69 | __u32 action; |
68 | int ifindex; | 70 | int ifindex; |
71 | __u32 options; | ||
72 | }; | ||
73 | enum cfg_options_flags { | ||
74 | NO_TOUCH = 0x0U, | ||
75 | READ_MEM = 0x1U, | ||
76 | SWAP_MAC = 0x2U, | ||
69 | }; | 77 | }; |
70 | #define XDP_ACTION_MAX (XDP_TX + 1) | 78 | #define XDP_ACTION_MAX (XDP_TX + 1) |
71 | #define XDP_ACTION_MAX_STRLEN 11 | 79 | #define XDP_ACTION_MAX_STRLEN 11 |
@@ -109,6 +117,18 @@ static void list_xdp_actions(void) | |||
109 | printf("\n"); | 117 | printf("\n"); |
110 | } | 118 | } |
111 | 119 | ||
120 | static char* options2str(enum cfg_options_flags flag) | ||
121 | { | ||
122 | if (flag == NO_TOUCH) | ||
123 | return "no_touch"; | ||
124 | if (flag & SWAP_MAC) | ||
125 | return "swapmac"; | ||
126 | if (flag & READ_MEM) | ||
127 | return "read"; | ||
128 | fprintf(stderr, "ERR: Unknown config option flags"); | ||
129 | exit(EXIT_FAIL); | ||
130 | } | ||
131 | |||
112 | static void usage(char *argv[]) | 132 | static void usage(char *argv[]) |
113 | { | 133 | { |
114 | int i; | 134 | int i; |
@@ -305,7 +325,7 @@ static __u64 calc_errs_pps(struct datarec *r, | |||
305 | 325 | ||
306 | static void stats_print(struct stats_record *stats_rec, | 326 | static void stats_print(struct stats_record *stats_rec, |
307 | struct stats_record *stats_prev, | 327 | struct stats_record *stats_prev, |
308 | int action) | 328 | int action, __u32 cfg_opt) |
309 | { | 329 | { |
310 | unsigned int nr_rxqs = bpf_map__def(rx_queue_index_map)->max_entries; | 330 | unsigned int nr_rxqs = bpf_map__def(rx_queue_index_map)->max_entries; |
311 | unsigned int nr_cpus = bpf_num_possible_cpus(); | 331 | unsigned int nr_cpus = bpf_num_possible_cpus(); |
@@ -316,8 +336,8 @@ static void stats_print(struct stats_record *stats_rec, | |||
316 | int i; | 336 | int i; |
317 | 337 | ||
318 | /* Header */ | 338 | /* Header */ |
319 | printf("\nRunning XDP on dev:%s (ifindex:%d) action:%s\n", | 339 | printf("\nRunning XDP on dev:%s (ifindex:%d) action:%s options:%s\n", |
320 | ifname, ifindex, action2str(action)); | 340 | ifname, ifindex, action2str(action), options2str(cfg_opt)); |
321 | 341 | ||
322 | /* stats_global_map */ | 342 | /* stats_global_map */ |
323 | { | 343 | { |
@@ -399,7 +419,7 @@ static inline void swap(struct stats_record **a, struct stats_record **b) | |||
399 | *b = tmp; | 419 | *b = tmp; |
400 | } | 420 | } |
401 | 421 | ||
402 | static void stats_poll(int interval, int action) | 422 | static void stats_poll(int interval, int action, __u32 cfg_opt) |
403 | { | 423 | { |
404 | struct stats_record *record, *prev; | 424 | struct stats_record *record, *prev; |
405 | 425 | ||
@@ -410,7 +430,7 @@ static void stats_poll(int interval, int action) | |||
410 | while (1) { | 430 | while (1) { |
411 | swap(&prev, &record); | 431 | swap(&prev, &record); |
412 | stats_collect(record); | 432 | stats_collect(record); |
413 | stats_print(record, prev, action); | 433 | stats_print(record, prev, action, cfg_opt); |
414 | sleep(interval); | 434 | sleep(interval); |
415 | } | 435 | } |
416 | 436 | ||
@@ -421,6 +441,7 @@ static void stats_poll(int interval, int action) | |||
421 | 441 | ||
422 | int main(int argc, char **argv) | 442 | int main(int argc, char **argv) |
423 | { | 443 | { |
444 | __u32 cfg_options= NO_TOUCH ; /* Default: Don't touch packet memory */ | ||
424 | struct rlimit r = {10 * 1024 * 1024, RLIM_INFINITY}; | 445 | struct rlimit r = {10 * 1024 * 1024, RLIM_INFINITY}; |
425 | struct bpf_prog_load_attr prog_load_attr = { | 446 | struct bpf_prog_load_attr prog_load_attr = { |
426 | .prog_type = BPF_PROG_TYPE_XDP, | 447 | .prog_type = BPF_PROG_TYPE_XDP, |
@@ -435,6 +456,7 @@ int main(int argc, char **argv) | |||
435 | int interval = 2; | 456 | int interval = 2; |
436 | __u32 key = 0; | 457 | __u32 key = 0; |
437 | 458 | ||
459 | |||
438 | char action_str_buf[XDP_ACTION_MAX_STRLEN + 1 /* for \0 */] = { 0 }; | 460 | char action_str_buf[XDP_ACTION_MAX_STRLEN + 1 /* for \0 */] = { 0 }; |
439 | int action = XDP_PASS; /* Default action */ | 461 | int action = XDP_PASS; /* Default action */ |
440 | char *action_str = NULL; | 462 | char *action_str = NULL; |
@@ -496,6 +518,12 @@ int main(int argc, char **argv) | |||
496 | action_str = (char *)&action_str_buf; | 518 | action_str = (char *)&action_str_buf; |
497 | strncpy(action_str, optarg, XDP_ACTION_MAX_STRLEN); | 519 | strncpy(action_str, optarg, XDP_ACTION_MAX_STRLEN); |
498 | break; | 520 | break; |
521 | case 'r': | ||
522 | cfg_options |= READ_MEM; | ||
523 | break; | ||
524 | case 'm': | ||
525 | cfg_options |= SWAP_MAC; | ||
526 | break; | ||
499 | case 'h': | 527 | case 'h': |
500 | error: | 528 | error: |
501 | default: | 529 | default: |
@@ -523,6 +551,11 @@ int main(int argc, char **argv) | |||
523 | } | 551 | } |
524 | cfg.action = action; | 552 | cfg.action = action; |
525 | 553 | ||
554 | /* XDP_TX requires changing MAC-addrs, else HW may drop */ | ||
555 | if (action == XDP_TX) | ||
556 | cfg_options |= SWAP_MAC; | ||
557 | cfg.options = cfg_options; | ||
558 | |||
526 | /* Trick to pretty printf with thousands separators use %' */ | 559 | /* Trick to pretty printf with thousands separators use %' */ |
527 | if (use_separators) | 560 | if (use_separators) |
528 | setlocale(LC_NUMERIC, "en_US"); | 561 | setlocale(LC_NUMERIC, "en_US"); |
@@ -542,6 +575,6 @@ int main(int argc, char **argv) | |||
542 | return EXIT_FAIL_XDP; | 575 | return EXIT_FAIL_XDP; |
543 | } | 576 | } |
544 | 577 | ||
545 | stats_poll(interval, action); | 578 | stats_poll(interval, action, cfg_options); |
546 | return EXIT_OK; | 579 | return EXIT_OK; |
547 | } | 580 | } |
diff --git a/samples/bpf/xdp_sample_pkts_kern.c b/samples/bpf/xdp_sample_pkts_kern.c new file mode 100644 index 000000000000..f7ca8b850978 --- /dev/null +++ b/samples/bpf/xdp_sample_pkts_kern.c | |||
@@ -0,0 +1,66 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | #include <linux/ptrace.h> | ||
3 | #include <linux/version.h> | ||
4 | #include <uapi/linux/bpf.h> | ||
5 | #include "bpf_helpers.h" | ||
6 | |||
7 | #define SAMPLE_SIZE 64ul | ||
8 | #define MAX_CPUS 128 | ||
9 | |||
10 | #define bpf_printk(fmt, ...) \ | ||
11 | ({ \ | ||
12 | char ____fmt[] = fmt; \ | ||
13 | bpf_trace_printk(____fmt, sizeof(____fmt), \ | ||
14 | ##__VA_ARGS__); \ | ||
15 | }) | ||
16 | |||
17 | struct bpf_map_def SEC("maps") my_map = { | ||
18 | .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY, | ||
19 | .key_size = sizeof(int), | ||
20 | .value_size = sizeof(u32), | ||
21 | .max_entries = MAX_CPUS, | ||
22 | }; | ||
23 | |||
24 | SEC("xdp_sample") | ||
25 | int xdp_sample_prog(struct xdp_md *ctx) | ||
26 | { | ||
27 | void *data_end = (void *)(long)ctx->data_end; | ||
28 | void *data = (void *)(long)ctx->data; | ||
29 | |||
30 | /* Metadata will be in the perf event before the packet data. */ | ||
31 | struct S { | ||
32 | u16 cookie; | ||
33 | u16 pkt_len; | ||
34 | } __packed metadata; | ||
35 | |||
36 | if (data < data_end) { | ||
37 | /* The XDP perf_event_output handler will use the upper 32 bits | ||
38 | * of the flags argument as a number of bytes to include of the | ||
39 | * packet payload in the event data. If the size is too big, the | ||
40 | * call to bpf_perf_event_output will fail and return -EFAULT. | ||
41 | * | ||
42 | * See bpf_xdp_event_output in net/core/filter.c. | ||
43 | * | ||
44 | * The BPF_F_CURRENT_CPU flag means that the event output fd | ||
45 | * will be indexed by the CPU number in the event map. | ||
46 | */ | ||
47 | u64 flags = BPF_F_CURRENT_CPU; | ||
48 | u16 sample_size; | ||
49 | int ret; | ||
50 | |||
51 | metadata.cookie = 0xdead; | ||
52 | metadata.pkt_len = (u16)(data_end - data); | ||
53 | sample_size = min(metadata.pkt_len, SAMPLE_SIZE); | ||
54 | flags |= (u64)sample_size << 32; | ||
55 | |||
56 | ret = bpf_perf_event_output(ctx, &my_map, flags, | ||
57 | &metadata, sizeof(metadata)); | ||
58 | if (ret) | ||
59 | bpf_printk("perf_event_output failed: %d\n", ret); | ||
60 | } | ||
61 | |||
62 | return XDP_PASS; | ||
63 | } | ||
64 | |||
65 | char _license[] SEC("license") = "GPL"; | ||
66 | u32 _version SEC("version") = LINUX_VERSION_CODE; | ||
diff --git a/samples/bpf/xdp_sample_pkts_user.c b/samples/bpf/xdp_sample_pkts_user.c new file mode 100644 index 000000000000..8dd87c1eb560 --- /dev/null +++ b/samples/bpf/xdp_sample_pkts_user.c | |||
@@ -0,0 +1,169 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | #include <stdio.h> | ||
3 | #include <stdlib.h> | ||
4 | #include <string.h> | ||
5 | #include <linux/perf_event.h> | ||
6 | #include <linux/bpf.h> | ||
7 | #include <net/if.h> | ||
8 | #include <errno.h> | ||
9 | #include <assert.h> | ||
10 | #include <sys/sysinfo.h> | ||
11 | #include <sys/ioctl.h> | ||
12 | #include <signal.h> | ||
13 | #include <libbpf.h> | ||
14 | #include <bpf/bpf.h> | ||
15 | |||
16 | #include "perf-sys.h" | ||
17 | #include "trace_helpers.h" | ||
18 | |||
19 | #define MAX_CPUS 128 | ||
20 | static int pmu_fds[MAX_CPUS], if_idx; | ||
21 | static struct perf_event_mmap_page *headers[MAX_CPUS]; | ||
22 | static char *if_name; | ||
23 | |||
24 | static int do_attach(int idx, int fd, const char *name) | ||
25 | { | ||
26 | int err; | ||
27 | |||
28 | err = bpf_set_link_xdp_fd(idx, fd, 0); | ||
29 | if (err < 0) | ||
30 | printf("ERROR: failed to attach program to %s\n", name); | ||
31 | |||
32 | return err; | ||
33 | } | ||
34 | |||
35 | static int do_detach(int idx, const char *name) | ||
36 | { | ||
37 | int err; | ||
38 | |||
39 | err = bpf_set_link_xdp_fd(idx, -1, 0); | ||
40 | if (err < 0) | ||
41 | printf("ERROR: failed to detach program from %s\n", name); | ||
42 | |||
43 | return err; | ||
44 | } | ||
45 | |||
46 | #define SAMPLE_SIZE 64 | ||
47 | |||
48 | static int print_bpf_output(void *data, int size) | ||
49 | { | ||
50 | struct { | ||
51 | __u16 cookie; | ||
52 | __u16 pkt_len; | ||
53 | __u8 pkt_data[SAMPLE_SIZE]; | ||
54 | } __packed *e = data; | ||
55 | int i; | ||
56 | |||
57 | if (e->cookie != 0xdead) { | ||
58 | printf("BUG cookie %x sized %d\n", | ||
59 | e->cookie, size); | ||
60 | return LIBBPF_PERF_EVENT_ERROR; | ||
61 | } | ||
62 | |||
63 | printf("Pkt len: %-5d bytes. Ethernet hdr: ", e->pkt_len); | ||
64 | for (i = 0; i < 14 && i < e->pkt_len; i++) | ||
65 | printf("%02x ", e->pkt_data[i]); | ||
66 | printf("\n"); | ||
67 | |||
68 | return LIBBPF_PERF_EVENT_CONT; | ||
69 | } | ||
70 | |||
71 | static void test_bpf_perf_event(int map_fd, int num) | ||
72 | { | ||
73 | struct perf_event_attr attr = { | ||
74 | .sample_type = PERF_SAMPLE_RAW, | ||
75 | .type = PERF_TYPE_SOFTWARE, | ||
76 | .config = PERF_COUNT_SW_BPF_OUTPUT, | ||
77 | .wakeup_events = 1, /* get an fd notification for every event */ | ||
78 | }; | ||
79 | int i; | ||
80 | |||
81 | for (i = 0; i < num; i++) { | ||
82 | int key = i; | ||
83 | |||
84 | pmu_fds[i] = sys_perf_event_open(&attr, -1/*pid*/, i/*cpu*/, | ||
85 | -1/*group_fd*/, 0); | ||
86 | |||
87 | assert(pmu_fds[i] >= 0); | ||
88 | assert(bpf_map_update_elem(map_fd, &key, | ||
89 | &pmu_fds[i], BPF_ANY) == 0); | ||
90 | ioctl(pmu_fds[i], PERF_EVENT_IOC_ENABLE, 0); | ||
91 | } | ||
92 | } | ||
93 | |||
94 | static void sig_handler(int signo) | ||
95 | { | ||
96 | do_detach(if_idx, if_name); | ||
97 | exit(0); | ||
98 | } | ||
99 | |||
100 | int main(int argc, char **argv) | ||
101 | { | ||
102 | struct bpf_prog_load_attr prog_load_attr = { | ||
103 | .prog_type = BPF_PROG_TYPE_XDP, | ||
104 | }; | ||
105 | struct bpf_object *obj; | ||
106 | struct bpf_map *map; | ||
107 | int prog_fd, map_fd; | ||
108 | char filename[256]; | ||
109 | int ret, err, i; | ||
110 | int numcpus; | ||
111 | |||
112 | if (argc < 2) { | ||
113 | printf("Usage: %s <ifname>\n", argv[0]); | ||
114 | return 1; | ||
115 | } | ||
116 | |||
117 | numcpus = get_nprocs(); | ||
118 | if (numcpus > MAX_CPUS) | ||
119 | numcpus = MAX_CPUS; | ||
120 | |||
121 | snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); | ||
122 | prog_load_attr.file = filename; | ||
123 | |||
124 | if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd)) | ||
125 | return 1; | ||
126 | |||
127 | if (!prog_fd) { | ||
128 | printf("load_bpf_file: %s\n", strerror(errno)); | ||
129 | return 1; | ||
130 | } | ||
131 | |||
132 | map = bpf_map__next(NULL, obj); | ||
133 | if (!map) { | ||
134 | printf("finding a map in obj file failed\n"); | ||
135 | return 1; | ||
136 | } | ||
137 | map_fd = bpf_map__fd(map); | ||
138 | |||
139 | if_idx = if_nametoindex(argv[1]); | ||
140 | if (!if_idx) | ||
141 | if_idx = strtoul(argv[1], NULL, 0); | ||
142 | |||
143 | if (!if_idx) { | ||
144 | fprintf(stderr, "Invalid ifname\n"); | ||
145 | return 1; | ||
146 | } | ||
147 | if_name = argv[1]; | ||
148 | err = do_attach(if_idx, prog_fd, argv[1]); | ||
149 | if (err) | ||
150 | return err; | ||
151 | |||
152 | if (signal(SIGINT, sig_handler) || | ||
153 | signal(SIGHUP, sig_handler) || | ||
154 | signal(SIGTERM, sig_handler)) { | ||
155 | perror("signal"); | ||
156 | return 1; | ||
157 | } | ||
158 | |||
159 | test_bpf_perf_event(map_fd, numcpus); | ||
160 | |||
161 | for (i = 0; i < numcpus; i++) | ||
162 | if (perf_event_mmap_header(pmu_fds[i], &headers[i]) < 0) | ||
163 | return 1; | ||
164 | |||
165 | ret = perf_event_poller_multi(pmu_fds, headers, numcpus, | ||
166 | print_bpf_output); | ||
167 | kill(0, SIGINT); | ||
168 | return ret; | ||
169 | } | ||
diff --git a/samples/bpf/xdpsock_user.c b/samples/bpf/xdpsock_user.c index 5904b1543831..4914788b6727 100644 --- a/samples/bpf/xdpsock_user.c +++ b/samples/bpf/xdpsock_user.c | |||
@@ -26,7 +26,7 @@ | |||
26 | #include <sys/types.h> | 26 | #include <sys/types.h> |
27 | #include <poll.h> | 27 | #include <poll.h> |
28 | 28 | ||
29 | #include "bpf_load.h" | 29 | #include "bpf/libbpf.h" |
30 | #include "bpf_util.h" | 30 | #include "bpf_util.h" |
31 | #include <bpf/bpf.h> | 31 | #include <bpf/bpf.h> |
32 | 32 | ||
@@ -145,8 +145,13 @@ static void dump_stats(void); | |||
145 | } while (0) | 145 | } while (0) |
146 | 146 | ||
147 | #define barrier() __asm__ __volatile__("": : :"memory") | 147 | #define barrier() __asm__ __volatile__("": : :"memory") |
148 | #ifdef __aarch64__ | ||
149 | #define u_smp_rmb() __asm__ __volatile__("dmb ishld": : :"memory") | ||
150 | #define u_smp_wmb() __asm__ __volatile__("dmb ishst": : :"memory") | ||
151 | #else | ||
148 | #define u_smp_rmb() barrier() | 152 | #define u_smp_rmb() barrier() |
149 | #define u_smp_wmb() barrier() | 153 | #define u_smp_wmb() barrier() |
154 | #endif | ||
150 | #define likely(x) __builtin_expect(!!(x), 1) | 155 | #define likely(x) __builtin_expect(!!(x), 1) |
151 | #define unlikely(x) __builtin_expect(!!(x), 0) | 156 | #define unlikely(x) __builtin_expect(!!(x), 0) |
152 | 157 | ||
@@ -886,7 +891,13 @@ static void l2fwd(struct xdpsock *xsk) | |||
886 | int main(int argc, char **argv) | 891 | int main(int argc, char **argv) |
887 | { | 892 | { |
888 | struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY}; | 893 | struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY}; |
894 | struct bpf_prog_load_attr prog_load_attr = { | ||
895 | .prog_type = BPF_PROG_TYPE_XDP, | ||
896 | }; | ||
897 | int prog_fd, qidconf_map, xsks_map; | ||
898 | struct bpf_object *obj; | ||
889 | char xdp_filename[256]; | 899 | char xdp_filename[256]; |
900 | struct bpf_map *map; | ||
890 | int i, ret, key = 0; | 901 | int i, ret, key = 0; |
891 | pthread_t pt; | 902 | pthread_t pt; |
892 | 903 | ||
@@ -899,24 +910,38 @@ int main(int argc, char **argv) | |||
899 | } | 910 | } |
900 | 911 | ||
901 | snprintf(xdp_filename, sizeof(xdp_filename), "%s_kern.o", argv[0]); | 912 | snprintf(xdp_filename, sizeof(xdp_filename), "%s_kern.o", argv[0]); |
913 | prog_load_attr.file = xdp_filename; | ||
902 | 914 | ||
903 | if (load_bpf_file(xdp_filename)) { | 915 | if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd)) |
904 | fprintf(stderr, "ERROR: load_bpf_file %s\n", bpf_log_buf); | 916 | exit(EXIT_FAILURE); |
917 | if (prog_fd < 0) { | ||
918 | fprintf(stderr, "ERROR: no program found: %s\n", | ||
919 | strerror(prog_fd)); | ||
905 | exit(EXIT_FAILURE); | 920 | exit(EXIT_FAILURE); |
906 | } | 921 | } |
907 | 922 | ||
908 | if (!prog_fd[0]) { | 923 | map = bpf_object__find_map_by_name(obj, "qidconf_map"); |
909 | fprintf(stderr, "ERROR: load_bpf_file: \"%s\"\n", | 924 | qidconf_map = bpf_map__fd(map); |
910 | strerror(errno)); | 925 | if (qidconf_map < 0) { |
926 | fprintf(stderr, "ERROR: no qidconf map found: %s\n", | ||
927 | strerror(qidconf_map)); | ||
928 | exit(EXIT_FAILURE); | ||
929 | } | ||
930 | |||
931 | map = bpf_object__find_map_by_name(obj, "xsks_map"); | ||
932 | xsks_map = bpf_map__fd(map); | ||
933 | if (xsks_map < 0) { | ||
934 | fprintf(stderr, "ERROR: no xsks map found: %s\n", | ||
935 | strerror(xsks_map)); | ||
911 | exit(EXIT_FAILURE); | 936 | exit(EXIT_FAILURE); |
912 | } | 937 | } |
913 | 938 | ||
914 | if (bpf_set_link_xdp_fd(opt_ifindex, prog_fd[0], opt_xdp_flags) < 0) { | 939 | if (bpf_set_link_xdp_fd(opt_ifindex, prog_fd, opt_xdp_flags) < 0) { |
915 | fprintf(stderr, "ERROR: link set xdp fd failed\n"); | 940 | fprintf(stderr, "ERROR: link set xdp fd failed\n"); |
916 | exit(EXIT_FAILURE); | 941 | exit(EXIT_FAILURE); |
917 | } | 942 | } |
918 | 943 | ||
919 | ret = bpf_map_update_elem(map_fd[0], &key, &opt_queue, 0); | 944 | ret = bpf_map_update_elem(qidconf_map, &key, &opt_queue, 0); |
920 | if (ret) { | 945 | if (ret) { |
921 | fprintf(stderr, "ERROR: bpf_map_update_elem qidconf\n"); | 946 | fprintf(stderr, "ERROR: bpf_map_update_elem qidconf\n"); |
922 | exit(EXIT_FAILURE); | 947 | exit(EXIT_FAILURE); |
@@ -933,7 +958,7 @@ int main(int argc, char **argv) | |||
933 | /* ...and insert them into the map. */ | 958 | /* ...and insert them into the map. */ |
934 | for (i = 0; i < num_socks; i++) { | 959 | for (i = 0; i < num_socks; i++) { |
935 | key = i; | 960 | key = i; |
936 | ret = bpf_map_update_elem(map_fd[1], &key, &xsks[i]->sfd, 0); | 961 | ret = bpf_map_update_elem(xsks_map, &key, &xsks[i]->sfd, 0); |
937 | if (ret) { | 962 | if (ret) { |
938 | fprintf(stderr, "ERROR: bpf_map_update_elem %d\n", i); | 963 | fprintf(stderr, "ERROR: bpf_map_update_elem %d\n", i); |
939 | exit(EXIT_FAILURE); | 964 | exit(EXIT_FAILURE); |