Skip to content

Commit 69e8cc1

Browse files
jrfastabdavem330
authored andcommitted
bpf: sockmap sample program
This program binds a program to a cgroup and then matches hard coded IP addresses and adds these to a sockmap. This will receive messages from the backend and send them to the client. client:X <---> frontend:10000 client:X <---> backend:10001 To keep things simple this is only designed for 1:1 connections using hard coded values. A more complete example would allow many backends and clients. To run, # sockmap <cgroup2_dir> Signed-off-by: John Fastabend <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 8a31db5 commit 69e8cc1

File tree

8 files changed

+547
-6
lines changed

8 files changed

+547
-6
lines changed

samples/bpf/bpf_load.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size)
6565
bool is_cgroup_skb = strncmp(event, "cgroup/skb", 10) == 0;
6666
bool is_cgroup_sk = strncmp(event, "cgroup/sock", 11) == 0;
6767
bool is_sockops = strncmp(event, "sockops", 7) == 0;
68+
bool is_sk_skb = strncmp(event, "sk_skb", 6) == 0;
6869
size_t insns_cnt = size / sizeof(struct bpf_insn);
6970
enum bpf_prog_type prog_type;
7071
char buf[256];
@@ -92,6 +93,8 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size)
9293
prog_type = BPF_PROG_TYPE_CGROUP_SOCK;
9394
} else if (is_sockops) {
9495
prog_type = BPF_PROG_TYPE_SOCK_OPS;
96+
} else if (is_sk_skb) {
97+
prog_type = BPF_PROG_TYPE_SK_SKB;
9598
} else {
9699
printf("Unknown event '%s'\n", event);
97100
return -1;
@@ -109,7 +112,7 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size)
109112
if (is_xdp || is_perf_event || is_cgroup_skb || is_cgroup_sk)
110113
return 0;
111114

112-
if (is_socket || is_sockops) {
115+
if (is_socket || is_sockops || is_sk_skb) {
113116
if (is_socket)
114117
event += 6;
115118
else
@@ -567,7 +570,8 @@ static int do_load_bpf_file(const char *path, fixup_map_cb fixup_map)
567570
memcmp(shname, "perf_event", 10) == 0 ||
568571
memcmp(shname, "socket", 6) == 0 ||
569572
memcmp(shname, "cgroup/", 7) == 0 ||
570-
memcmp(shname, "sockops", 7) == 0) {
573+
memcmp(shname, "sockops", 7) == 0 ||
574+
memcmp(shname, "sk_skb", 6) == 0) {
571575
ret = load_and_attach(shname, data->d_buf,
572576
data->d_size);
573577
if (ret != 0)

samples/sockmap/Makefile

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# kbuild trick to avoid linker error. Can be omitted if a module is built.
2+
obj- := dummy.o
3+
4+
# List of programs to build
5+
hostprogs-y := sockmap
6+
7+
# Libbpf dependencies
8+
LIBBPF := ../../tools/lib/bpf/bpf.o
9+
10+
HOSTCFLAGS += -I$(objtree)/usr/include
11+
HOSTCFLAGS += -I$(srctree)/tools/lib/
12+
HOSTCFLAGS += -I$(srctree)/tools/testing/selftests/bpf/
13+
HOSTCFLAGS += -I$(srctree)/tools/lib/ -I$(srctree)/tools/include
14+
HOSTCFLAGS += -I$(srctree)/tools/perf
15+
16+
sockmap-objs := ../bpf/bpf_load.o $(LIBBPF) sockmap_user.o
17+
18+
# Tell kbuild to always build the programs
19+
always := $(hostprogs-y)
20+
always += sockmap_kern.o
21+
22+
HOSTLOADLIBES_sockmap += -lelf -lpthread
23+
24+
# Allows pointing LLC/CLANG to a LLVM backend with bpf support, redefine on cmdline:
25+
# make samples/bpf/ LLC=~/git/llvm/build/bin/llc CLANG=~/git/llvm/build/bin/clang
26+
LLC ?= llc
27+
CLANG ?= clang
28+
29+
# Trick to allow make to be run from this directory
30+
all:
31+
$(MAKE) -C ../../ $(CURDIR)/
32+
33+
clean:
34+
$(MAKE) -C ../../ M=$(CURDIR) clean
35+
@rm -f *~
36+
37+
$(obj)/syscall_nrs.s: $(src)/syscall_nrs.c
38+
$(call if_changed_dep,cc_s_c)
39+
40+
$(obj)/syscall_nrs.h: $(obj)/syscall_nrs.s FORCE
41+
$(call filechk,offsets,__SYSCALL_NRS_H__)
42+
43+
clean-files += syscall_nrs.h
44+
45+
FORCE:
46+
47+
48+
# Verify LLVM compiler tools are available and bpf target is supported by llc
49+
.PHONY: verify_cmds verify_target_bpf $(CLANG) $(LLC)
50+
51+
verify_cmds: $(CLANG) $(LLC)
52+
@for TOOL in $^ ; do \
53+
if ! (which -- "$${TOOL}" > /dev/null 2>&1); then \
54+
echo "*** ERROR: Cannot find LLVM tool $${TOOL}" ;\
55+
exit 1; \
56+
else true; fi; \
57+
done
58+
59+
verify_target_bpf: verify_cmds
60+
@if ! (${LLC} -march=bpf -mattr=help > /dev/null 2>&1); then \
61+
echo "*** ERROR: LLVM (${LLC}) does not support 'bpf' target" ;\
62+
echo " NOTICE: LLVM version >= 3.7.1 required" ;\
63+
exit 2; \
64+
else true; fi
65+
66+
$(src)/*.c: verify_target_bpf
67+
68+
# asm/sysreg.h - inline assembly used by it is incompatible with llvm.
69+
# But, there is no easy way to fix it, so just exclude it since it is
70+
# useless for BPF samples.
71+
$(obj)/%.o: $(src)/%.c
72+
$(CLANG) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) $(EXTRA_CFLAGS) -I$(obj) \
73+
-D__KERNEL__ -D__ASM_SYSREG_H -Wno-unused-value -Wno-pointer-sign \
74+
-Wno-compare-distinct-pointer-types \
75+
-Wno-gnu-variable-sized-type-not-at-end \
76+
-Wno-address-of-packed-member -Wno-tautological-compare \
77+
-Wno-unknown-warning-option \
78+
-O2 -emit-llvm -c $< -o -| $(LLC) -march=bpf -filetype=obj -o $@

samples/sockmap/sockmap_kern.c

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/* Copyright (c) 2017 Covalent IO, Inc. http://covalent.io
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+
* This program is distributed in the hope that it will be useful, but
8+
* WITHOUT ANY WARRANTY; without even the implied warranty of
9+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10+
* General Public License for more details.
11+
*/
12+
#include <uapi/linux/bpf.h>
13+
#include <uapi/linux/if_ether.h>
14+
#include <uapi/linux/if_packet.h>
15+
#include <uapi/linux/ip.h>
16+
#include "../../tools/testing/selftests/bpf/bpf_helpers.h"
17+
#include "../../tools/testing/selftests/bpf/bpf_endian.h"
18+
19+
/* Sockmap sample program connects a client and a backend together
20+
* using cgroups.
21+
*
22+
* client:X <---> frontend:80 client:X <---> backend:80
23+
*
24+
* For simplicity we hard code values here and bind 1:1. The hard
25+
* coded values are part of the setup in sockmap.sh script that
26+
* is associated with this BPF program.
27+
*
28+
* The bpf_printk is verbose and prints information as connections
29+
* are established and verdicts are decided.
30+
*/
31+
32+
#define bpf_printk(fmt, ...) \
33+
({ \
34+
char ____fmt[] = fmt; \
35+
bpf_trace_printk(____fmt, sizeof(____fmt), \
36+
##__VA_ARGS__); \
37+
})
38+
39+
struct bpf_map_def SEC("maps") sock_map = {
40+
.type = BPF_MAP_TYPE_SOCKMAP,
41+
.key_size = sizeof(int),
42+
.value_size = sizeof(int),
43+
.max_entries = 20,
44+
};
45+
46+
SEC("sk_skb1")
47+
int bpf_prog1(struct __sk_buff *skb)
48+
{
49+
return skb->len;
50+
}
51+
52+
SEC("sk_skb2")
53+
int bpf_prog2(struct __sk_buff *skb)
54+
{
55+
__u32 lport = skb->local_port;
56+
__u32 rport = skb->remote_port;
57+
int ret = 0;
58+
59+
if (lport == 10000)
60+
ret = 10;
61+
else
62+
ret = 1;
63+
64+
bpf_printk("sockmap: %d -> %d @ %d\n", lport, bpf_ntohl(rport), ret);
65+
return bpf_sk_redirect_map(&sock_map, ret, 0);
66+
}
67+
68+
SEC("sockops")
69+
int bpf_sockmap(struct bpf_sock_ops *skops)
70+
{
71+
__u32 lport, rport;
72+
int op, err = 0, index, key, ret;
73+
74+
75+
op = (int) skops->op;
76+
77+
switch (op) {
78+
case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB:
79+
lport = skops->local_port;
80+
rport = skops->remote_port;
81+
82+
if (lport == 10000) {
83+
ret = 1;
84+
err = bpf_sock_map_update(skops, &sock_map, &ret,
85+
BPF_NOEXIST,
86+
BPF_SOCKMAP_STRPARSER);
87+
bpf_printk("passive(%i -> %i) map ctx update err: %d\n",
88+
lport, bpf_ntohl(rport), err);
89+
}
90+
break;
91+
case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB:
92+
lport = skops->local_port;
93+
rport = skops->remote_port;
94+
95+
if (bpf_ntohl(rport) == 10001) {
96+
ret = 10;
97+
err = bpf_sock_map_update(skops, &sock_map, &ret,
98+
BPF_NOEXIST,
99+
BPF_SOCKMAP_STRPARSER);
100+
bpf_printk("active(%i -> %i) map ctx update err: %d\n",
101+
lport, bpf_ntohl(rport), err);
102+
}
103+
break;
104+
default:
105+
break;
106+
}
107+
108+
return 0;
109+
}
110+
char _license[] SEC("license") = "GPL";

0 commit comments

Comments
 (0)