eBPF 数据包监视器在“ping -f”时丢失一些数据包
eBPF packet monitor losing some packets when 'ping -f'ed
我编写了这个程序来捕获进入我的网络接口的所有数据包。
它似乎适用于 ping [IP] 之类的东西。
它也适用于 ping -f [IP] -c 10。
然而,当被 ping 的数据包数量上升到大约 200 时,程序发现丢失了一些数据包。
这是 eBPF 的自然限制还是我做错了什么?
这是代码:
此外,当我 ping -f [IP] -c 500 时,它还会输出:"Possibly lost 10 samples" 或 "Possibly lost 34 samples"
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 程序在环形缓冲区上产生事件的速度快于用户空间 (Python) 进程可以消耗它们的速度,那么一些事件将会丢失(因为它是环形缓冲区而被覆盖)。 Possibly lost XX samples
消息是对这种情况的通知。
我首先建议您尝试在 BPF 端将多个 skb_events.perf_submit_skb
调用组合成一个。这可能会有所帮助。否则,您可以尝试在 BPF 端聚合数据,以减少发送到 Python 端的信息。
我编写了这个程序来捕获进入我的网络接口的所有数据包。 它似乎适用于 ping [IP] 之类的东西。 它也适用于 ping -f [IP] -c 10。 然而,当被 ping 的数据包数量上升到大约 200 时,程序发现丢失了一些数据包。 这是 eBPF 的自然限制还是我做错了什么? 这是代码:
此外,当我 ping -f [IP] -c 500 时,它还会输出:"Possibly lost 10 samples" 或 "Possibly lost 34 samples"
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 程序在环形缓冲区上产生事件的速度快于用户空间 (Python) 进程可以消耗它们的速度,那么一些事件将会丢失(因为它是环形缓冲区而被覆盖)。 Possibly lost XX samples
消息是对这种情况的通知。
我首先建议您尝试在 BPF 端将多个 skb_events.perf_submit_skb
调用组合成一个。这可能会有所帮助。否则,您可以尝试在 BPF 端聚合数据,以减少发送到 Python 端的信息。