C 为什么ebpf程序内部样本/bpf不';不行?

C 为什么ebpf程序内部样本/bpf不';不行?,c,kernel,bpf,ebpf,C,Kernel,Bpf,Ebpf,目标:在4.18.0内核源代码树的samples/bpf目录中编写一个新的ebpf示例,编译并执行它 问题:编译后,当我运行sudo./mine时,它就终止了 mine_kern.c #include <uapi/linux/bpf.h> #include <uapi/linux/if_ether.h> #include <uapi/linux/ip.h> #include <linux/in.h> #include <linux/if_pa

目标:在4.18.0内核源代码树的
samples/bpf
目录中编写一个新的
ebpf
示例,编译并执行它

问题:编译后,当我运行
sudo./mine
时,它就终止了

mine_kern.c

#include <uapi/linux/bpf.h>
#include <uapi/linux/if_ether.h>
#include <uapi/linux/ip.h>
#include <linux/in.h>
#include <linux/if_packet.h>
#include "bpf_helpers.h" 

int icmp_filter(struct __sk_buff *skb){

        int proto = load_byte(skb, ETH_HLEN + offsetof(struct iphdr, protocol));
        if(proto == IPPROTO_ICMP && skb->pkt_type == PACKET_OUTGOING){
           return -1;
        } else {
           return 0;
        }
}

char _license[] SEC("license") = "GPL";
#include <stdio.h>
#include <assert.h>
#include <linux/bpf.h>
#include <bpf/bpf.h>
#include "bpf_load.h"
#include "sock_example.h"
#include <unistd.h>
#include <arpa/inet.h>    

int main(int ac, char **argv)
{
    char filename[256];
    FILE *f;
    int i, sock;

    snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);

    if (load_bpf_file(filename)) {
        printf("%s", bpf_log_buf);
        return 1;
    }   

    sock = open_raw_sock("lo");

    assert(setsockopt(sock, SOL_SOCKET, SO_ATTACH_BPF, prog_fd,
              sizeof(prog_fd[0])) == 0);

    f = popen("ping -c5 localhost", "r");
    (void) f;

    char buf[65535];

    for(i=0; i<20; i++){
           int res = recvfrom(sock, buf, sizeof(buf), 0, NULL, 0);
           printf("res=%d\n", res);
     } 

     return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括“bpf_helpers.h”
int icmp_筛选器(结构_sk_buff*skb){
int proto=加载字节(skb,ETH_HLEN+偏移量(结构iphdr,协议));
if(proto==IPPROTO\u ICMP&&skb->pkt\u type==PACKET\u传出){
返回-1;
}否则{
返回0;
}
}
字符_许可证[]秒(“许可证”)=“GPL”;
mine\u user.c

#include <uapi/linux/bpf.h>
#include <uapi/linux/if_ether.h>
#include <uapi/linux/ip.h>
#include <linux/in.h>
#include <linux/if_packet.h>
#include "bpf_helpers.h" 

int icmp_filter(struct __sk_buff *skb){

        int proto = load_byte(skb, ETH_HLEN + offsetof(struct iphdr, protocol));
        if(proto == IPPROTO_ICMP && skb->pkt_type == PACKET_OUTGOING){
           return -1;
        } else {
           return 0;
        }
}

char _license[] SEC("license") = "GPL";
#include <stdio.h>
#include <assert.h>
#include <linux/bpf.h>
#include <bpf/bpf.h>
#include "bpf_load.h"
#include "sock_example.h"
#include <unistd.h>
#include <arpa/inet.h>    

int main(int ac, char **argv)
{
    char filename[256];
    FILE *f;
    int i, sock;

    snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);

    if (load_bpf_file(filename)) {
        printf("%s", bpf_log_buf);
        return 1;
    }   

    sock = open_raw_sock("lo");

    assert(setsockopt(sock, SOL_SOCKET, SO_ATTACH_BPF, prog_fd,
              sizeof(prog_fd[0])) == 0);

    f = popen("ping -c5 localhost", "r");
    (void) f;

    char buf[65535];

    for(i=0; i<20; i++){
           int res = recvfrom(sock, buf, sizeof(buf), 0, NULL, 0);
           printf("res=%d\n", res);
     } 

     return 0;
}
#包括
#包括
#包括
#包括
#包括“bpf_load.h”
#包括“sock_example.h”
#包括
#包括
int main(int ac,字符**argv)
{
字符文件名[256];
文件*f;
inti,sock;
snprintf(文件名,sizeof(文件名),“%s_kern.o”,argv[0]);
if(加载文件名){
printf(“%s”,bpf\u log\u buf);
返回1;
}   
短袜=未加工短袜(“lo”);
断言(setsockopt)(sock、SOL_SOCKET、SO_ATTACH_BPF、prog_fd、,
sizeof(prog_fd[0])==0;
f=popen(“ping-c5本地主机”,“r”);
(f)无效;
char-buf[65535];

对于(i=0;i由于
load\u bpf\u file()
加载函数的方式,您需要将bpf程序函数放在单独的ELF部分中。例如,我可以使用以下方法加载程序:

SEC(“套接字”)
int icmp_筛选器(结构_sk_buff*skb){
...
}
在那之后,我在运行程序时看到一系列的
res=-1
。这是因为您的套接字被
open\u raw\u sock()
sock\u example.h
设置为非阻塞:

sock=socket(PF_数据包,sock_原始| sock_非块| sock_CLOEXEC,htons(ETH_P_ALL));

<> P>当没有数据包接收时,<代码> RevFor()/Case>简单地返回<代码> -1 (并设置<代码> ErnNO./COD> > <代码> -EGAIN < /代码> -您应该考虑打印<代码> SrrError(ErnO)< /C>而不是等待数据包。因此,您可能也想更改它。

是否尝试调试用户空间程序?我已尝试放置一些printf并将其输入到第一个文件中,如果是这样,它将由于return 1;语句而终止。此外,如果printf(%s,bpf_log__buf)没有打印任何内容。再次感谢!1)SEC()需要特定的名称?因为我尝试使用像SEC(“mine”)这样的随机名称,但它不起作用(mine\u user mine\u kern是文件的名称)。然后我尝试了我在另一个示例中看到的一个名称(例如SEC(“socket1”),效果很好2)为什么套接字是以非阻塞方式打开的?我可以自己打开一个套接字而不使用SOCK\u NONBLOCK吗?或者我不鼓励这样做?在您的示例中,您没有使用libbpf。您使用了
bpf\u load.c
,并且它需要一个特定的前缀,在您的示例中:
socket
。请参见。2)这只是示例的编码方式,再次参见代码/:美国er应用程序不读取套接字,只读取BPF映射。我不明白为什么不应该阻止打开经典的阻塞套接字。BPF\u load.c
的大部分内容都早于libbpf。这导致了BPF程序使用各种加载程序的情况。今天,大多数程序都迁移到了libbpf,这应该是处理BPF对象文件和pr的参考grams。一些示例仍然使用
bpf\u load.c
(我不记得该文件甚至可能包含libbpf本身的一些内容)。请随意试用这个加载程序,但如果您构建了一个严肃的项目,一定要使用libbpf(并且从内核树构建程序,这可能会让您的生活更轻松)。您不需要自己使用系统调用,libbpf可以为您处理。除了headers/includes之外,3)与1)相同。您可以从树中获取libbpf,您可以下载、安装并与任何其他C库一样使用。您看过我提供的示例了吗?从树中使用libbpf来构建程序(libbpf GitHub repo是作为Git子模块添加的)。除了构建它之外,
bpftool
可以处理任何BPF内容,而不仅仅是内核中的示例。不,
BPF()
手册页完全过时了。关于权限,对于大多数命令和程序类型,您都需要此功能,但对于某些cgroup内容,则需要此功能。