0
0

More than 3 years have passed since last update.

BCCでeBPFに入門

Last updated at Posted at 2020-05-09

eBPFは、ユーザが定義したプログラムをカーネルランドで実行するための仕組みです。計測、セキュリティ、ネットワーク処理などの利用用途があります。

BPF Compiler Collection (BCC)という、eBPFプログラムの作成や実行を簡易的に行うためのツールセットがあります。
カーネルランドで動かすBPFプログラムはCで書く必要がありますが、BPFプログラムの読み込みや出力のフォーマットなどはPython(もしくはlua)のバインディングを利用して書くことができます。

サンプルプログラム

ループバックインターフェイスに対するICMPパケットのみをドロップするプログラムを書いてみました。

BPFプログラムは次のとおりです。不正なメモリアクセスなどが発生しないように、データアクセスの前にそのデータ長を事前チェックするなど、堅牢なプログラムにしておかないとverifierで弾かれるので注意。

prog.c
#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/in.h>
#include <linux/ip.h>

int prog(struct xdp_md *ctx) {
    int ipsize = 0;
    void *data = (void *)(long)ctx->data;
    void *data_end = (void *)(long)ctx->data_end;
    struct ethhdr *eth = data;
    struct iphdr *ip;

    ipsize = sizeof(*eth);
    ip = data + ipsize;
    ipsize = sizeof(struct iphdr);
    if (data + ipsize > data_end) {
        return XDP_PASS;
    }

    if ((void *)&ip[1] > data_end) {
        return XDP_PASS;
    }

    if (ip->protocol == IPPROTO_ICMP) {
        bpf_trace_printk("drop!\\n");
        return XDP_DROP;
    }

    return XDP_PASS;
}

ユーザランドで実行するPythonプログラムは次のとおりです。

example.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from bcc import BPF


def main():
    b = BPF(src_file='program.c')
    fn = b.load_func('prog', BPF.XDP)
    device = 'lo'
    b.attach_xdp(device, fn, 0)
    try:
        b.trace_print()
    finally:
        b.remove_xdp(device, 0)


if __name__ == '__main__':
    main()

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0