外部記憶装置

脳みそ小さすぎるからメモしとく

Mewz (WebAssembly x Unikernel) を libkrun で動かしてみた

Mewz とは

Mewz は2023年度未踏IT人材発掘・育成事業において、上田氏、野崎氏によって開発されている WebAssembly (Wasm) 専用の unikernel である。 www.ipa.go.jp github.com

unikernel 実装である Mewz と、WebAssembly バイナリをマシンネイティブなオブジェクトファイルに変換する Wasker の詳細については氏らの成果報告において発表されているため割愛する。

https://demoday.saza.dev/demoday/

libkrun

libkrun は RedHat のエンジニアである Sergio López 氏によって開発されている、コンテナ向けのVMMである。 github.com

VMM としては QEMU が代表例として知られているが、 QEMU はコンテナ向けに利用するにはフットプリントが大きく、コンテナ向けとしては扱いにくい問題がある。 そういった点を踏まえ、libkrun は、コンテナ向けにカスタマイズされた専用の Linux カーネルを動かすために必要最低限な仮想デバイスのみ提供するシンプルなVMMとして設計されている。 また、libkrun 自体はその名のとおり共有ライブラリとして提供され、CAPI経由で呼び出すことができるため、crun などの既存のコンテナソフトウェアと組み合わせやすいという特徴を持つ。 また、TSIと呼ばれる、ホストのTCP/IPスタックを利用する仕組みを持つ。

専用の Linux カーネルについても libkrunfw という共有ライブラリとして提供されている。 実体としては、Linux カーネル全体が配列として定義され、CAPI経由でエントリアドレスやバイナリ自体が提供される仕組みとなっている。 github.com

詳細については以下の記事にて詳しく解説されている。 logmi.jp rheb.hatenablog.com rheb.hatenablog.com

なお、同氏により unikernel の一種である unikraft と Wasm ランタイムである WAMR をその上で動かすことには成功している。

sinrega.org

libkrun で Mewz を動かすために必要な実装

Mewz で libkrun 実装を動かすためには次の実装が必要となる

  • libkrunfw の細工
  • Mewz への追加実装
    • Linux zeropage
    • Linux kernel’s command-line parameters
    • Virtio MMIO
    • virtio-vsock (必要に応じて)

libkrunfw の細工

libkrunfw の Makefile では、専用の Linux カーネルコンパイルしそれをCファイルに変換している。

https://github.com/containers/libkrunfw/blob/8a718429995dce928aa04872a5d8c3a700a39446/Makefile#L76

ここで Mewz を処理対象とすれば、libkrun で利用可能な libkrunfw を生成することができる。

Mewz への追加実装

Linux zeropage

Mewz は multiboot プロトコルに従い BIOS から利用可能なメモリ領域を取得している。 しかし、libkrun はブートプロトコルとして、Linux zeropage を利用している www.kernel.org

multiboot プロトコルの代わりに、Linux zeropage 経由で利用可能なメモリ領域を取得できるようにすればよい。 libkrun では、0x7000 に zeropage がマップされているため、このアドレスから必要な情報を読み取る。

Linux kernel’s command-line parameters

libkrun では、仮想デバイスはすべて MMIO 経由で提供する。それらの情報は以下のデバイスツリーのような形で kernel cmdline に織り込まれた形で提供される。

reboot=k panic=-1 panic_print=0 nomodules console=hvc0 rootfstype=virtiofs rw quiet no-kvmapf init=/init.krun KRUN_INIT=/bin/bash KRUN_WORKDIR=/ KRUN_RLIMITS="6=4096:8192" "TEST=works" virtio_mmio.device=4K@0xd0000000:5 virtio_mmio.device=4K@0xd0001000:6 virtio_mmio.device=4K@0xd0002000:7 virtio_mmio.device=4K@0xd0003000:8 virtio_mmio.device=4K@0xd0004000:9 tsi_hijack  --

virtio デバイスについても、この cmdline を適切にパースし、マップされた先のアドレスと IRQ 番号を取得する必要がある。 cmdline 自体は0x20000 にマップされているため、null 終端な文字列としてパースする。

Virtio MMIO

virtio ではデバイスの制御用チャネルとして PCI を利用する場合と、MMIO を利用する場合がある。 QEMU では通常 PCI を利用し、デバイスのスキャンを行う必要があった。 libkrun ではMMIO 経由でデバイスの制御が可能であり、アドレスも cmdline で指定されているためスキャンを行う必要がなくブートの高速化も行える。

docs.oasis-open.org

ドライバの初期化フローは PCIMMIO で大きく変わらないため、PCI版virtioで行っていた初期化をMMIO版virtioデバイスで行うだけでよい。

virtio-vsock

libkrun では、通常の仮想NICである virtio-net だけでなく、ホストの TCP/IP スタックを利用する TSI が提供されている。 TSI では、virtio-vsock と呼ばれるゲストVM<->ホスト間通信をソケットで行うことができる仕組みを利用する。 そのため、TSI を利用する場合は virtio-vsock のドライバ実装と、TSI のプロトコルに従ったソケットを実装する必要がある。

docs.oasis-open.org

プロトコル等、詳細については後日記す。

動かしてみた

ここまでの実装を全て行い、実際に動かした結果が以下のスクリーンショットである。 ここでは、ホスト側の 1235/tcp ポートをゲスト VM1234/tcp ポートにマップしている。

liblwip をリンクせずとも、ネットワークの機能は TSI 経由で提供されるため正常に WebAssembly 上の Webサーバーと通信できていることが分かる。

これから

現時点では、高負荷時に不具合が生じているため性能測定が実施できていない。 コード自体も大規模かつ破壊的な変更となっているため、現時点でソースコードを公開していない。 不具合の修正と性能測定をしたのち、一連の変更を upstream へ取り込んでもらうよう働きかけたい。

2023 年振り返り

開発したもの

時系列順に振り返っていく

xdp-nat

github.com

「XDP でなんか作ってみたいなぁ」と思っていたところ、2023年年始に勢いで作ってみた NAPT ソフトウェア。 TCP の状態管理や UDP, ICMP のタイムアウトをちゃんとやりつつ、cli も実装されていて何気に気合が入っている。 使い方のマニュアルが残されていないため、毎回ソースコードを読んで使い方を確認している。

zig-vmm

github.com

Zig で書かれた KVM 用の VMM (Virtual Machine Monitor)。 virtio-net が実装されているため、Linux kernel と initrd を読み込んで起動しnginx を動かして、外部に対して Web ページを公開できる。 大部分は gokvm を参考にした(感謝!)。 virtio 系実装として最初に virtio-console を実装したが、躓くことが多く、ゲスト kernel で printk デバッグをしながら実装していた。

etherip-linux

「EtherIP の実装やってみるか」で tap デバイス版と eBPF 版を実装した。 eBPF 版の開発で TSO, GSO 周りで苦しんでいた。

twitter.com

ユーザーランドエージェントが influxDB 向けに pps や bps のメトリックを吐く機能を持ち、意外と高機能。 既に周囲の環境にデプロイしているが、ソースコードに機微なアドレス等がハードコードされているため公開できない模様。

bypass4netns

github.com

Rootless コンテナ向けの TCP/IP 通信の高速化モジュールとして開発し、しばらく放置してしまっていだが、最近改良を行った。 実は bypass4netns に関する論文を国際会議に投稿し、一度 reject されている。 GitHub Actions 上で redis や静的リンクされた Go バイナリなどを対象にテストを自動で行うようになった。 iptables のポリシを考慮した socket switching やマルチノード通信の高速化の機能などが追加され、少しずつ進化している。

meta-fuse-csi-plugin

github.com tech.preferred.jp

FUSE を用いたあらゆるファイルシステムの実装を一般ユーザーの Kubernetes Pod 内で利用できるようにする CSI Plugin。 Preferred Networks でのインターン「キャッシュを利⽤した機械学習・深層学習ワークロードの加速」で取り組んだ成果について公開したもの。 インターンでは、メンターの上野さん、上西さん、Cluster Services Team、Storage Team の方々には大変お世話になりました。ありがとうございました。 FUSE の操作を適切に仲介する手法である fusermount3-proxy は、実は議論している中でぽっと出たアイデアを数時間で実装したものだったりする。 意外とうまく動いて書いた本人も驚いている。

そのほか

overlay-sync

github.com

リモートに保存されたファイル群を読みながらバッググラウンドで別の場所にファイルをコピーするための簡易ツール。 OverlayFS を用いている。 なお、作った2週間後に利用目的が消失した。

simple-sev-snp

github.com

pibvt.hateblo.jp

AMD SEV-SNP を使うかぁとなった時、想像以上に情報が無かったため色々調べてスクリプトもまとめた。 Measurement の検証がうまくいかない原因が SEV-ES 向けのパッチであることを知った時、「ヘァッ!!」となった。

書いた論文

CREBAS: Enabling Network Access Control in a Home with One Click

www.jstage.jst.go.jp

2022 年末に accept され、2023 年に出版された論文。 卒論で取り組んでいた、高粒度かつ設定が容易なネットワークアクセス制御に関する成果をまとめた論文。 OpenFlow コントローラを自前で実装していたり、第一著者(自分)の趣味が割と入っている。

Efficient Container Image Updating in Low-bandwidth Networks with Delta Encoding

https://repository.kulib.kyoto-u.ac.jp/dspace/bitstream/2433/286295/1/ic2e59103.2023.00009.pdfrepository.kulib.kyoto-u.ac.jp

speakerdeck.com

github.com

修士論文で取り組んでいた内容をまとめた論文。 「コンテナイメージの更新がレイヤなの、あんま効率良くないよなぁ」という素朴な疑問に対する自分なりの解を見つけようとした論文。 更新前と更新後のイメージ間で、ファイル毎に差分を取得し、その差分のみ転送するというアイデアに基づいた提案手法で、更新に要するデータサイズが削減できることを確認した。 差分を lazy に適用する専用ファイルシステムや、それに合わせた snapshotter plugin を実装しているため、containerd で簡単に利用することが出来るのがこだわりポイントの一つ。 更新に要するデータサイズに限らず、あるアプリケーションについてローカルで複数バージョンを保持する場合に消費するディスク容量も削減できる。

博士課程について

今年の4月から京都大学情報学研究科の博士課程に進学した。 総括としては、1年を通して、自分自身の力足らず、未熟さを痛感した。 論文を読み書く能力が圧倒的に足りないと感じていたため、前期(4月~7月)の間は毎日論文を1本読みその内容をまとめる取り組み(日課論文)を行っていた。

日課論文のまとめ

↓論文まとめの例 その一部は、情報科学若手の会における論文紹介という形で公開している。 hackmd.io

しかし、その取り組みもその後途切れてしまっているため、自分自身の研究活動に対する本気さが足りないのではないか?と思っている。 また、研究活動自体も取り組みが自分自身の気分によるところがあり、毎日コツコツ取り組み、小さな発見も調査したり、文章にまとめて知見として公開するというが出来ていなかった。 2024年は、そういったサボり癖を排除し、研究活動に集中して取り組むようにしたい。

今年の総括 & 来年の抱負

今年は自分自身の未熟さを痛感した1年であった。 未熟さに限らず、自分自身に負けていると感じることも多くあり、思い悩むことが多かった。 その一方で、出張やインターンを通して多くの人と会い、また多くのことを助けていただき、感謝してもしきれない。 2024 年は、今年の反省を踏まえて、大きな飛躍が出来るような1年となるよう頑張っていきたいと思う。

Running Confidential VM with AMD SEV-SNP

What is AMD SEV-SNP?

AMD SEV (Secure Encrypted Virtualization) is a technology to isolates guest VMs from the hypervisor.

AMD SEV provides only Memory Encryption.

AMD SEV-ES (SEV Encrypted State) provides encryption for guest VM's registers.

AMD SEV-SNP (SEV Secure Nested Paging) is the latest SEV techonology and it provides strong memory integrity protection and improved attestation. SEV-SNP has the concept of memory page owner. Only page owner (guest VM) can read memory page and others cannot read it. It prevents others from altering memory contents.

(cited from page 7 in AMD SEV-SNP:Strengthening VM Isolation with Integrity Protection and More)

The detail is described in AMD SEV-SNP:Strengthening VM Isolation with Integrity Protection and More

Tested Environment

  • CPU: AMD EPYC 7313P
  • MotherBoard: Supermicro H12SSL-I (BIOS Version 2.6a)
  • Memory: 128GB
  • OS: Ubuntu 23.10

Used Software

Configure Host BIOS

We need to configure BIOS to enable SEV-SNP support

Advanced -> NB Configuration

  • Configure SEV-SNP Support to Enabled

Advanced -> CPU Configuration

  • Configure SMEE to Enabled
  • Configure SEV ASID Count to 509 ASIDs
  • Configure SEV-ES ASID Space Limit Control to Manual
  • Configure SEV-ES ASID Space Limit to 100
  • Configure SNP Memory (RMP Table) Coverage to Enabled

Install the Latest Firmware

Download latest SNP firmware from AMD official Website. CPU is EPYC 7313P (Millan), so here we download amd_sev_fam19h_model0xh_1.55.16.zip

~$ wget https://download.amd.com/developer/eula/sev/amd_sev_fam19h_model0xh_1.55.16.zip
~$ unzip amd_sev_fam19h_model0xh_1.55.16.zip
Archive:  amd_sev_fam19h_model0xh_1.55.16.zip
  inflating: amd_sev_fam19h_model0xh_1.55.16.sbin
  inflating: Milan Release Notes.txt
~$ sudo rm -rf /lib/firmware/amd/amd_sev_fam19h_model0xh.sbin
~$ sudo cp amd_sev_fam19h_model0xh_1.55.16.sbin /lib/firmware/amd/amd_sev_fam19h_model0xh.sbin

Build Host Kernel for SEV-SNP

Mainline kernel does not have support for SEV-SNP host. We need to build out-of-tree SEV-SNP supported host kernel. If you want to build kernel manually, clone source code from https://github.com/AMDESE/linux (branch is snp-host-latest).

Currently(2023/12/30), host kernel commit id is 5a170ce1a08259ac57a9074e1e7a170d6b8c0cda

~$ sudo apt -y install build-essential bison libssl-dev flex libelf-dev libncurses-dev
~$ git clone --single -b snp-latest https://github.com/AMDESE/AMDSEV/
~$ cd AMDSEV
~/AMDSEV$ ./build.sh kernel host
~/AMDSEV$ ls -l linux/
total 342996
drwxrwxr-x 27 naoki naoki      4096 Dec 30 06:42 guest
drwxrwxr-x 28 naoki naoki      4096 Dec 30 06:52 host
-rw-r--r--  1 naoki naoki   9683256 Dec 30 06:54 linux-headers-6.6.0-rc1-snp-host-5a170ce1a082_6.6.0-rc1-g5a170ce1a082-2_amd64.deb
-rw-r--r--  1 naoki naoki  88048938 Dec 30 06:54 linux-image-6.6.0-rc1-snp-host-5a170ce1a082_6.6.0-rc1-g5a170ce1a082-2_amd64.deb
-rw-r--r--  1 naoki naoki 252103406 Dec 30 06:54 linux-image-6.6.0-rc1-snp-host-5a170ce1a082-dbg_6.6.0-rc1-g5a170ce1a082-2_amd64.deb
-rw-r--r--  1 naoki naoki   1362734 Dec 30 06:54 linux-libc-dev_6.6.0-rc1-g5a170ce1a082-2_amd64.deb
-rw-rw-r--  1 naoki naoki      7744 Dec 30 06:54 linux-upstream_6.6.0-rc1-g5a170ce1a082-2_amd64.buildinfo
-rw-rw-r--  1 naoki naoki      2961 Dec 30 06:55 linux-upstream_6.6.0-rc1-g5a170ce1a082-2_amd64.changes

Sucessfully built, deb packages exist. Install them and reboot. To enable SEV-SNP enabled KVM, module options are required. debug_swap=0 is required to disable new VMSA fields. The detail is in https://github.com/AMDESE/AMDSEV/issues/195.

~/AMDSEV$ sudo dpkg -i linux/*.deb
~/AMDSEV$ echo "options kvm_amd sev-snp=1 sev=1 sev-es=1 debug_swap=0" | sudo tee /etc/modprobe.d/kvm.conf
~/AMDSEV$ sudo reboot

Boot from the built kernel. If everything works correctly, we can see below log.

$ uname -r
6.6.0-rc1-snp-host-5a170ce1a082
$ sudo dmesg | grep -e SEV
[sudo] password for naoki:
[    0.716831] SEV-SNP: RMP table physical address [0x0000000087800000 - 0x00000000a7dfffff]
[    5.068960] ccp 0000:47:00.1: SEV firmware update successful
[    6.904814] ccp 0000:47:00.1: SEV API:1.55 build:16
[    6.904820] ccp 0000:47:00.1: SEV-SNP API:1.55 build:16
[    6.916442] kvm_amd: SEV-ES and SEV-SNP supported: 99 ASIDs
[    6.916444] kvm_amd: SEV enabled (ASIDs 100 - 509)
[    6.916446] kvm_amd: SEV-ES enabled (ASIDs 1 - 99)
$ ls -l /dev/sev
crw------- 1 root root 10, 122 Dec 30 07:08 /dev/sev

Build SEV-SNP supported QEMU

Build SEV-SNP supported QEMU. Ubuntu 23.10 has default gcc version 13, but gcc-13 cannot build QEMU correctly. So, we use gcc version 12 to build QEMU.

~/AMDSEV$ sudo apt install gcc-12 g++-12
~/AMDSEV$ CC=gcc-12 CXX=g++-12 ./build.sh qemu
~/AMDSEV$ ls -l usr/local/bin/qemu-system-x86_64
-rwxr-xr-x 1 naoki naoki 65718848 Dec 30 08:35 usr/local/bin/qemu-system-x86_64

Build the dedicated UEFI Firmware

To run linux kernel in SEV-SNP VM, the dedicated UEFI Firmware (OVMF) is required. To build the dedicated OVMF, we need to patch build script common.sh.

~/AMDSEV$ git diff
diff --git a/common.sh b/common.sh
index e4087d5..171779a 100755
--- a/common.sh
+++ b/common.sh
@@ -126,7 +126,7 @@ build_install_ovmf()
                GCCVERS="GCC5"
        fi

-       BUILD_CMD="nice build -q --cmd-len=64436 -DDEBUG_ON_SERIAL_PORT=TRUE -n $(getconf _NPROCESSORS_ONLN) ${GCCVERS:+-t $GCCVERS} -a X64 -p OvmfPkg/OvmfPkgX64.dsc"
+       BUILD_CMD="nice build -q --cmd-len=64436 -DDEBUG_ON_SERIAL_PORT=TRUE -n $(getconf _NPROCESSORS_ONLN) ${GCCVERS:+-t $GCCVERS} -a X64 -p OvmfPkg/AmdSev/AmdSevX64.dsc"

        # initialize git repo, or update existing remote to currently configured one
        if [ -d ovmf ]; then
@@ -150,11 +150,11 @@ build_install_ovmf()
                run_cmd git submodule update --init --recursive
                run_cmd make -C BaseTools
                . ./edksetup.sh --reconfig
+               run_cmd touch OvmfPkg/AmdSev/Grub/grub.efi
                run_cmd $BUILD_CMD

                mkdir -p $DEST
-               run_cmd cp -f Build/OvmfX64/DEBUG_$GCCVERS/FV/OVMF_CODE.fd $DEST
-               run_cmd cp -f Build/OvmfX64/DEBUG_$GCCVERS/FV/OVMF_VARS.fd $DEST
+               run_cmd cp -f Build/AmdSev/DEBUG_$GCCVERS/FV/OVMF.fd $DEST

                COMMIT=$(git log --format="%h" -1 HEAD)
                run_cmd echo $COMMIT >../source-commit.ovmf

After modifying common.sh, build the dedicated OVMF.

~$ ./build.sh ovmf
~$ ls -l usr/local/share/qemu/
total 4096
-rw-rw-r-- 1 naoki naoki 4194304 Dec 30 08:25 OVMF.fd

Build Guest Linux Kernel

Build guest linux kernel with SEV_GUEST enabled.

~/AMDSEV$ git diff
diff --git a/common.sh b/common.sh
index e4087d5..b2634d6 100755
--- a/common.sh
+++ b/common.sh
@@ -84,7 +84,7 @@ build_kernel()
                        run_cmd ./scripts/config --disable SYSTEM_TRUSTED_KEYS
                        run_cmd ./scripts/config --disable SYSTEM_REVOCATION_KEYS
                        run_cmd ./scripts/config --disable MODULE_SIG_KEY
-                       run_cmd ./scripts/config --module  SEV_GUEST
+                       run_cmd ./scripts/config --enable  SEV_GUEST
                        run_cmd ./scripts/config --disable IOMMU_DEFAULT_PASSTHROUGH
                        run_cmd ./scripts/config --disable PREEMPT_COUNT
                        run_cmd ./scripts/config --disable PREEMPTION
~/AMDSEV$ ./build.sh kernel guest
~/AMDSEV$ ls -l linux/guest/arch/x86/boot/bzImage
-rw-rw-r-- 1 naoki naoki 11440128 Dec 30 09:17 linux/guest/arch/x86/boot/bzImage

Run with Measurement

I prepared scripts to launch guest VM with measurement. Measurement validates memory integrity when the SEV-SNP guest VM starts.

# Setup Rust environment
~$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
~$ rustup target add x86_64-unknown-linux-musl

~$ git clone --recursive https://github.com/naoki9911/simple-sev-snp
~$ cd simple-sev-snp

# Build SEV-SNP guest tools
~/simple-sev-snp$ cd snpguest
~/simple-sev-snp/snpguest$ cargo build --target x86_64-unknown-linux-musl
~/simple-sev-snp/snpguest$ cd ../

# Create small initrd with alpine rootfs
~/simple-sev-snp$ ./create_rootfs.sh

# Generate private keys to sign launch digests 
~/simple-sev-snp$ ./gen_key.sh

# Then, launch with measurement!
~/simple-sev-snp$ sudo ./launch.sh

# You can get Attestation Report with snpguest
~ # ./snpguest report report.bin req.txt --random
~ # ./snpguest display report report.bin

Attestation Report (1184 bytes):
Version:                      2
Guest SVN:                    0

    Guest Policy (196608):
    ABI Major:     0
    ABI Minor:     0
    SMT Allowed:   1
    Migrate MA:    0
    Debug Allowed: 0
    Single Socket: 0
Family ID:
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
...

11th IEEE International Conference on Cloud Engineering (IC2E 2023) 参加記

2023年9月25-28日にボストンで開催された 11th IEEE International Conference on Cloud Engineering で論文発表をしてきた際の記録である。

発表した論文について

発表論文は "Efficient Container Image Updating in Low-bandwidth Networks with Delta Encoding" である。 狭帯域環境でのコンテナイメージの「更新」というシナリオにおいて、差分符号を用いることで従来の手法に比べて大幅に更新データサイズを削減する手法を提案した。 単に差分符号を適用するだけでなく、更新時間を短縮するための差分の生成戦略や、高速な差分適用といった手法を提案した。 テクニカルには bsdiff の差分同士をマージする、手法や、containerd 向けの Snapshotter plugin の実装を行っている。 実装についても公開しているが、差分符号の可能性を検証する PoC であるため、実用にはさらなる実装が必要となっている。 (この成果を元に実用的な手法を考えているところではある。)

手法はおおむね電子情報通信学会のインターネットアーキテクチャ研究会での発表と修論を改編したものとなっている。

speakerdeck.com

9/24

9/22 まで東京でインターンをし、9/23 の午後に自宅のある大阪に戻ってきたため、弾丸日程でボストン出張の準備をした。

14:35 ITM -> 16:00 NRT AA8431(運航はJL3006)

伊丹空港の展望台に数年ぶりに上った。 レストラン街もきれいに整備されており、担々麺定食を食した。 SSD 交換用に買った100円の精密ドライバを鞄に入れたまま忘れていたため、保安検査で引っかかり、危ない人判定になりそうであった。

9/24 18:25 NRT -> 9/24 18:15 BOS AA8476(運航はJL8)

何気に成田空港に来るのは初めてであった。 研究室の教員の御厚意でJALサクララウンジに入った。 夕食はカレーとフィッシュアンドチップスを食べた。

フライト中はJALの機内WiFi 24時間プラン(18.80$)を購入し、 大学の計算機で追加実験を回したりスライドの改善を行うなどした。 東京とボストンでは13時間時差があるため、ちょうどフライト分の時間が打ち消され出発と到着の現地時刻がおよそ同じであった。

Boston Logan Airport -> ホテル

到着時のボストンはあいにくの雨であり、また、普通にパーカーを着てないと寒いぐらいの気温(10℃~20℃くらい)であった。 空港からホテル(The Arcadian)への移動は、 MBTA(Massachusetts Bay Transportation Authority) の地下鉄を利用した。 Blue Line の AirPort 駅で Charlie Card と呼ばれるプリペイドカードを7日間乗り放題(7-day link card)プランで購入した。 購入自体は普通の券売機で画面を操作し、VISAタッチで決済するとカードが吐き出される仕組みであった。

Airport 駅の次の駅のホームで、上裸の男が喧嘩をしていたため電車が足止めを食らった。しばらくすると走り始め、そのまま Government Center 駅まで乗車した。 Government Center 駅で一旦地上に出た。 この駅周辺は市や州、連邦政府の期間が集中しているようで、オフィス街の様相を呈していた。 近くのマクドナルドで夕飯としてダブルチーズバーガーセットを食べた。大きさは日本のものと大きくは変わらないようだが、ソフトドリンクがカップをもらい自分でドリンクバーから注ぐタイプであった。

ホテルへは Green Line に乗り換える必要があるため、Government Center 駅から Green Line (Cleveland Circle 行き) に乗り、St. Paul 駅まで乗車した。

なお、MBTA の地下鉄は予定の時間に到着、出発することはほとんどなく早めに出発する場合もあるため、想定以上に時間がかかる場合が多かった。

ホテル滞在(The Arcadian)

ホテルは Expedia で The Arcadian powerd by Sonder というホテルを予約した。 なお、宿泊は同会議で発表する同じ研究室の学生との相部屋である。(1人で泊まると費用が嵩む...) 広めのくつろげるロビーと、部屋の区画は長い廊下に部屋が並んでいるシンプルな構造で、自分にとっては初めて見る光景であった。 部屋はベッドとシャワールームがあるシンプルな構造だった。

9/25 IC2E Day-1

5時間程度寝たような気がするが、朝からすでに疲れている状態であった。 朝食はホテルのロビーで提供されるパンやシリアルを食べた。 砂糖マシマシで甘ったるいパンにギョッとしつつ、コーヒーで流し込んだ。 参加予定の FPGA Tutorial は午後からであったっため、午前は同室の学生と一緒にボストン市内の観光をした。 MIT を見てみたかったため、ボストン大学の存在するエリアの対岸に渡り、うろうろ歩いた。 MIT 自体は明確に敷地が湧けられているわけではなく、なんとなく MIT の建物が集中的にある感じであった。工事している建物が多かったり、グラウンドが何個もあったりした。 MIT MUSEUM で展示を見て、話題の miT (mjT) T シャツとパーカーを買った。

午後はボストン大学の Center for Computing and Data Sciences (ジェンガのようなぶっ飛んだ建物)に移動し、FPGA Tutorial に参加した。

CloudLab で提供される FPGA (Alveo U280) を使ってみるというチュートリアルであったが、HLS で書かれた example のビルドに時間がかかり待っている時間が多かった。

github.com

github.com

夕方に Government Center 駅近くのクラムチャウダーで有名な店に行き、クラムチャウダーとロブスターサンドイッチのセットを食べた。30$ちょいという結構なお値段の甲斐あり、おいしかった。 その後ホテルに戻り、発表練習をして早めに寝た。

9/26 IC2E Day-2

2時間おきに目が覚めまともに寝れず朝を迎えた。 この日だけ別会場であり、43 Hawes Street, Brookline にあるボストン大学の建物で開催された。 Ketnote セッションの次のセッション最初が自分の発表であったため、変な汗をかきつつ Keynote の発表を聞いていた。

自分の発表では、かなり早口の喋り(になっていたらしい)になってしまった。 質疑に関しては PoC の実装ではケアできていないところが突っ込まれ、実現可能か否かその場で考えて沈黙の時間を作ってしまうなどしたが、おおむね好意的に受け止めてもらえたように感じた。

自分の後の発表が同じ研究室の学生の発表であった。Google Pixel の文字起こしを活用しようとしたが、マイクの性能が足らずうまくいかなかったらしい。

会場で用意されたランチ(軽食)を食べたり、周辺を散歩して昼の休憩時間を過ごした。 会場ではお茶等も提供してくれるのだが、なべて甘いため途中からげんなりしていた。

午後は Keynote の発表を聞いたり、ポスターセッションで簡単な議論をして過ごすなどした。

夜は Banquet がありコース形式であったのだが、疲労困憊で話す気力もなく、ただただ会話を聞き流す人間になっていた。22:30くらいにはホテルに戻っていた気がする。

9/27 IC2E Day-3

やはり5時間ぐらいしか寝れず、明け方に目が覚めてしまった。 この日はジェンガの建物で開催されるため徒歩でホテルから移動した。

午前中の Keynote が大学主体で構築する研究者向けのクラウド基盤の紹介とその運用や改善を元に書かれた論文の話であり、非常に面白かった。 日本でそういったことが出来ると非常に楽しいに違いないのになぁと思った。

午後にかけて体調が徐々に悪化し、扁桃腺が腫れているような症状が出てしんどかった。 発表を聞いてはいたのだが頭に入ってこず、夜も速めにホテルに戻り休んだ。

9/28 IC2E Day-4

最後のセッションを聞きつつ、 Industry は実データが取りやすくていいなぁと思うなどしていた。 Closing では IC2E 2024 がキプロスで開催されることを聞き、何か出せる論文があればまた出してみたいなと思った。

午後は知人が別の会議でボストンに来ていたため、ハーバード大学周辺や自然博物館を見学した。 博物館の鉱物展示で愛媛の鉱山の鉱石が展示されているのを発見した。 夕方には次郎系ラーメン店の Yume Wo Katare (夢を語れ) に行った。

京都大学近くの一乗寺にある店舗に行ったことが無いため、ボストンで初の次郎系を体験した。味は普通においしかった。 食べ終わると「夢を簡単に語ります?」的なことを聞かれたが丁重にお断りした。地元らしき人たちは普通に語っていた。 帰り道でアジアンマーケットでカリフォルニアロールを買った。アジアンマーケットの品ぞろえが想像以上に豊富で、スナック菓子から食パンの超熟まであり日本食が恋しくなっても困らなそうと思った。 夜はカリフォルニアロールを食べ21時過ぎには寝た。

9/29,30 移動日

朝からあいにくの雨であった。 お土産として頼まれていたボストンレッドソックスの帽子を買うために、球場近くの公式ショップへ行った。 朝からキャップをやたらと買う(4個,160$相当)人になっていた。

その後、Boston Logan Airport に MBTA の地下鉄を乗り継いで移動した。 チェックイン、出国、保安検査を滞りなく済ませ、ハンバーガーショップで BBQ ハンバーガーを購入し食べた。

9/29 13:20 BOS -> 9/30 16:15 NRT AA8475(運航はJL7)

フライトが13時間かかるため結構しんどい。 名探偵コナンの最新作とマリオの映画を見たが、どちらも面白かった。 Nintendo Switch + Factorio を持ってくればよかったと後悔している。

18:25 NRT -> 19:50 NRT AA8469(運航はJL3009)

爆睡であった。

まとめ

アメリカ、初オフライン英語発表で疲れたが、貴重な体験をすることが出来た。 今後も自分のペースで頑張っていきたいと思う。

(観光と飯食うことしかしてなくね?)

R86S レビュー(pfSense 編 その3 IPSec VPN)

R86S レビューシリーズ

前回までのあらすじと今回の内容

前回、Firewall と NAT について速度計測を行った。 今回は、pfSense に付属している IPSec VPN サーバーを試してみる。

IPSec VPN

IPSec は、VPNに用いられるプロトコルであり、トンネリング及び認証・暗号化を提供するプロトコルである。

pfSense での設定

公式に Site-to-Site な IPSec VPN の設定手順が掲載されているため、これに従って設定する。

docs.netgate.com

想定するネットワーク

前回までのネットワークを利用する。192.168.14.128/25 を IPSec で接続するLANとし、 WAN 側のIPアドレスとして、R86S は 192.168.14.1/25、IPSec で接続する負荷生成マシンのWAN側を 192.168.14.2/25 とする。負荷生成マシンの LAN のアドレスは 192.168.15.1/24 とする。

下準備

前回、NATの設定をしていたが今回は利用しないため、設定を初期状態に戻しておく。

Phase 1 の設定

初期状態では何も設定されていないため、"Add P1" から設定を追加する。

Remote Gateway にトンネルの対向である負荷生成マシンのWAN側IPアドレス(192.168.14.2)を指定する。 AESについては、"256bits"を指定するようにマニュアルに記載されているため、その通りに指定する。Pre-Shared Key については "Generate new Pre-Shared Key" から自動で生成することが出来る。

Phase 2 の設定

Phase 2 の設定を行う。追加した Phase 1 の設定から、"Add P2" を選択する。

"Local Network" は IPSec で接続するローカル側のネットワークを指定する。 ここでは、OPT1 のサブネットを接続するため、"OPT1 subnet" を選択している。 "Remote Network" では、負荷生成マシン側のLANアドレス(192.168.15.0/24)を指定する。

"Encryption Algorithms" は、マニュアルの指示に従い、"AES256-GCM" を key length "128bits" のみ指定する。

設定内容を変更するために、"Apply Changes" を選択する。

Firewall の設定

IPSec 用の Firewall を設定しておく。ここでは、IPSec で接続するネットワークについて、双方向に通信を許可する設定をしている。

Ubuntu での IPSec 設定(strongswan)

strongswan を用いて IPSec 接続を行う。IPv4フォワーディングを許可する設定を行っておく。

$ sudo vim /etc/sysctl.conf
net.ipv4.ip_forward=1 (コメントアウトを外す)
$ sudo sysctl -p /etc/sysctl.conf
net.ipv4.ip_forward = 1

IPSec の接続情報を追加する。left が自身、right が接続先である。

$ sudo apt install strongswan
$ sudo vim /etc/ipsec.conf
conn pfsense-ipsec
        type=tunnel
        keyexchange=ikev2
        left=192.168.14.2
        leftsubnet=192.168.15.0/24
        leftid=192.168.14.2
        leftauth=psk
        right=192.168.14.1
        rightsubnet=192.168.14.128/25
        rightid=192.168.14.1
        rightauth=psk
        ike=aes256-sha256-modp2048
        esp=aes256gcm16-modp2048
        ikelifetime=31680s
        lifetime=31680s
        auto=start
$ sudo vim /etc/ipsec.secrets
192.168.14.2 192.168.14.1 : PSK "a3ee7ee313ef23bdb3bc4578ede0d618ea549626bab6109d48c72b54"
$ sudo ipsec restart
$ sudo ip a add 192.168.15.1/32 dev lo

接続の確認

設定が正常に反映されていれば、pfSense 側では以下のような表示になる。

Ubuntu 側でも以下のように接続が確立していることを確認できる。

$ sudo ipsec status
Security Associations (1 up, 0 connecting):
pfsense-ipsec[1]: ESTABLISHED 5 minutes ago, 192.168.14.2[192.168.14.2]...192.168.14.1[192.168.14.1]
pfsense-ipsec{1}:  INSTALLED, TUNNEL, reqid 1, ESP SPIs: ca1fb313_i c4bacbd3_o
pfsense-ipsec{1}:   192.168.15.0/24 === 192.168.14.128/25

XFRM に、対応するポリシが追加されていることも確認できる。

$ sudo ip xfrm policy
src 192.168.15.0/24 dst 192.168.14.128/25
        dir out priority 374911
        tmpl src 192.168.14.2 dst 192.168.14.1
                proto esp spi 0xc4bacbd3 reqid 1 mode tunnel
src 192.168.14.128/25 dst 192.168.15.0/24
        dir fwd priority 374911
        tmpl src 192.168.14.1 dst 192.168.14.2
                proto esp reqid 1 mode tunnel
src 192.168.14.128/25 dst 192.168.15.0/24
        dir in priority 374911
        tmpl src 192.168.14.1 dst 192.168.14.2
                proto esp reqid 1 mode tunnel
...

iperf3 での速度計測

iperf3 を用いて IPSec を通したマシン間の通信スループットを計測した。

負荷生成マシンへの経路の追加

負荷生成マシン(192.168.14.130/25)へ IPSec を通す経路を追加しておく。

$ sudo ip route add 192.168.15.0/24 via 192.168.14.129

IPSec で接続されたマシン(192.168.15.1)への疎通が取れることを確認する。

$ ping 192.168.15.1
PING 192.168.15.1 (192.168.15.1) 56(84) bytes of data.
64 bytes from 192.168.15.1: icmp_seq=1 ttl=63 time=0.822 ms
64 bytes from 192.168.15.1: icmp_seq=2 ttl=63 time=0.924 ms
64 bytes from 192.168.15.1: icmp_seq=3 ttl=63 time=0.765 ms

計測結果(AES-NI なし)

デフォルト設定では、Intel CPU の AES 演算支援機構である AES-NI が無効化されている。 まず、その状態で計測を行った。

双方向同時に計測し、最大で 170 Mbps 前後であった。 前回の NAT での計測に比べてかなり速度が低下していることが分かる。

CPU 使用率については、NAT時と同様に1コアを使い切っている。

計測結果(AES-NI あり)

"System" -> "Advanced" -> "Miscellaneous" -> "Cryptographic & Thermal Hardware" から AES-NI を有効化する。ここでは、 "AES-NI and BSD Crypto Device (aesni, cryptodev)" を選択した。

AES と SHA についてハードウェアアクセラレーションが有効になっていることが分かる。

計測した結果、双方向合計で最大 2.3 Gbps 程度は出ていることが分かる。 forward と reverse で偏りがあるが、個別に計測した場合はどちらも 2Gbps 程度は出ていたため、なにかしらの影響によりこのような結果となっていると考えられる。

CPU使用率は AES-NI が無効な場合と比べて若干減少し、内訳も割り込み("interrupt")が中心となった。

まとめ

pfSense の IPSec サーバー機能を試してみた。 性能計測の結果より、MTU1500 な環境ではスループットは1Gbpsにも届いていない。 そのため、10Gbps な環境におけるトンネリング用デバイスとして利用するには厳しいが、 一般家庭の10G回線用に利用する分には十分に思う。

参考文献

R86S レビュー(pfSense 編 その2 Firewall, NAT)

R86S レビューシリーズ

前回までのあらすじと今回の内容

R86S に pfSense をインストールし、初期設定まで完了した。 10G インタフェースである Mellanox ConnectX-3 についても、正常に認識されることを確認した。

今回は、pfSense の Firewall と NAT について、その性能を計測する。

想定するネットワーク

これまでのネットワークと同じネットワークで計測する。 VLAN B(192.168.14.128/25) から VLAN A(192.168.14.0/25) への通信に対して、NATを行う。 Firewall については、VLAN B のインタフェース(OPT1)において、サブネット内からの通信についてのみ外向きを許可するようにした。

Firewall の設定

ConnectX-3 の VLAN B 向けインタフェースである、OPT1 について、サブネット内から外向きへの通信を許可する設定を追加した。 実際の設定は下図のとおりである。

追加し、"Apply Changes" で結果を反映すると、下図のようになる。 この時に、試験用VM(192.168.14.130/25) から OPT1(192.168.14.129/25) に対する ping が通るようになる。

NAT の設定

pfSense の NAT では、デフォルトでLAN インタフェースに関する設定が追加されている。 OPT1 についても、何かしらの方法で Internal Interface として扱えれば下記のルール設定を行わずとも良いかもしれないが、 Internal Interface に指定する方法が分からなかったため、手動でルールを追加する。

すでに生成されているルールに追加で、 OPT1 のサブネット (192.168.14.128/25) から WAN インタフェース(192.168.14.1/25) のアドレスへの変換を行うルールを追加する。 実際の設定内容は以下のようになる。

設定したルールを有効化するために、Mode で "Hybrid Outbound NAT generation" を指定し、保存する。 "Apply Changes" を実行すると以下のような状態になる。

iperf3 での計測

Ubuntu 22.10 での計測と同様に、以下の設定で iperf3 を用いて性能を計測した。

iperf3 -c 192.168.14.2 -i 0 -O 5 -M [MSS] -t 120 --json --bidir

結果は下図のとおりである。MSS が 1478 byte までの計測結果については、Ubuntu 22.10 での計測に比べてかなり遅い結果となった。 MSS が 1478 bytes の時、 Ubuntu では双方向合計で約 15 Gbps 出ていたのに対し、 pfSense では、約 5.5 Gbps 程度しか出ていない。 MSS をある程度大きくすると、Ubuntu とほぼ同様の速度が出ていることから、 pfSense の NAT におけるパケット処理性能が低い可能性が高い。

性能計測中の CPU の使用率は下図のとおりである。 Ubuntu での計測と同様に、およそ1コアで処理されているようである。 MSS が大きくなる計測後半にかけて、interrupt の割合が急上昇している点が気になるところではある。

まとめ

pfSense の Firewall, NAT 機能における性能を計測した。 機能自体は問題なくUbuntu での計測結果に比べて、スループットが大幅に低下している点は注意が必要である。

R86S レビュー(pfSense 編 その1 初期設定)

R86S レビューシリーズ

pfSense インストール

インストールメディアの作成

pfSense 公式から USB メモリ用のインストールメディアを取得する。 www.pfsense.org

ダウンロードするメディアは AMD64, USB Memstick Installer, VGA と設定した。

USB インストーラー自体の作成は OpenBSD の時と同様に Rufus を利用して作成した。

インストール

Ubuntu, OpenBSD インストール時と同様に、USBメモリ、キーボード、ディスプレイを接続し起動する。 ブートオーダーはUSBメモリを最優先に設定しているため、放っておけばインストーラーが起動する。

基本はデフォルト設定で進める。 しかし、ファイルシステムについては "Auto(ZFS)" を選択するとフリーズするため、 "Auto (UFS) UEFI" を選択する。

再起動後の初期設定についてもデフォルト設定で進める。 既に Mellanox ConnectX-3 のインタフェースが認識されているため、WAN 側のインタフェースとして割り当てた。 LAN側には管理用のインタフェースとして Intel I225 のインタフェースに固定でIPアドレスを割り当てた。

初期設定

LAN側のインタフェースにWebブラウザで接続すると初期設定ウィザードの画面が見える。

WAN 側のインタフェースは固定IPアドレスを割り当てる。 また、MTUも9000で設定する。

WAN側にもプライベートIPアドレスを割り当てているため、 プライベートアドレスからの接続をブロックする設定は無効化しておく。

一連の設定を完了すると、ダッシュボードを確認できる。 ダッシュボードで見た限りでは、プロセッサやNICも正しく認識されていることが分かる。

ConnectX-3 の残りのインタフェースについても登録する。

それぞれのインタフェースで隣接する試験用VMのアドレスが確認でき、正常に動作していることが分かる。

まとめ

R86S に pfSense をインストールし、初期設定まで終わらせた。 Mellanox ConnectX-3 についても正常に認識された。 次回以降、pfSense の各種機能を試すことにする。