LoginSignup
9
10

More than 5 years have passed since last update.

FreeBSDで体験する次世代ネットワークスタック

Posted at

FreeBSD Advent Calendar 17日目です。

ソケット API を前提としたネットワークスタックの設計は、20 年以上昔のコンピュータやネットワークの速度を前提に設計されています。現在では CPU はマルチコア化がすすみ、ネットワークは 10Gbps や 40Gbps といった具合に数桁高速になり、またストレージもディスクから、数桁高速でアクセス方法すら違う不揮発性メモリになりつつあるなど、大きな変化が起こっています。OS のカーネルは新たなデバイスドライバのサポートに加え、こういったハードウェアの高速化、あるいはそれらの関係の変化に対処するために新たな I/O サブシステムやAPIを実装したりと、日々進化を遂げています。

こうした新たなカーネルの仕組みを試すのにはいつも大掛かりなハードウェアのセットアップが必要なわけではなく、ものによっては VM を利用して簡単に試すことができます。この記事では、既存の http ベンチマークツールと簡易 web サーバを使って、まだ本家にはマージされてませんが、PASTE という高速ネットワークスタックを体感してみたいと思います。ホストは Mac か Linux, 仮想化ソフトウェアには Virtualbox, 仮想化ソフトウェアの管理には Vagrant を使います。

まずは VM を作りましょう。freebsd という適当な作業ディレクトリを作って、その中に以下のような内容の Vagrantfile を作ります。

Vagrantfile
Vagrant.configure("2") do |config|
  config.vm.network :forwarded_port, guest: 22, host: 3332, id: "ssh"
  config.vm.guest = :freebsd
  config.vm.synced_folder ".", "/vagrant", id: "vagrant-root", disabled: true
  config.vm.box = "freebsd/FreeBSD-13.0-CURRENT"
  config.vm.base_mac = "080027D14C26"
  config.ssh.shell = "sh"
#  config.vm.network :"private_network", ip: "192.168.18.18"
  config.vm.provider :virtualbox do |vb|
    vb.gui = true
    vb.customize ["modifyvm", :id, "--memory", "2048"]
    vb.customize ["modifyvm", :id, "--cpus", "2"]
    vb.customize ["modifyvm", :id, "--hwvirtex", "on"]
    vb.customize ["modifyvm", :id, "--audio", "none"]
    vb.customize ["modifyvm", :id, "--uart1", "0x3F8", "4"]
    vb.customize ["modifyvm", :id, "--uartmode1", "server", "/tmp/freebsd-ttyS1.sock"]
    vb.customize ["modifyvm", :id, "--nictype1", "virtio"]
#    vb.customize ["modifyvm", :id, "--nictype2", "82545em"]
#    vb.customize ["modifyvm", :id, "--nicpromisc2", "allow-all"]
  end

  config.vm.provision :shell, :inline => "[ ! -f /usr/local/bin/python ] && /usr/sbin/pkg install -y python || true"
  config.vm.provision :shell, :inline => "ln -sf /usr/local/bin/python /usr/bin/python || true"
  end
end

CPUコアの数やメモリの量は環境に応じて変えてください。メモリは最低 1GB 割り当てるとよいと思います。

同じディレクトリで、vagrant up すると、VM が起動します (ネットワーク越しにセットアップするので少し時間がかかります)。起動したら /etc/rc.conf の中にある、ifconfig_DEFAULT="SYNCDHCP" の行を、ifconfig_em0="SYNCDHCP" に変更します。そしたら今度は、Vagrantfile の中の三箇所のコメントアウト (# で始まる行) を外します。そして再度 vagrant reload すると、VM の em0 に 192.168.18.18 のアドレスが付いていて、ホスト側から ping が届くはずです。また、vagrant ssh-config --host va0 で出力される内容をホスト側の .ssh/config に追記すると、その VM に ssh va0 でログインできるようになります。

ここまでできたら、カーネル再構築の準備です。まずはユーザ権限でカーネルがコンパイルできるように以下のようにします。

sudo chown vagrant /usr/src
sudo mkdir /usr/obj
sudo chown vagrant /usr/obj

次に https://github.com/freebsd/freebsd からとってきた最新の FreeBSD CURRENT のコードを展開しましょう。展開後は、以下のようなディレクトリレイアウトになってると思います。

vagrant@freebsd:~ % ls /usr/src/
COPYRIGHT       cddl            secure
LOCKS           contrib         share
MAINTAINERS     crypto          stand
Makefile        etc         sys
Makefile.inc1       gnu         targets
Makefile.libcompat  include         tests
Makefile.sys.inc    kerberos5       tools
ObsoleteFiles.inc   lib         usr.bin
README          libexec         usr.sbin
README.md       release         xen
UPDATING        rescue
bin         sbin
vagrant@freebsd:~ % 

次に、PASTE という netmap を拡張して作られた高速ネットワークスタックのパッチを当てます。VM 内で、

git clone git@github.com:micchie/netmap.git
cp netmap/sys/net/* /usr/src/sys/net/
cp netmap/sys/dev/netmap/netmap* /usr/src/sys/dev/netmap/
echo dev/netmap/netmap_bdg.c optional netmap >> /usr/src/sys/conf/files
echo dev/netmap/netmap_stack.c optional netmap >> /usr/src/sys/conf/files

とすれば OK です。
Vagrant での VM 起動時に最新のコードのスナップショットで起動していますので、普通に build kernel できるはずです。

cd /usr/src
make buildkernel KERNCONF=GENERIC=NODEBUG # 複数コアあれば -j3 のようにして複数スレッド使いましょう
sudo make installkernel KERNCONF=GENERIC-NODEBUG

新しいカーネルを有効にするために一旦 VM を再起動して、まず NIC を設定します。

sudo ifconfig em0 up
sudo ifconfig em0 -lro -tso -txcsum -rxcsum

簡易 web サーバ (phttpd) のディレクトリに移動してコンパイルします。

cd netmap/apps/phttpd
make clean; make

まずは phttpd を普通のソケットAPIを使って動かしてみます。中身は、kqueue ベースのイベントループが動いていて、read()/write() でネットワークデータを読み書きしています。

./phttpd

ホスト側から、wrk を使って、100 本のコネクションを使って HTTP リクエストを送ってみます。

michio@client:~ >wrk -d 3 -c 100 -t 100 http://192.168.18.18:60000 
Running 3s test @ http://192.168.18.18:60000
  100 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     6.77ms    1.30ms  23.04ms   90.36%
    Req/Sec   148.17     17.83   282.00     89.99%
  45375 requests in 3.11s, 6.53MB read
Requests/sec:  14612.95
Transfer/sec:      2.10MB

サーバ側は、`Ctrl+C`で終了します。
次に、PASTE を有効にした簡易 web サーバを動かしてみます。

./phttpd -i em0

ホスト側から同じコマンドで HTTP トラフィックを生成します。

michio@client:~ >wrk -d 3 -c 100 -t 100 http://192.168.18.18:60000  
Running 3s test @ http://192.168.18.18:60000
  100 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.37ms  640.18us   9.06ms   92.63%
    Req/Sec   762.45     67.41     0.92k    71.13%
  235389 requests in 3.10s, 33.90MB read
  Socket errors: connect 0, read 25, write 0, timeout 0
Requests/sec:  75867.18
Transfer/sec:     10.93MB

かなり高速になりますね。

VM なのであくまで目安ですが、カーネルの技術だけでこんなにネットワークサーバの性能が変わるのかということを体感していただければと思います。
FreeBSD には netmap や vale をはじめ、TCP スタックを部分的に変更できるようにしてある TCP Function Block という仕組みや、最近では eBPF や不揮発性メモリドライバがマージされたりと、ネットワークスタックの研究に向いている機能がたくさん入っているので、ネットワークの研究に興味がある人とかもぜひ見てみると面白いと思います。

9
10
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
9
10