bobuhiro11/mininetlab - GitHub

Linux においてパケットミラーを実現する方法はいくつかあるが、 XDP単体ではパケットミラーリングは実装できないのではないかと思っていた。 つまりTCなど他の機能と組み合わせる必要があると考えていた。

いくつか実験の結果、devmap 全エントリへの同時送信の機能を使うことによってパケットミラーリングできることがわかったので記録を残しておく。 コードは xdp_mirror.py として公開している。

xdp_mirror

全体像はこのような感じ。3台のホスト h1-3 があり、ゲートウェイ gw がそれらを接続している。 ホストとゲートウェイは netns で仮想的に作ったもので、veth ペアで接続されている。 h1からh2へ Packet1 が転送されている状況において、 gwが事前に設定した5tupleにマッチした場合には、 h2へ転送するのに加えてパケットを加工しつつh3へも転送する。 繰り返しになるが TC などの外部の機能を使わずXDP単体で実装する。 灰色のブロックがXDPプログラムを示す。全部で4種類ある。 host_pass.c は veth のために作成したが本質ではないので無視して良い。

filter.c では5tupleによるマッチングを行い、マッチした場合には devmap の全エントリに対してパケットを送信する。

// filter.c
SEC("xdp")
int xdp_filter(struct xdp_md *ctx)
{
    ip = ... ;
    udp = ... ;

    struct five_tuple key = {
        .saddr = ip->saddr,
        .daddr = ip->daddr,
        .sport = udp->source,
        .dport = udp->dest,
        .proto = ip->protocol,
    };

    // Mirror Enabled: the packet is sent to
    // all entries (for h2 & h3) in the devmap.
    if (bpf_map_lookup_elem(&mirror_targets, &key))
        return bpf_redirect_map(&tx_port, 0, BPF_F_BROADCAST);

    // Mirror Disabled: the packet is sent to
    // the first entry (for h2) in the devmap.
    return bpf_redirect_map(&tx_port, 0, 0);
}

ここで filter.c から bpf_redirect_map を経由して実行される mirror.c は BPF_XDP_DEVMAP attach type としてコンパイルされる必要がある。bpf_xdp_adjust_head などを使ってパケットを加工でき、この例ではVXLANヘッダを付与している。

おしまい。