一、前言
不要认为是一些小的demo而忽略对它的学习,往往一个复杂的代码,复杂的工程是一个个小demo拼接成的。
ebpf 网络过滤器这门技术在网络监控领域用的非常多,ebpf 编程我现在用的比较多的其实只有几个探针,kprobe、uprobe 以及linux网络过滤器。
今天读了 <<Linux内核观测技术BPF>>以及linux 内核源码中的sock_user1.c sock_kern.c ,linux内核的demo我认为写的还是很简单,而且这本书里面写的也很简单,打算对书里和linux内核的demo里的例子做一下实践。
内核代码很复杂,以后有空再看,今晚对linux 网络过滤器这块部分进行了实践。
心中一直有个疑问,好多网文都说他是cbpf的革新,那么cbpf filter 在pcap 中有过滤数据包能力,那ebpf是如何做到的呢?
二、实践
场景1:ebpf 统计网络包
ebpf程序
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright (c) 2020 Facebook */
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
/* Packet types */
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
#ifndef __BPF_LEGACY__
#define __BPF_LEGACY__
/* llvm builtin functions that eBPF C program may use to
* emit BPF_LD_ABS and BPF_LD_IND instructions
*/
unsigned long long load_byte(void *skb,
unsigned long long off) asm("llvm.bpf.load.byte");
unsigned long long load_half(void *skb,
unsigned long long off) asm("llvm.bpf.load.half");
unsigned long long load_word(void *skb,
unsigned long long off) asm("llvm.bpf.load.word");
#endif
#define PACKET_OUTGOING 4 /* Outgoing of any type */
#define ETH_ALEN 6 /* Octets in one ethernet addr */
#define ETH_TLEN 2 /* Octets in ethernet type field */
#define ETH_HLEN 14 /* Total octets in header. */
#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */
#define ETH_DATA_LEN 1500 /* Max. octets in payload */
#define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */
#define ETH_FCS_LEN 4 /* Octets in the FCS */
char LICENSE[] SEC("license") = "Dual BSD/GPL";
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__type(key, u32);
__type(value, long);
__uint(max_entries, 256);
} my_map SEC(".maps");
SEC("socket/test")
int bpf_prog1(struct __sk_buff *skb)
{
int index = load_byte(skb, ETH_HLEN + offsetof(struct iphdr, protocol));
long *value;
if (skb->pkt_type != PACKET_OUTGOING)
return -1;
value = bpf_map_lookup_elem(&my_map, &index);
if (value)
__sync_fetch_and_add(value, skb->len);
return 0;
}
char _license[] SEC("license") = "GPL";
编译ebpf程序:
/usr/bin/clang-14 -g -O2 -target bpf -D__TARGET_ARCH_x86_64 -c kern1.c -o kernel_write.o
user 部分程序
其实很简单 创建一个链路套接字,然后把我们的bpf程序使用SO_ATTACH_BPF附着上去就可以了
common.h
/* SPDX-License-Identifier: GPL-2.0 */
#include <stdlib.h>
#include <stdio.h>
#include <linux/unistd.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <linux/if_ether.h>
#include <net/if.h>
#include <linux/if_packet.h>
#include <arpa/inet.h>
static inline int open_raw_sock(const char *name)
{
struct sockaddr_ll sll;
int sock;
sock = socket(PF_PACKET, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, htons(ETH_P_ALL));
if (sock < 0) {
printf("cannot create raw socket\n");
return -1;
}
memset(&sll, 0, sizeof(sll));
sll.sll_family = AF_PACKET;
sll.sll_ifindex = if_nametoindex(name);
sll.sll_protocol = htons(ETH_P_ALL);
if (bind(sock, (struct sockaddr *)&sll, sizeof(s

本文介绍了EBPF(Extended Berkeley Packet Filter)在网络监控中的应用,通过实例展示了如何编写EBPF程序来统计网络包,并分析了不同返回值对RAW SOCKET数据包接收的影响。实践部分包括统计网络流量和过滤数据包,揭示了EBPF在流量监控和数据过滤方面的功能。
最低0.47元/天 解锁文章
2494

被折叠的 条评论
为什么被折叠?



