python - 使用 BPF 过滤器时 python 脚本的 CPU 使用率

标签 python linux networking cpu-usage bpf

我从 here 得到代码.

from binascii import hexlify
from ctypes import create_string_buffer, addressof
from socket import socket, AF_PACKET, SOCK_RAW, SOL_SOCKET
from struct import pack, unpack

sniff_interval=120
# A subset of Berkeley Packet Filter constants and macros, as defined in
# linux/filter.h.

# Instruction classes
BPF_LD = 0x00
BPF_JMP = 0x05
BPF_RET = 0x06

# ld/ldx fields
BPF_H = 0x08
BPF_B = 0x10
BPF_ABS = 0x20

# alu/jmp fields
BPF_JEQ = 0x10
BPF_K = 0x00

def bpf_jump(code, k, jt, jf):
    return pack('HBBI', code, jt, jf, k)

def bpf_stmt(code, k):
    return bpf_jump(code, k, 0, 0)


# Ordering of the filters is backwards of what would be intuitive for
# performance reasons: the check that is most likely to fail is first.
filters_list = [
    # Must have dst port 67. Load (BPF_LD) a half word value (BPF_H) in
    # ethernet frame at absolute byte offset 36 (BPF_ABS). If value is equal to
    # 67 then do not jump, else jump 5 statements.
    bpf_stmt(BPF_LD | BPF_H | BPF_ABS, 36),
    bpf_jump(BPF_JMP | BPF_JEQ | BPF_K, 5201, 0, 5),

    # Must be UDP (check protocol field at byte offset 23)
    bpf_stmt(BPF_LD | BPF_B | BPF_ABS, 23),
    bpf_jump(BPF_JMP | BPF_JEQ | BPF_K, 0x06, 0, 3),

    # Must be IPv4 (check ethertype field at byte offset 12)
    bpf_stmt(BPF_LD | BPF_H | BPF_ABS, 12),
    bpf_jump(BPF_JMP | BPF_JEQ | BPF_K, 0x0800, 0, 1),

    bpf_stmt(BPF_RET | BPF_K, 0x0fffffff), # pass
    bpf_stmt(BPF_RET | BPF_K, 0), # reject
]

# Create filters struct and fprog struct to be used by SO_ATTACH_FILTER, as
# defined in linux/filter.h.
filters = ''.join(filters_list)
b = create_string_buffer(filters)
mem_addr_of_filters = addressof(b)
fprog = pack('HL', len(filters_list), mem_addr_of_filters)

# As defined in asm/socket.h
SO_ATTACH_FILTER = 26

# Create listening socket with filters
s = socket(AF_PACKET, SOCK_RAW, 0x0800)
s.setsockopt(SOL_SOCKET, SO_ATTACH_FILTER, fprog)
s.bind(('eth0', 0x0800))

while True:
    data, addr = s.recvfrom(65565)
    #print "*****"
    print 'got data from', addr, ':', hexlify(data) #Have to print data, then only the CPU is 2%

我正在使用 iperf3 进行测试,通过以太网电缆生成从另一台笔记本电脑到我的笔记本电脑的流量。服务器(我的笔记本电脑)在 5021 上列出,客户端(另一台笔记本电脑)发送数据。

  • 如果我注释print 'got data from', addr, ':', hexlify(data),并运行脚本,脚本的CPU利用率 达到 30%,在 100MB 流量下达到 40%。
  • 如果我取消注释print 'got data from', addr, ':', hexlify(data) 并再次运行,在存在相同流量的情况下,CPU 下降到 2%。我入住了 htop

那么,这里发生了什么?

最佳答案

我敢打赌 hexlify() 或最有可能的 print(因为它必须与 STDOUT 同步)正在为您的主线程提供急需的中断,并且一个呼吸的空间,而不是在无限的 while 循环中敲打 socket 读数

尝试添加 time.sleep(0.05)(当然首先导入 time)而不是打印语句并再次检查 CPU 使用率。

关于python - 使用 BPF 过滤器时 python 脚本的 CPU 使用率,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42620540/

相关文章:

python - 如何使用 unicode 从 python 服务解析 JSON?语法错误 : Unexpected token u

python - 为什么要使用 sendrecv?

python - 在 numpy 中更有效地矢量化此卷积类型循环

c++ - 如何通过 glibc/malloc 回溯调试崩溃的 Linux 程序(无可用核心)?

c - 我如何跟踪内存分配?

macos - 如何在Scala中读取网络流?

windows-xp - 刷新内部 Windows 网络状态

python - Colab - 与谷歌驱动器连接的自动身份验证,每个笔记本的持久性

linux - 用于网络播放的链接视频(flash/html5 相当于 mplayer?)

networking - 在 Haskell 中列出网络接口(interface)