【问题标题】:eBPF packet monitor losing some packets when 'ping -f'edeBPF 数据包监视器在“ping -f”时丢失了一些数据包
【发布时间】:2020-05-26 15:04:39
【问题描述】:

我编写了这个程序来捕获进入我的网络接口的所有数据包。 它似乎适用于 ping [IP] 之类的东西。 它也适用于 ping -f [IP] -c 10。 但是,当被 ping 的数据包数量增加到 200 个时,程序会丢失一些数据包。 这是 eBPF 的自然限制还是我做错了什么? 这是代码:

另外,当我 ping -f [IP] -c 500 时,它还会输出:“可能丢失 10 个样本”或“可能丢失 34 个样本”

 from bcc import BPF

# Network interface to be monoitored
INTERFACE = "my_interface"

bpf_text = """
#include <uapi/linux/ptrace.h>
#include <net/sock.h>
#include <bcc/proto.h>
#include <linux/bpf.h>
#define IP_TCP 6
#define IP_UDP 17
#define IP_ICMP 1
#define ETH_HLEN 14
BPF_PERF_OUTPUT(skb_events);    // has to be delcared outside any function
BPF_ARRAY(black_list, u64, 5);
int packet_monitor(struct __sk_buff *skb) {
    u8 *cursor = 0;
    u32 saddr;
    u32 daddr;
    u32 ttl;
    u32 hchecksum;

    u64 magic = 111;
    u64 magic2 = 111;

    struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
    if (!(ethernet -> type == 0x0800)) {
        return 0; // drop
    }
    struct ip_t *ip = cursor_advance(cursor, sizeof(*ip));
    /*
    if (ip->nextp != IP_TCP) 
    {
        if (ip -> nextp != IP_UDP) 
        {
            if (ip -> nextp != IP_ICMP) 
                return 0; 
        }
    }
    */

    skb_events.perf_submit_skb(skb, skb -> len, &magic, sizeof(magic));
    saddr = ip -> src;
    daddr = ip -> dst;
    ttl = ip -> ttl;
    hchecksum = ip -> hchecksum;
    magic = ip -> src;
    magic2 = ip -> dst;
    skb_events.perf_submit_skb(skb, skb->len, &magic, sizeof(magic)); // this one parses number as a hex to the user space
    skb_events.perf_submit_skb(skb, skb->len, &magic2, sizeof(magic2)); // can send multiple values like this


    bpf_trace_printk("saddr = %llu, daddr = %llu, ttl = %llu", saddr, daddr, ttl); 
//    bpf_trace_printk("Incoming packet!!\\n");
    return -1;
}
"""

from ctypes import *
import ctypes as ct
import sys
import socket
import os
import struct

def print_skb_event(cpu, data, size):
    class SkbEvent(ct.Structure):
        _fields_ = [ ("magic", ct.c_uint32), ("magic2", ct.c_uint32)]

    skb_event = ct.cast(data, ct.POINTER(SkbEvent)).contents 
    print("- : ")
    print("%d" % (skb_event.magic))

bpf = BPF(text=bpf_text)

function_skb_matching = bpf.load_func("packet_monitor", BPF.SOCKET_FILTER)

BPF.attach_raw_socket(function_skb_matching, INTERFACE)

bpf["skb_events"].open_perf_buffer(print_skb_event)

black_list = bpf.get_table("black_list")    # retrieve blacklist list

try:
    while True :
        bpf.perf_buffer_poll()  # value = bpf.perf_buffer_poll() function does not return any function and therefore, doesn't work
except KeyboardInterrupt:
    pass

【问题讨论】:

    标签: bpf ebpf bcc-bpf


    【解决方案1】:

    是的,这是 perf 环形缓冲区的限制。如果 BPF 程序在环形缓冲区上产生事件的速度快于用户空间(Python)进程消耗它们的速度,那么一些事件将会丢失(因为它是一个环形而被覆盖)。 Possibly lost XX samples 消息是发生这种情况的通知。

    我首先建议您尝试在 BPF 端将多个 skb_events.perf_submit_skb 调用组合成一个单独的调用。这可能会有所帮助。否则,您可以尝试在 BPF 端聚合数据,以减少发送到 Python 端的信息。

    【讨论】:

    • 非常感谢您的帮助!我会尽量听从你的建议!我什至没有考虑环形缓冲区,我在想这个“瓶颈”会在哪里。非常感谢! :))
    • 我还有一个问题!您是否认为使用 eBPF 捕获每个数据包而不会丢失理论上是不可能的,可能是由于诸如环形缓冲区等问题?
    • 取决于您的数据包速率、CPU 等
    • 好的。谢谢您的帮助! :))
    猜你喜欢
    • 1970-01-01
    • 2023-01-08
    • 2017-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-04
    • 1970-01-01
    • 2021-06-04
    相关资源
    最近更新 更多