かーねるさんとか

発言は個人の見解であり、所属する組織の公式見解ではありません。

netmap で Network Function アプリケーションを動かしてみる

netmap のサンプルアプリケーションの bridge と、FreeBSD の IP ファイアーウォールのユーザー空間実装である netmap-ipfw を動かしてみます。

netmap bridge を動かす

netmap bridge は netmap レポジトリの apps/bridge ディレクトリにあります。
この実装は二つのインターフェースに対して netmap を有効にして、片側のインターフェースから受信したパケットを反対側のインターフェースにフォワードします。
様々な NF アプリケーションの基本となるような挙動の実装方法が示されています。

実際に試していきます。
netmap のカーネルモジュールをインストールした状態で以下を試してください。netmap のインストール方法は以前のエントリー*1に書いてありますので、そちらも参考にしてください。

まず、clone してきた netmap のディレクトリへ移動します。

$ cd netmap

次に、bridge アプリケーションのディレクトリへ移動して、make を実行してコンパイルを行います。

$ cd apps/bridge
$ make

ディレクトリに bridge という名前のアプリケーションができていれば成功です。

実際にアプリケーションを実行してみましょう。

$ ./bridge -i vale0:foo -i vale1:bar

上記のコマンドを実行すると、二つの仮想インターフェースが生成され、bridge アプリケーションはそれらのインターフェースに対して受け取ったデータをフォワードします。

以前のエントリー*2で試した pkt-gen アプリケーションを使って、パケットの転送を確認してみましょう。

新しいターミナルを開いて、pkt-gen のプログラムのあるディレクトリまで移動したのち、以下のようなコマンドを実行して受信側の pkt-gen を立ち上げてみてください。

$ ./pkt-gen -i vale1:rx -f rx

次に、またもう一つ新しくターミナルを開いて、下記のようなコマンドで、送信側の pkt-gen を実行してください。

$ ./pkt-gen -i vale0:tx -f tx

受信側でパケットが受信されたら成功です。
また、受信側の pkt-gen がパケットを受信していることを確認したら、bridge アプリケーションを停止してみてください。受信側の pkt-gen でパケットが受信されなくなるはずです。

このようにコマンドを実行すると、トポロジーは以下の図のようになります。

https://raw.githubusercontent.com/yasukata/asset/master/img/netmap_bridge_20171110/bridge_topo.png

bridge と pkt-gen のアプリケーション起動時に指定する -i オプションの組み合わせによって、このような設定を行っています。
まず、最初の bridge アプリケーションのために foo と bar という仮想インターフェース(VALE ポート)が作成されるのと一緒に、同時に指定した vale0, vale1 という名前の別々の VALE スイッチがカーネル空間に作られます。
次に、受信 pkt-gen アプリケーションは、rx という名前の仮想インターフェースを持つように指定し、さらにそれは vale1 と名前のついた VALE スイッチに接続されます。
送信 pkt-gen の仮想インターフェースには、tx という名前を指定し、vale0 という名前の VALE スイッチにつながります。

送信側の pkt-gen から転送されたパケットはまず、vale0 VALE スイッチへ送られ、vale0 VALE スイッチは、同じスイッチに繋がっている foo というインターフェースへ向けて、受信したデータをフォワードします。
vale0 からフォワードされたパケットは、bridge アプリケーションへたどり着き、bridge アプリケーション内部で foo から bar インターフェースへのパケットフォワードを行います。

この段階で、パケットをチェックしてフォワードしない、もしくはパケットの中身を一部変更する等の処理を追加することで、オリジナルな NF アプリケーションが実装できます。

bar インターフェースから送信されたパケットは vale1 VALE スイッチへ送られ、vale1 は同じスイッチに接続されている rx インターフェースへ向けてパケットをフォワードします。
こうして、受信側の pkt-gen アプリケーションへ送信側 pkt-gen が生成したパケットが到着します。


netmap-ipfw を試す

bridge アプリケーションは、ただ受け取ったパケットをフォワードするだけでしたので、次は実際に使われるようなファイアーウォールを動かしてみます。

netmap-ipfw*3FreeBSD に実装されているファイアーウォール実装をユーザー空間へポートした上で、netmap API への対応が追加されています。

実際にダウンロードして、ビルドしてみます。
make コマンドを実行する際に、netmap のディレクトリ内部にある sys というディレクトリまでのパスを NETMAP_INC に指定する必要があります。

$ git clone https://github.com/luigirizzo/netmap-ipfw.git
$ cd netmap-ipfw
$ make NETMAP_INC=/netmapのディレクトリ/sys

コマンド実行後に、kipfw というバイナリができていれば成功です。

実行してみましょう。トポロジーは、bridge のサンプルと同じになるようにします。

ipfw の起動。

$ ./kipfw vale0:foo vale1:bar

受信側 pkt-gen の用意。
新しくターミナルを開いて、pkt-gen のディレクトリまで移動の後、以下のコマンドを実行してください。

$ ./pkt-gen -i vale1:rx -f rx

送信側 pkt-gen も同じく、新しく開いたターミナルで、pkt-gen のディレクトリまで移動の後、以下のコマンドを実行してください。

$ ./pkt-gen -i vale0:tx -f tx

bridge の時と同じように、受信側でデータが受け取れたら成功です。

netmap-ipfwFreeBSDipfw と同じコマンドでルールが追加可能です。
pkt-gen アプリケーションは UDP パケットを生成するので、UDP パケットを通さないルールを netmap-ipfw を追加してみましょう。
ルールの追加と削除をするには netmap-ipfw/ipfw 以下にある、ipfw コマンドを使います。
netmap-ipfwディレクトリに移動したのち、以下のコマンドを実行してみてください。

$ ./ipfw/ipfw add 100 deny udp from any to any

受信側にパケットが届かなくなったのではないでしょうか。

$ ./ipfw/ipfw delete 100

先ほど追加したルールを削除してみます。
再度パケットが受信側に届き始めたら成功です。