forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
samples: bpf: example of stateful socket filtering
this socket filter example does: - creates arraymap in kernel with key 4 bytes and value 8 bytes - loads eBPF program which assumes that packet is IPv4 and loads one byte of IP->proto from the packet and uses it as a key in a map r0 = skb->data[ETH_HLEN + offsetof(struct iphdr, protocol)]; *(u32*)(fp - 4) = r0; value = bpf_map_lookup_elem(map_fd, fp - 4); if (value) (*(u64*)value) += 1; - attaches this program to raw socket - every second user space reads map[IPPROTO_TCP], map[IPPROTO_UDP], map[IPPROTO_ICMP] to see how many packets of given protocol were seen on loopback interface Usage: $sudo samples/bpf/sock_example TCP 0 UDP 0 ICMP 0 packets TCP 187600 UDP 0 ICMP 4 packets TCP 376504 UDP 0 ICMP 8 packets TCP 563116 UDP 0 ICMP 12 packets TCP 753144 UDP 0 ICMP 16 packets Signed-off-by: Alexei Starovoitov <[email protected]> Signed-off-by: David S. Miller <[email protected]>
- Loading branch information
Showing
4 changed files
with
144 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
/* eBPF example program: | ||
* - creates arraymap in kernel with key 4 bytes and value 8 bytes | ||
* | ||
* - loads eBPF program: | ||
* r0 = skb->data[ETH_HLEN + offsetof(struct iphdr, protocol)]; | ||
* *(u32*)(fp - 4) = r0; | ||
* // assuming packet is IPv4, lookup ip->proto in a map | ||
* value = bpf_map_lookup_elem(map_fd, fp - 4); | ||
* if (value) | ||
* (*(u64*)value) += 1; | ||
* | ||
* - attaches this program to eth0 raw socket | ||
* | ||
* - every second user space reads map[tcp], map[udp], map[icmp] to see | ||
* how many packets of given protocol were seen on eth0 | ||
*/ | ||
#include <stdio.h> | ||
#include <unistd.h> | ||
#include <assert.h> | ||
#include <linux/bpf.h> | ||
#include <string.h> | ||
#include <stdlib.h> | ||
#include <errno.h> | ||
#include <sys/socket.h> | ||
#include <arpa/inet.h> | ||
#include <linux/if_ether.h> | ||
#include <linux/ip.h> | ||
#include <stddef.h> | ||
#include "libbpf.h" | ||
|
||
static int test_sock(void) | ||
{ | ||
int sock = -1, map_fd, prog_fd, i, key; | ||
long long value = 0, tcp_cnt, udp_cnt, icmp_cnt; | ||
|
||
map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(key), sizeof(value), | ||
256); | ||
if (map_fd < 0) { | ||
printf("failed to create map '%s'\n", strerror(errno)); | ||
goto cleanup; | ||
} | ||
|
||
struct bpf_insn prog[] = { | ||
BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | ||
BPF_LD_ABS(BPF_B, ETH_HLEN + offsetof(struct iphdr, protocol) /* R0 = ip->proto */), | ||
BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -4), /* *(u32 *)(fp - 4) = r0 */ | ||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4), /* r2 = fp - 4 */ | ||
BPF_LD_MAP_FD(BPF_REG_1, map_fd), | ||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), | ||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), | ||
BPF_MOV64_IMM(BPF_REG_1, 1), /* r1 = 1 */ | ||
BPF_RAW_INSN(BPF_STX | BPF_XADD | BPF_DW, BPF_REG_0, BPF_REG_1, 0, 0), /* xadd r0 += r1 */ | ||
BPF_MOV64_IMM(BPF_REG_0, 0), /* r0 = 0 */ | ||
BPF_EXIT_INSN(), | ||
}; | ||
|
||
prog_fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, prog, sizeof(prog), | ||
"GPL"); | ||
if (prog_fd < 0) { | ||
printf("failed to load prog '%s'\n", strerror(errno)); | ||
goto cleanup; | ||
} | ||
|
||
sock = open_raw_sock("lo"); | ||
|
||
if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_BPF, &prog_fd, | ||
sizeof(prog_fd)) < 0) { | ||
printf("setsockopt %s\n", strerror(errno)); | ||
goto cleanup; | ||
} | ||
|
||
for (i = 0; i < 10; i++) { | ||
key = IPPROTO_TCP; | ||
assert(bpf_lookup_elem(map_fd, &key, &tcp_cnt) == 0); | ||
|
||
key = IPPROTO_UDP; | ||
assert(bpf_lookup_elem(map_fd, &key, &udp_cnt) == 0); | ||
|
||
key = IPPROTO_ICMP; | ||
assert(bpf_lookup_elem(map_fd, &key, &icmp_cnt) == 0); | ||
|
||
printf("TCP %lld UDP %lld ICMP %lld packets\n", | ||
tcp_cnt, udp_cnt, icmp_cnt); | ||
sleep(1); | ||
} | ||
|
||
cleanup: | ||
/* maps, programs, raw sockets will auto cleanup on process exit */ | ||
return 0; | ||
} | ||
|
||
int main(void) | ||
{ | ||
FILE *f; | ||
|
||
f = popen("ping -c5 localhost", "r"); | ||
(void)f; | ||
|
||
return test_sock(); | ||
} |