search
LoginSignup
0

More than 1 year has passed since last update.

posted at

updated at

BCCでeBPFに入門

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()

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
What you can do with signing up
0