前回はMirageOS Unikernelという特定のプログラムを動作させるだけの極小OSを動かしてHello Worldを出力させて遊んでみた。
MirageOS含め、Unikernelのアーキテクチャの全貌を掴めたという訳ではないが、MirageOSへの興味が強くなった為、更に先に進んでみる事にした。
今回は、bridgeインターフェースとtapインターフェースを介し、サンプルプログラムを使ってMirageOSへ通信させてみた時のメモ。
※前回:https://debslink.hatenadiary.jp/entry/20200516/1589616362
2020年8月1日追記
Ubuntu 20.04 + MirageOS 3.8.0環境で再試行した結果、想定どおりの動作を確認。
当記事は再試行版に再編集した。
当方の環境
ホストOS:Windows7 32bit版 / RAM: 4GB / CPU: Intel Core i3-2350M 2.30GHz
ゲストOS:Ubuntu Server 20.04 x86 64bit版
UnkernelなOS:Mirage OS 3.8.0
Virtualbox 5.2.32
Ubuntu Serverは既にデプロイ済み
PCのCPU仮想化支援機構はBIOSにて有効済み
MirageOSのインストール手順は、当記事下部に載せたサイトを参考に進めた。
ただし、自分の環境ではhvtオプション下での通信テストが正常に実行出来なかった為、Virtioオプションでコンパイルし通信のサンプルプログラムを生成、実行した。
当方の環境で動作するLinuxカーネルとUbuntuのバージョンは以下のとおり。
$ uname -a Linux hostname 5.4.0-42-generic #46-Ubuntu SMP Fri Jul 10 00:24:02 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux $ $ cat /etc/lsb-release DISTRIB_ID=Ubuntu DISTRIB_RELEASE=20.04 DISTRIB_CODENAME=focal DISTRIB_DESCRIPTION="Ubuntu 20.04.1 LTS" $
当方の環境で動作するMirageOS Unikernelとopamのバージョンは以下のとおり。
$ mirage --version v3.8.0 $ $ # switch compiler description → 4.10.0 ocaml-base-compiler.4.10.0 4.10.0 default ocaml-system.4.08.1 default [WARNING] The environment is not in sync with the current switch. You should run: eval $(opam env) $
インターフェースmirage_brとtap0の作成
MirageOSは通信時にtapインターフェースを使用する。
ホスト機内部でOS(Ubuntu)~MirageOS間で通信が出来るよう、bridgeインターフェース(当環境ではmirage_br)とtapインターフェース(当環境ではtap0)を作成。
ただし、以下は恒久的な設定ではなく、Ubuntuの再起動でbridgeインターフェースとtapインターフェースは消える為、恒久的に残したい場合は別途設定が必要。
$ sudo brctl addbr mirage_br $ sudo ip link set mirage_br up $ sudo ip tuntap add tap0 mode tap $ sudo ip link set dev tap0 up $ sudo brctl addif mirage_br tap0 $ $ sudo ip addr add 192.168.122.1/24 dev mirage_br $
作成後、インターフェースの状態を確認。
作成直後はmirage_br、tap0共にDOWNのステータス。
$ ip addr show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: enp0s17: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 08:00:27:40:3b:77 brd ff:ff:ff:ff:ff:ff inet 192.168.3.99/24 brd 192.168.3.255 scope global enp0s17 valid_lft forever preferred_lft forever inet6 2400:2410:d441:a900:a00:27ff:fe40:3b77/64 scope global dynamic mngtmpaddr noprefixroute valid_lft 86258sec preferred_lft 14258sec inet6 fe80::a00:27ff:fe40:3b77/64 scope link valid_lft forever preferred_lft forever 3: mirage_br: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000 link/ether 9e:77:cd:a6:c4:b2 brd ff:ff:ff:ff:ff:ff inet 192.168.122.1/24 scope global mirage_br valid_lft forever preferred_lft forever inet6 fe80::1cf3:e1ff:febf:3d54/64 scope link valid_lft forever preferred_lft forever 4: tap0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel master mirage_br state DOWN group default qlen 1000 link/ether 9e:77:cd:a6:c4:b2 brd ff:ff:ff:ff:ff:ff $
mirage-skeletonディレクトリ配下のnetworkに移動。
config.mlファイル(構成ファイル)とunikernel.ml(アプリケーションのソースコード)が生成されている事を確認。
$ cd mirage-skeleton/device-usage/network/ $ $ ls config.ml unikernel.ml $
コンパイル作業の前に、unikernel.mlファイルを編集しTera Term上に出力させるログのレベルをdebugからinfoに変更。
Logs.debug (fun f -> f "read: %d bytes:\n%s" (Cstruct.len b) (Cstruct.to_string b));を
Logs.info (fun f -> f "read: %d bytes:\n%s" (Cstruct.len b) (Cstruct.to_string b));に修正した。
vi unikernel.ml open Lwt.Infix module Main (S: Mirage_stack.V4) = struct let start s = let port = Key_gen.port () in S.listen_tcpv4 s ~port (fun flow -> let dst, dst_port = S.TCPV4.dst flow in Logs.info (fun f -> f "new tcp connection from IP %s on port %d" (Ipaddr.V4.to_string dst) dst_port); S.TCPV4.read flow >>= function | Ok `Eof -> Logs.info (fun f -> f "Closing connection!"); Lwt.return_unit | Error e -> Logs.warn (fun f -> f "Error reading data from established connection: %a" S.TCPV4.pp_error e); Lwt.return_unit | Ok (`Data b) -> Logs.debug (fun f -> f "read: %d bytes:\n%s" (Cstruct.len b) (Cstruct.to_string b)); S.TCPV4.close flow ); S.listen s end
通信プログラムのコンパイルとインストール
今回もVirtioオプションを付け、通信プログラムのコンパイルを実行。
コンパイル完了まで3つのコマンドを打つ必要が有る。
最初はVirtioオプションを付けてmirage configureコマンドを叩き、コンパイルに必要なファイルの生成。
オプション--ipv4でMirageOSアプリケーションにIPアドレスを設定。
$ mirage configure -t virtio --ipv4=192.168.122.100/24 --ipv4-gateway=192.168.122.1 $
次にmake dependコマンドを打ち、依存関係の有るopamツールおよびUbuntuのパッケージを自動でインストール。
make depend以下は自動で出力される。
今回も途中で数回質問されているようなのだが、こちらが返答する必要は無く勝手に進んでインストールされる。
$ make depend opam pin add -k path --no-action --yes mirage-unikernel-network-virtio . && opam depext --yes --update mirage-unikernel-network-virtio ; opam pin remove --no-action mirage-unikernel-network-virtio Package mirage-unikernel-network-virtio does not exist, create as a NEW package? [Y/n] y [mirage-unikernel-network-virtio.~dev] synchronised from file:///home/hechtia/mirage-skeleton/device- usage/network [WARNING] Failed checks on mirage-unikernel-network-virtio package definition from source at file:///home/hechtia/mirage-skeleton/device-usage/network: warning 37: Missing field 'dev-repo' warning 49: The following URLs don't use version control but look like version control URLs: "https://github.com/mirage/mirage-skeleton.git#master" mirage-unikernel-network-virtio is now pinned to file:///home/hechtia/mirage-skeleton/device-usage/network (version ~dev) Opam plugin "depext" is not installed. Install it on the current switch? [Y/n] Y The following actions will be performed: ? install opam-depext 1.1.3 <><> Gathering sources ><><><><><><><><><><><><><><><><><><><><><><><><><><><><> [opam-depext.1.1.3] downloaded from cache at https://opam.ocaml.org/cache <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> ? installed opam-depext.1.1.3 : : :
最後に、makeコマンドを打ち通信アプリケーションバイナリファイルnetwork.virtioと仮想マシンのバイナリファイルsolo5-virtio-runを生成。
※ここで言うアプリケーションバイナリファイルとはMirageOS側、仮想マシンとはUbuntu側を指す。
生成後、lsコマンドの実行でnetwork.virtioが当フォルダ内に有る事を確認。solo5-virtio-runは別のディレクトリ内に有る。whichコマンドでsolo5-virtio-runファイルが有る場所を探す事が出来る。
$ make mirage build config.exe: [WARNING] pkg-config solo5-bindings-virtio --variable=ld returned nothing, using ld $
通信プログラムの実行
ここでは、仮想マシンバイナリファイルsolo5-virtio-runでアプリケーションバイナリnetwork.virtioを、tap0をオプションに実行させる。
アスキーアートのロゴの出力は前回と同じ。
UbuntuとMirageOS間のリンク(mirage_br~tap0)がUPすると、[tcpip-stack-direct] stack assembled: mac=52:54:00:12:34:56,ip=192.168.122.100が出力される。
$ solo5-virtio-run -n tap0 network.virtio + exec qemu-system-x86_64 -cpu Westmere -m 128 -nodefaults -no-acpi -display none -serial stdio -device virtio-net,netdev=n0 -netdev tap,id=n0,ifname=tap0,script=no,downscript=no -device isa-debug-exit -kernel /home/hechtia/mirage-skeleton/device-usage/network/network.virtio | ___| __| _ / | _ / __ / /__ / ( | | ( | ) | ____//___/ _|/___/____/ Solo5: Bindings version v0.6.6 Solo5: Memory map: 128 MB addressable: Solo5: reserved @ (0x0 - 0xfffff) Solo5: text @ (0x100000 - 0x220fff) Solo5: rodata @ (0x221000 - 0x265fff) Solo5: data @ (0x266000 - 0x340fff) Solo5: heap >= 0x341000 < stack < 0x8000000 Solo5: Clock source: TSC, frequency estimate is 2297494800 Hz Solo5: PCI:00:02: virtio-net device, base=0xc000, irq=10 Solo5: PCI:00:02: configured, mac=52:54:00:12:34:56, features=0x79bfffe7 Solo5: Application acquired 'service' as network device 2020-08-01 04:26:21 -00:00: INF [netif] Plugging into service with mac 52:54:00:12:34:56 mtu 1500 2020-08-01 04:26:21 -00:00: INF [ethernet] Connected Ethernet interface 52:54:00:12:34:56 2020-08-01 04:26:21 -00:00: INF [ARP] Sending gratuitous ARP for 192.168.122.100 (52:54:00:12:34:56) 2020-08-01 04:26:21 -00:00: INF [udp] UDP interface connected on 192.168.122.100 2020-08-01 04:26:21 -00:00: INF [tcpip-stack-direct] stack assembled: mac=52:54:00:12:34:56,ip=192.168.122.100 2020-08-01 04:27:59 -00:00: INF [application] new tcp connection from IP 192.168.122.1 on port 58154
ここで、Tera TermやPuTTYなどターミナルツールをもう1枚立ち上げ、Ubuntuにログイン。
pingを打って疎通確認してみる。
$ ping 192.168.122.100 64 bytes from 192.168.122.100: icmp_seq=1 ttl=64 time=0.056 ms 64 bytes from 192.168.122.100: icmp_seq=2 ttl=64 time=0.059 ms 64 bytes from 192.168.122.100: icmp_seq=3 ttl=64 time=0.060 ms 64 bytes from 192.168.122.100: icmp_seq=4 ttl=64 time=0.057 ms 64 bytes from 192.168.122.100: icmp_seq=5 ttl=64 time=0.058 ms ^C --- 192.168.122.100 ping statistics --- 24 packets transmitted, 5 received, 0% packet loss, time 0.29ms rtt min/avg/max/mdev = 0.056/0.067/0.108/0.011 ms $ $
MirageOSまで届いた。
この状態でechoコマンドとncコマンドでMirageOSに文字列"hogehoge"を送ってみる。
$ $ echo -en "hogehoge" | nc 192.168.122.100 8080 $
この時、1枚目のターミナルツールに戻ると、出力内容の一番下の行にUbuntuからTCPコネクションが発生した旨のログが出力された。
(2020-08-01 04:27:59 -00:00: INF [application] new tcp connection from IP 192.168.122.1 on port 58154の事)
併せて、2020-08-01 04:27:59 -00:00: INF [application] read: 8 bytes:のログ出力と同時に hogehoge が出力された。
$ solo5-virtio-run -n tap0 network.virtio + exec qemu-system-x86_64 -cpu Westmere -m 128 -nodefaults -no-acpi -display none -serial stdio -device virtio-net,netdev=n0 -netdev tap,id=n0,ifname=tap0,script=no,downscript=no -device isa-debug-exit -kernel /home/hechtia/mirage-skeleton/device-usage/network/network.virtio | ___| __| _ / | _ / __ / /__ / ( | | ( | ) | ____//___/ _|/___/____/ Solo5: Bindings version v0.6.6 Solo5: Memory map: 128 MB addressable: Solo5: reserved @ (0x0 - 0xfffff) Solo5: text @ (0x100000 - 0x220fff) Solo5: rodata @ (0x221000 - 0x265fff) Solo5: data @ (0x266000 - 0x340fff) Solo5: heap >= 0x341000 < stack < 0x8000000 Solo5: Clock source: TSC, frequency estimate is 2297494800 Hz Solo5: PCI:00:02: virtio-net device, base=0xc000, irq=10 Solo5: PCI:00:02: configured, mac=52:54:00:12:34:56, features=0x79bfffe7 Solo5: Application acquired 'service' as network device 2020-08-01 04:26:21 -00:00: INF [netif] Plugging into service with mac 52:54:00:12:34:56 mtu 1500 2020-08-01 04:26:21 -00:00: INF [ethernet] Connected Ethernet interface 52:54:00:12:34:56 2020-08-01 04:26:21 -00:00: INF [ARP] Sending gratuitous ARP for 192.168.122.100 (52:54:00:12:34:56) 2020-08-01 04:26:21 -00:00: INF [udp] UDP interface connected on 192.168.122.100 2020-08-01 04:26:21 -00:00: INF [tcpip-stack-direct] stack assembled: mac=52:54:00:12:34:56,ip=192.168.122.100 2020-08-01 04:27:59 -00:00: INF [application] new tcp connection from IP 192.168.122.1 on port 58154 2020-08-01 04:27:59 -00:00: INF [application] read: 8 bytes: hogehoge
今回の振り返り。Ubuntu~MirageOS間の通信と文字列の送信に成功した。
当記事の編集前との違いは、UbuntuとMirageOSのバージョンとバージョン変更により一部のUbuntuやopamのパッケージが変わったくらいで、config.mlやunikernel.mlの内容は前回と同じ。
リンク先
https://mirage.io/ Mirage OS
https://github.com/mirage Mirage OS (github)
https://releases.ubuntu.com/20.04/ Ubuntu 20.04
https://debslink.hatenadiary.jp/entry/20200516/1589616362 前回:MirageOS Unikernelを少しかじってみた
https://debslink.hatenadiary.jp/entry/20200718/1595076105 追記:Ubuntu 20.04でMirageOS Unikernel
https://debslink.hatenadiary.jp/entry/20200726/1595768920 追記:MirageOS UnikernelでWebサーバ
https://debslink.hatenadiary.jp/entry/20200815/1597493701 追記:MirageOS Unikernelでデータベース
今回の通信テストの参考先 (MirageOS Unikernel アプリケーションの中身を理解する(その1))
https://qiita.com/t-imada/items/5d0149587d36c6051ed3
自分にとって始めの一歩となったサイト (MirageOS のインストールから Hello World までを試す)
https://qiita.com/t-imada/items/6ee299653ac063532b4f