naoki86star

インターネットの片隅でなにかしら書いてみる

gobgp + flowspec by clojure (java...)

 gobgp経由のflowspecこんどはclojureで呼び出せるかやってました。

 clojureと銘打ってますが、grpcのコアな部分・protobufとかはjavaライブラリに依存することになります。それゆえ、調べごと・実装のほとんどすべてはjavaと格闘することになりました。
 javaのほうでrpc呼び出しのstaticメソッド作って呼んでいるだけなので、はい、すみません今回やった部分で clojure ほとんど関係ありません。ですがclojure を使ってgrpc経由で他のプロセスとつながることできました。*1clojureでブリブリ判断処理やってbgpにメッセージを送る、みたいな用途に使えそうであります。

build gobgp-grpc using java

 ここに、gradle かmaven を使うとjavaコードで必要なプラグインを使ってコードが生成されると書いてありまして、自分はmaven使いました。そっちのほうに親しんでいるからです。(うまくいかない場合の対応とかちょっと手抜きですすめたい場合とかになんとかしやすい)*2といいながら、pom.xmlを作るところまでで時間の多くを費やしてしまいました。protoc呼び出しのときプラグイン付きでないとgrpcのsubコードが出力されなく最初インターフェースクラスのコードに全部xxGrpcとか含まれているのかと勘違いし続けてました。

 javaのprotobuf部分、python/nodejsとはまた違った雰囲気の書き方でデータ構造のシリアライズ部分書くことになりましたが、今つかんでるコツはこんな感じです。

  • データ構造インターフェースのオブジェクトクラスのインスタンスのために、newBuilder()でまずBuilderインスタンスを作る。
  • 単パラメータはsetXXX()でBuilderインスタンスに格納する*3
  • repeatedパラメータは要素ごとにaddXXX()でBuilderインスタンスに格納する
  • Builderインスタンスのbuild()の戻り値をAny.pack()する。

pom.xml(+パラメータ埋め込みで記述してしまっているclientコード例)はここに残しておきます。client例は値も架空の固定値でflowspecだけを考慮した例です。gobgpのデータ構造の扱いとしてもjavaの書き方としても整理の余地ありありです。。。

gobgpの*.protoファイルを原本からsrc/main/protoにコピーしてきて

mvn package

`target/grpc-gobgp-1.0-SNAPSHOT-jar-with-dependencies.jar`に必要jar全部込みで出力されます。今時点、エントリをexample.Client#mainに指定してあります。

run gobgp + flowspec by clojure
nao@hnd:gobgp-grpc-java$ clojure -cp target/grpc-gobgp-1.0-SNAPSHOT-jar-with-dependencies.jar
Clojure 1.9.0
user=> (ns user (:import gobgpapi.example.Client))
nil
user=> (gobgpapi.example.Client/process "add")
call addPath
Done
nil
user=> (gobgpapi.example.Client/process "del")
call delPath
Done
nil
user=>

実行前/process "add"後/process "del"後/のgobgpで見れる情報はこんな感じ

nao@hnd:$ #before status
nao@hnd:$ gobgp global rib -a ipv4-flowspec
Network not in table
nao@hnd:$
nao@hnd:$ #after calling (process "add")
nao@hnd:$ gobgp global rib -a ipv4-flowspec
   Network                                                                              Next Hop             AS_PATH              Age        Attrs
*> [destination: 1.2.3.4/32][source: 5.6.7.8/32][protocol: ==udp][port: ==1900 ==11211] fictitious                                00:00:03   [{Extcomms: [discard]} {Origin: i}]
nao@hnd:$
nao@hnd:$ #after calling (process "del")
nao@hnd:$ gobgp global rib -a ipv4-flowspec
Network not in table
補足

 ubuntu(16/18)の上で、aptでclojureインストールすると起動スクリプトはrlwrapというコマンドでラップされて起動するそうです。*4上記の実行例はaptインストールのclojureによります。ここのインストール方法だと少し動きが変わってしまいます。こっちの起動スクリプトは読み込みjarの指定をdeps.ednというファイルで指定してmavenで引っ張ってこれる仕組みになっています。この仕組みは開発者向け、ということと理解してます。

蛇足

 最近、個人で動かすjavaはAmazon/Correttoを使ってます。*5

*1:パラメータを送るだけの例題なのでclojure 生きてこなく、bgpを題材にしたのだから量のある経路情報引っ張ってきてガリガリリスト処理みたいなのなにかをやってみればいいのですが力不足にて

*2:gradleはサービスプロセスを併用しながら動くより優れモノだと想像できるのですが。

*3:XXXとかはjavaのsetter/getterでよく使われている命名規則とあってる感じ

*4:slack communityで教えてもらいました

*5:これの存在も某所で教えていただいた