Linux kernel 如何使用BPF访问内核变量?

Linux kernel 如何使用BPF访问内核变量?,linux-kernel,kernel,bpf,ebpf,Linux Kernel,Kernel,Bpf,Ebpf,例如,要访问函数ip_rcv中的skb变量: int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { ... } 我搜索了互联网,但没有找到任何示例。用BPF截取内核函数最简单的方法可能是使用。它提供了一个更高级别的Python API,用于在内核中加载BPF程序并与之交互: #/usr/bin/env py

例如,要访问函数
ip_rcv
中的
skb
变量:

int ip_rcv(struct sk_buff *skb, struct net_device *dev,
           struct packet_type *pt, struct net_device *orig_dev)
{
...
}

我搜索了互联网,但没有找到任何示例。

用BPF截取内核函数最简单的方法可能是使用。它提供了一个更高级别的Python API,用于在内核中加载BPF程序并与之交互:

#/usr/bin/env python
从密件抄送导入BPF
BPF(text=”“”
int kprobe_uuuIP_rcv(结构pt_uregs*ctx,结构sk_ubuff*skb){
bpf_trace_printk(“skb=%p!\\n”,skb);
返回0;
}
“”)。trace_print()
返回:

      <idle>-0     [007] d.s.  1441.065248: : skb=ffff906b2bd53400!
      <idle>-0     [007] d.s.  1442.267325: : skb=ffff906b76c5b700!
      <idle>-0     [007] d.s.  1442.993894: : skb=ffff906b42b76800!
      <idle>-0     [007] d.s.  1443.194334: : skb=ffff906be925d300!
      <idle>-0     [007] d.s.  1444.616469: : skb=ffff906b67e6a200!
-0[007]d.s.1441.065248::skb=ffff906b2bd53400!
-0[007]d.s.1442.267325::skb=ffff906b76c5b700!
-0[007]d.s.1442.993894::skb=ffff906b42b76800!
-0[007]d.s.1443.194334::skb=ffff906be925d300!
-0[007]d.s.1444.616469::skb=ffff906b67e6a200!
有关详细信息,请参见bcc存储库的


如果不想使用bcc,可以在Linux内核中找到。特别是,我邀请您查看
tracex1\u kern/user.c

您还可以通过将其附加到原始套接字(如下面尝试筛选和解析HTTP数据包的程序)来访问它。 C BPF计划应如下所示:

int http_筛选器(结构_sk_buff*skb){

u8*光标=0;
结构以太网=游标前进(游标,大小(*以太网));
//过滤IP数据包(以太网类型=0x0800)
如果(!(以太网->类型==0x0800)){
跳投;
}
struct ip_t*ip=cursor_advance(cursor,sizeof(*ip));
//过滤TCP数据包(ip下一个协议=0x06)
如果(ip->nextp!=ip\U TCP){
跳投;
}
u32 tcp_头_长度=0;
u32 ip_头_长度=0;
u32有效载荷_偏移=0;
u32有效载荷长度=0;
结构键;
结构叶零={0};
//计算ip报头长度
//要乘以*4的值
//e、 g.ip->hlen=5;ip头长度=5 x 4字节=20字节
ip_头_长度=ip->hlen*4乘
//根据最小值检查ip标头长度
if(ip_头_长度dst;
key.src_ip=ip->src;
key.dst_port=tcp->dst_port;
key.src_port=tcp->src_port;
//计算tcp报头长度
//要乘以*4的值
//e、 g.tcp->offset=5;tcp头长度=5 x 4字节=20字节
tcp\u头\u长度=tcp->offset*4乘法
//计算有效载荷偏移量和长度
有效负载偏移量=以太网连接+ip连接头长度+tcp连接头长度;
有效负载长度=ip->tlen-ip\U头长度-tcp\U头长度;
//http://stackoverflow.com/questions/25047905/http-request-minimum-size-in-bytes
//http请求的最小长度始终大于7字节
//避免无效访问内存
//包括空有效载荷
如果(有效载荷长度<7){
跳投;
}
//将有效负载的前7字节加载到p(有效负载_数组)
//不允许直接访问skb
无符号长p[7];
int i=0;
对于(i=0;i<7;i++){
p[i]=加载字节(skb,有效载荷偏移量+i);
}
}

附加程序的Python脚本应如下所示: 而1: #从套接字检索原始数据包 数据包\u str=os.read(套接字\u fd,4096)

u8 *cursor = 0;

struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
//filter IP packets (ethernet type = 0x0800)
if (!(ethernet->type == 0x0800)) {
    goto DROP;
}

struct ip_t *ip = cursor_advance(cursor, sizeof(*ip));
//filter TCP packets (ip next protocol = 0x06)
if (ip->nextp != IP_TCP) {
    goto DROP;
}

u32  tcp_header_length = 0;
u32  ip_header_length = 0;
u32  payload_offset = 0;
u32  payload_length = 0;
struct Key  key;
struct Leaf zero = {0};

    //calculate ip header length
    //value to multiply * 4
    //e.g. ip->hlen = 5 ; IP Header Length = 5 x 4 byte = 20 byte
    ip_header_length = ip->hlen << 2;    //SHL 2 -> *4 multiply

    //check ip header length against minimum
    if (ip_header_length < sizeof(*ip)) {
            goto DROP;
    }

    //shift cursor forward for dynamic ip header size
    void *_ = cursor_advance(cursor, (ip_header_length-sizeof(*ip)));

struct tcp_t *tcp = cursor_advance(cursor, sizeof(*tcp));

//retrieve ip src/dest and port src/dest of current packet
//and save it into struct Key
key.dst_ip = ip->dst;
key.src_ip = ip->src;
key.dst_port = tcp->dst_port;
key.src_port = tcp->src_port;

//calculate tcp header length
//value to multiply *4
//e.g. tcp->offset = 5 ; TCP Header Length = 5 x 4 byte = 20 byte
tcp_header_length = tcp->offset << 2; //SHL 2 -> *4 multiply

//calculate payload offset and length
payload_offset = ETH_HLEN + ip_header_length + tcp_header_length;
payload_length = ip->tlen - ip_header_length - tcp_header_length;

//http://stackoverflow.com/questions/25047905/http-request-minimum-size-in-bytes
//minimum length of http request is always geater than 7 bytes
//avoid invalid access memory
//include empty payload
if(payload_length < 7) {
    goto DROP;
}

//load first 7 byte of payload into p (payload_array)
//direct access to skb not allowed
unsigned long p[7];
int i = 0;
for (i = 0; i < 7; i++) {
    p[i] = load_byte(skb , payload_offset + i);
}