TAIを使ってみる
こんにちは、NTTの石田です。
本記事では前回簡単に紹介したTAIを実際に動かすための手順を紹介します。
といっても、TAIに対応したパケットトランスポンダ(Voyager, Cassini)を用意するのはなかなか大変なので、
本記事ではパケットトランスポンダなしでTAIを試すことができるTAI stub libraryを利用します。
当然、実際に光伝送を行うことはできませんが、TAIを使った光伝送トランシーバ制御の雰囲気は伝わるかと思います。
まずは本記事で出てくる用語の一覧です。
用語
光伝送トランシーバ
- 電気信号を光信号に変換(またはその逆)を行うハードウェア
- プラガブルの場合もあれば、装置/プラットフォームに備え付けの場合もある
TAI adapter
- TAIで定義されるAPIの実装
- ハードウェア依存部
- ユーザモードデバイスドライバ/ドライバと呼ぶこともある
- 共有ライブラリ(libtai.so)として実装される
TAI adapter host
- TAIアダプタを利用するコード
- ハードウェア非依存部
- TAIホスト/アプリーケーションと呼ぶこともある
- 一般的にはsystemd等で管理されるデーモン
TAI module
- 光伝送トランシーバのTAIでの呼称
- 具体的にはCFP2DCO, CFP2ACO + 外部DSP, AC400 5x7モジュール等を指す
TAI network interface
- 1波長の光信号を入出力するインターフェイス
- 光ラインシステムに接続される
TAI host interface
- 電気信号を入出力するインターフェイス
- Voyager, Cassiniの場合は筐体内のBroadcom Tomahawk ASICに接続される
TAI object
- TAI module/TAI network interface/TAI host interfaceのいずれかを指す
- それぞれ複数のアトリビュートを持ち、取得/設定が可能
- TAI adapter hostによってobjectは作成される
- それぞれにユニークなObject ID/OIDが割り当てられる
TAI attribute
- 読み書き可能なオブジェクトインスタンスのアトリビュート (アトリビュートによっては読み込みのみ)
- 例えば TAI_MODULE_ATTR_VENDOR_SERIAL_NUMBER(トランシーバのシリアル番号), TAI_NETWORK_INTERFACE_ATTR_CURRENT_OUTPUT_POWER(出力パワー)等
TAI stub library
- TAI adapterのスタブ実装
- ハードウェアなしでTAIのテストが可能
- 新たにTAI adapterを実装する際のプロトタイプとしての利用も想定している
TAI meta library
- TAIを利用するプログラムが利用可能なヘルパライブラリ
- TAI attributeのシリアライズ/デシリアライズ, attributeのフラグ(読み込み専用等)の確認等が可能
TAI shell (taish)
- TAIのデバッグシェル, クライアント,サーバ型のプログラムでクライアントはgRPCを介してサーバにアクセス
- スタンドアロン型(taish_server)としても利用できる他、共有ライブラリとしてビルドしてTAI adapter hostに組み込むことも可能
TAIをサポートするパケットトランスポンダ
現在TAIをサポートするパケットトランスポンダにはVoyagerとCassiniがあります。
Voyager
- Ethernet ASIC : Broadcom Tomahawk
12x100GbEクライアントポート(フロントパネルポート) (QSFP28), 8x100GbEホストポートが2台のAC400と内部接続 - ホストボード: 4コア Atom E3845 @1.9GHz, 8GB DRAM, 128G SSD
- 2 x AC400(Acacia製, 2 x 200G DWDM)
- 対応OS : Cumulus Linux
Cassini
- Ethernet ASIC : Tomahawk+
16x100GbEクライアントポート(フロントパネルポート) (QSFP28)
8個のモジュールスロット(2xCAUI-4) - ホストボード: 4コア Broadwell-DE 1.6GHz, 8GB DRAM, 32G Flash
- モジュール
- ACOモジュール : CFP2ACO, 外部DSP(NTT Electronics ExaSpeed200)搭載
- DCOモジュール: CFP2DCO, MACsecサポート
- QSFPモジュール: 2xQSFP28, MACsecサポート
- 対応OS: OOPTOS ( SONiC+ONL ), IPInfusion OcNOS
TAI shell + TAI stub libraryを使ってみる
TAI shellを使って、TAIを使った伝送装置の設定方法を試してみます。上の図を踏襲すると、構成は次のようになります。
ビルド手順
必須ではありませんがビルドはdockerを利用すると便利です。以下の手順はUbuntu18.04にdockerをインストールして行っています。
dockerを利用しない場合は、TAIリポジトリのMakefile, Dockerfileを参照し、依存ライブラリをインストールしてください。
またTAI shellのクライアントはPythonで書かれているので、Pythonのインストールも必要です。Python3での動作を確認済です。
1. TAIリポジトリをクローン
$ git clone https://github.com/Telecominfraproject/oopt-tai.git
$ cd oopt-tai
$ ls
docs Doxyfile inc LICENSE Makefile meta README.md stub test tools
2. TAI metaライブラリのビルド
$ cd oopt-tai/meta
$ make docker-image
docker build -t taimeta-builder .
Sending build context to Docker daemon 340.5kB
Step 1/4 : FROM ubuntu:18.04
---> cd6d8154f1e1
Step 2/4 : RUN apt update
---> Using cache
---> ff41e618afef
Step 3/4 : RUN apt install -qy wget python3 python3-pip libclang1-6.0
---> Using cache
---> a6e03ab8e221
Step 4/4 : RUN pip3 install clang jinja2
---> Using cache
---> ff105030183d
Successfully built ff105030183d
Successfully tagged taimeta-builder:latest
$ make docker
cd ../; docker run -v `pwd`:/data -w /data -u `id -u`:`id -g` taimeta-builder make -C meta
make: Entering directory '/data/meta'
python3 main.py ../inc/tai.h
gcc -shared -fPIC -I ../inc taiserialize.c taimetadatautils.c taimetadata.c -o libmetatai.so
make: Leaving directory '/data/meta'
3. TAI stubライブラリのビルド
$ cd oopt-tai/stub
$ make
gcc -shared -fPIC -I ../meta -I ../inc stub_tai.c -o libtai.so -L ../meta/ -lmetatai
$ ls libtai.so
libtai.so
4. TAI shellのビルド
$ cd oopt-tai/tools/taish
$ # libtai.soをコピー
$ cp ../../stub/libtai.so .
$ make docker-image
docker build -t libtai-grpc-builder .
Sending build context to Docker daemon 28.45MB
Step 1/11 : FROM debian:jessie
---> 7f228954ce78
Step 2/11 : RUN apt update
---> Using cache
---> 522a91bf4fc9
Step 3/11 : RUN apt install -qy make gcc g++
---> Using cache
---> c4848c121869
Step 4/11 : RUN apt install -qy git
---> Using cache
---> dac281d74e00
Step 5/11 : RUN git clone https://github.com/grpc/grpc.git
---> Using cache
---> dcb3036db8e6
Step 6/11 : RUN cd grpc; git submodule update --init --recursive
---> Using cache
---> c9fb63333b66
Step 7/11 : RUN apt install -qy dh-autoreconf
---> Using cache
---> cf005d47575e
Step 8/11 : RUN cd grpc; make
---> Using cache
---> 0ba756214c8e
Step 9/11 : RUN cd grpc; make install
---> Using cache
---> 94b1872fcdfa
Step 10/11 : RUN cd grpc/third_party/protobuf; make install
---> Using cache
---> e493f424b0d6
Step 11/11 : RUN apt install -qy pkg-config
---> Using cache
---> d6f6af28c525
Successfully built d6f6af28c525
Successfully tagged libtai-grpc-builder:latest
$ make docker
# realpath doesn't work on travis use cd and pwd instead
cd ../../ && docker run -u `id -u`:`id -g` -w /data/tools/taish --rm -v `pwd`:/data -it libtai-grpc-builder make
protoc --cpp_out=./lib -I proto tai.proto
protoc --grpc_out=./lib --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` -I proto tai.proto
g++ -std=c++11 -g3 -fPIC -I ../../meta -I ../../inc -I ./include -I ./lib -c -o lib/tai.grpc.pb.o lib/tai.grpc.pb.cc
g++ -std=c++11 -g3 -fPIC -I ../../meta -I ../../inc -I ./include -I ./lib -c -o lib/tai.pb.o lib/tai.pb.cc
g++ -std=c++11 -g3 -fPIC -I ../../meta -I ../../inc -I ./include -I ./lib -o taish_server server/main.o lib/tai.grpc.pb.o lib/tai.pb.o lib/server.o `pkg-config --libs protobuf grpc++ grpc` -L ../../meta/ -lmetatai -L . -ltai -lgrpc++_reflection -lpthread
5. TAI shell clientのビルド
$ cd oopt-tai/tools/taish/client
$ pip install grpcio-tools prompt_toolkit tabulate more-itertools
$ make
python -m grpc_tools.protoc -I../proto --python_out=. --grpc_python_out=. ../proto/tai.proto
TAI shellの起動
1. taish_serverの起動
$ cd oopt-tai/tools/taish
$ make bash
# realpath doesn't work on travis use cd and pwd instead
cd ../../ && docker run --net=host -it -v `pwd`:/data -w /data/tools/taish libtai-grpc-builder bash
root@fremont:/data/tools/taish# LD_LIBRARY_PATH=../../meta:. ./taish_server
present: 1, loc: 0
module id: 72057594037927936
num hostif: 2
num netif: 1
hostif: 144115188075855872
hostif: 144115188075855873
netif: 216172782113783808
present: 1, loc: 1
module id: 72057594037927937
num hostif: 2
num netif: 1
hostif: 144115188075921408
hostif: 144115188075921409
netif: 216172782113849344
present: 1, loc: 2
module id: 72057594037927938
num hostif: 2
num netif: 1
hostif: 144115188075986944
hostif: 144115188075986945
netif: 216172782113914880
present: 1, loc: 3
module id: 72057594037927939
num hostif: 2
num netif: 1
hostif: 144115188076052480
hostif: 144115188076052481
netif: 216172782113980416
Server listening on 0.0.0.0:50051
2. taishの起動
taish_serverが起動している状態で、別端末からtaish.pyを実行します。
$ cd oopt-tai/tools/taish/client
$ ./taish.py
>
プロンプト(>)が出てくれば、正常にサーバと接続できています。
3. TAI objectの一覧を取得 ( listコマンド )
listコマンドでtaish_serverが認識/作成したTAI objectの一覧が取得できます。
> list
module: 0 0x100000000000000
hostif: 0 0x200000000000000
hostif: 1 0x200000000000001
netif: 0 0x300000000000000
module: 1 0x100000000000001
hostif: 0 0x200000000010000
hostif: 1 0x200000000010001
netif: 0 0x300000000010000
module: 2 0x100000000000002
hostif: 0 0x200000000020000
hostif: 1 0x200000000020001
netif: 0 0x300000000020000
module: 3 0x100000000000003
hostif: 0 0x200000000030000
hostif: 1 0x200000000030001
netif: 0 0x300000000030000
表示フォーマットは次の通りです。
- module: <location> <oid>
- hostif: <index> <oid>
- netif: <index> <oid>
出力から4つのモジュールを認識し、モジュールにはそれぞれ2つのホストインターフェイスと1つのネットワークインターフェースがあることがわかります。
これはstubライブラリで次のようにそれぞれのオブジェクトの数が定義されているからです。
#define STUB_NUM_MODULE 4
#define STUB_NUM_HOSTIF 2
#define STUB_NUM_NETIF 1
4. TAI moduleのTAI attributeの取得/設定
次にTAI moduleにどのようなTAI attributeがあるか確認してみます。
> module 0
module(0)> list-attr
name readonly value
------------------------------ ---------- ------------------------------
location false <string>
vendor-name true <string>
vendor-part-number true <string>
vendor-serial-number true <string>
firmware-versions true <flaot list>
oper-status true [unknown|initialize|ready|max]
temp true <float>
power true <float>
num-host-interfaces true <uint32>
num-network-interfaces true <uint32>
admin-status false [unknown|down|up|max]
tributary-mapping false <oid map list>
module-shutdown-request-notify false <pointer>
module-state-change-notify false <pointer>
module(0)>
まず module コマンドで操作対象のモジュールを選択します。引数にはモジュールのlocationを指定します。ここでは引数に0を渡して、0番目のモジュールを選択します。
list-attrコマンドで選択されているTAI objectのTAI attribute一覧が取得できます。
1カラム目はattributeの名前、2カラム目がreadonlyフラグ、3カラム目が設定する値になっています。
これらのアトリビュートはtaimodule.hで定義されています。
アトリビュートの取得/設定にはgetコマンド, setコマンドを利用します。
module(0)> get location
0
module(0) > set admin-status up
module(0) > get admin-status
up
他のモジュールを選択するにはmoduleコマンドかqで無選択状態にしてからmoduleコマンドを使用します。
module(0) > module 1
module(1) > q
> module 2
module(2) >
5. TAI network interfaceのTAI attributeの取得/設定
TAI network interfaceのTAI attributeを操作してみます。TAI moduleと操作は同様です。TAI network interfaceを選択するにはモジュールが既に選択されている状態でnetifコマンドを利用します。
引数にはindexを指定します。
module(0)> netif 0
module(0)/netif(0)> list-attr
name readonly value
--------------------------------- ---------- ----------------------------------------------------------------------------------------------------------------
index false <uint32>
tx-align-status true [loss|out|cmu-lock|ref-clock|timing]
rx-align-status true [modem-sync|modem-lock|loss|out|timing]
tx-dis false <bool>
tx-grid-spacing true [unknown|100-ghz|50-ghz|33-ghz|25-ghz|12-5-ghz|6-25-ghz|max]
output-power false <float>
current-output-power true <float>
tx-laser-freq false <uint64>
tx-fine-tune-laser-freq false <int64>
modulation-format false [unknown|bpsk|dp-bpsk|qpsk|dp-qpsk|8-qam|dp-8-qam|16-qam|dp-16-qam|32-qam|dp-32-qam|64-qam|dp-64-qam|max]
current-ber true <float>
current-ber-period true <uint32>
differential-encoding false <bool>
oper-status true [unknown|reset|initialize|low-power|high-power-up|tx-off|tx-turn-on|ready|tx-turn-off|high-power-down|fault|max]
min-laser-freq true <uint64>
max-laser-freq true <uint64>
laser-grid-support true [unknown|100-ghz|50-ghz|33-ghz|25-ghz|12-5-ghz|6-25-ghz|max]
current-input-power true <float>
current-post-voa-total-power true <float>
current-provisioned-channel-power true <float>
pulse-shaping-tx false <bool>
pulse-shaping-rx false <bool>
pulse-shaping-tx-beta false <float>
pulse-shaping-rx-beta false <float>
voa-rx false <float>
loopback-type false [none|shallow|deep|max]
prbs-type false [none|prbs7|prbs9|prbs11|prbs15|prbs20|prbs23|prbs31|max]
current-tx-laser-freq true <uint64>
ch1-freq false <uint64>
module(0)/netif(0)> get index
0
module(0)/netif(0)> set modulation-format dp-qpsk
module(0)/netif(0)> get modulation-format
dp-qpsk
module(0)/netif(0)>
これらのアトリビュートはtainetworkif.hで定義されています。
6. TAI host interfaceのTAI attributeの取得/設定
最後にTAI host interfaceのTAI attributeを操作してみます。
TAI network interfaceと操作は同様です。TAI host interfaceを選択するにはモジュールが既に選択されている状態でhostifコマンドを利用します。
引数にはindexを指定します。
module(0)> hostif 0
module(0)/hostif(0)> list-attr
name readonly value
--------------- ---------- -------------------------------------
index false <uint32>
lane-fault true [loss-of-lock|tx-fifo-err]
tx-align-status true [cdr-lock-fault|loss|out|deskew-lock]
fec-type false [none|rs|fc]
loopback-type false [none|shallow|deep|max]
module(0)/hostif(0)> get index
0
module(0)/hostif(0)> set fec-type rs
rs
module(0)/hostif(0)> get fec-type
rs
アトリビュートはtaihostif.hで定義されています。
おわりに
TAI stub libraryとTAI shellを使って、TAIがどのように使えるかを紹介しました。
従来から光伝送で利用できるAPIとしては、OIF CFP2ACO, CFP MSAなどのトランシーバレジスタマップとOpenConfig, OpenROADMなどのYANGモデルがあります。
しかしレジスタマップはベンダによって準拠度がまちまちであったり、抽象度が低すぎるため、レジスタマップを直接使って、アプリケーション(TAI host adapter相当)を開発するのはなかなか大変です。またYANGモデルはオペレータのためのAPIであるため、逆に抽象度が高すぎて、トランスポンダ内のアプリケーションでの利用には適しません。
今までレジスタマップのレイヤとYANGモデルのレイヤの間の橋渡しはハードウェア, ソフトウェア両者を開発するシステムベンダによって行われていました。しかしVoyager, Cassiniといったオープンなトランスポンダが登場し、ハードウェア, ソフトウェアの開発ベンダが別々になることで、両者を橋渡しするオープンなAPIが必要になりTIP(Telecom Infra Project)で議論を重ね、TAIの開発が始まりました。
NTTでは未来のネットワークインフラを見据え、TAIの開発をTIPコミュニティと一緒に積極的に進めています。もし興味を持たれた方がいらっしゃいましたら、是非ご連絡ください。一緒に仕事をしてみたいという方は弊社の採用情報ページも御覧ください。