BGP Scanner を試す

BGP Scanner という MRT レンダリングツールを教えてもらったので試してみました。

BGP Scanner?

バイナリである MRT のデータをテキストで見せるレンダリングツールとしては bgpdump が有名だと思います。 よくお世話になっていますが、特定の subnet や AS 番号でフィルタしたいなんて時に grep 等で頑張らないといけないところに辛さがあります。

BGP ScannerIsolarioプロジェクト で開発されているC言語製の MRT レンダリングツールで、既存の MRT レンダリングツール群よりイケているとのことです。 情報は少ないですが以下参考にしました。

要約すると次のような利点があるそうです。

  • パフォーマンスを重視した設計で速い、しかも低メモリ消費
  • フィルタリング機能が充実
  • 高水準言語でラップ可能なため開発が活発化する(と期待される)

bgpdump 含め様々な MRT レンダリングツールと比較したパフォーマンス評価の結果もあり、早いことは間違いなさそうです。

インストール

環境

インストール方法

(1) Download bgpscanner-[version].tar.gz
(2) ./configure && make && make install

ITNOGでの発表資料 によると上記コマンドでおっけーって書いてあるけど、私の Mac ではそのまんまだとビルドできませんでした。

% wget https://www.isolario.it/tools/bgpscanner-1.0-1.tar.gz
% tar -zxvf bgpscanner-1.0-1.tar.gz
% cd bgpscanner-1.0-1
% ./configure
% make
/Library/Developer/CommandLineTools/usr/bin/make  all-am
depbase=`echo src/main.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;\
    gcc -DHAVE_CONFIG_H -I.    -Isubprojects/isocore/include/ -g -O2 -MT src/main.o -MD -MP -MF $depbase.Tpo -c -o src/main.o src/main.c &&\
    mv -f $depbase.Tpo $depbase.Po
src/main.c:942:13: warning: implicit declaration of function 'posix_fadvise' is invalid in C99
      [-Wimplicit-function-declaration]
            posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
            ^
src/main.c:942:37: error: use of undeclared identifier 'POSIX_FADV_SEQUENTIAL'
            posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
                                    ^
1 warning and 1 error generated.
make[1]: *** [src/main.o] Error 1
make: *** [all] Error 2

Man 曰く、

POSIX_FADV_SEQUENTIAL アプリケーションは指定されたデータがシーケンシャルに (大きなオフセットの前に小さなオフセットのデータを読むように) アクセスされることを期待する。 Man page of POSIX_FADVISE

はて。
すみません、コメントアウトさせてください。(動きはしますが正しさは保障できません。。)

% emacs src/main.c
(snip)
941        // if (fd != STDIN_FILENO)
942        //     posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
(snip)

ビルドできました。-v-h もないみたいですが、とりあえず動くようです。

% make
% make install
% which bgpscanner
/usr/local/bin/bgpscanner
% bgpscanner -v
bgpscanner: illegal option -- v
bgpscanner: The Isolario MRT data reader utility
Usage:
    bgpscanner [-cdlL] [-mM COMMSTRING] [-pP PATHEXPR] [-i ADDR] [-I FILE] [-a AS] [-A FILE] [-e PREFIX] [-E FILE] [-t ATTR_CODE] [-T FILE] [-o FILE] [FILE...]
    bgpscanner [-cdlL] [-mM COMMSTRING] [-pP PATHEXPR] [-i ADDR] [-I FILE] [-a AS] [-A FILE] [-s PREFIX] [-S FILE] [-t ATTR_CODE] [-T FILE] [-o FILE] [FILE...]
    bgpscanner [-cdlL] [-mM COMMSTRING] [-pP PATHEXPR] [-i ADDR] [-I FILE] [-a AS] [-A FILE] [-u PREFIX] [-U FILE] [-t ATTR_CODE] [-T FILE] [-o FILE] [FILE...]
    bgpscanner [-cdlL] [-mM COMMSTRING] [-pP PATHEXPR] [-i ADDR] [-I FILE] [-a AS] [-A FILE] [-r PREFIX] [-R FILE] [-t ATTR_CODE] [-T FILE] [-o FILE] [FILE...]

Available options:
    -a <feeder AS>
        Print only entries coming from the given feeder AS
    -A <file>
        Print only entries coming from the feeder ASes contained in file
(snip)

試してみる

おなじみ オレゴン大学Route Viewsプロジェクト から適当な MRT ファイルをいただいて覗いてみます。

見え方

bgpdump との比較。 個人的に現時点では bgpdump の方が見やすい印象です。
例えば bgpscanner は NEXT_HOP と FROM IP (= feeder IP) をどっちも出してたり。フィルタリングは色々できる (後述) けど、出力の内容をオプションで制御するのは現時点では改善の余地ありだと思います。 せめてUNIX時間は直させておくれよ。

% bgpdump -M rib.20190211.1400.bz2| head -n5
2019-02-12 23:39:33 [info] logging to syslog
TABLE_DUMP2|02/11/19 14:00:00|B|94.156.252.18|34224|0.0.0.0/0|34224 3356|IGP
TABLE_DUMP2|02/11/19 14:00:00|B|216.221.157.162|40191|0.0.0.0/0|40191 3257|IGP
TABLE_DUMP2|02/11/19 14:00:00|B|202.73.40.45|18106|0.0.0.0/0|18106|IGP
TABLE_DUMP2|02/11/19 14:00:00|B|195.22.216.188|6762|1.0.0.0/24|6762 13335|IGP
TABLE_DUMP2|02/11/19 14:00:00|B|94.156.252.18|34224|1.0.0.0/24|34224 13335|IGP

% bgpscanner rib.20190211.1400.bz2 | head -n5
=|0.0.0.0/0|34224 3356|94.156.252.18|i|||34224:333|94.156.252.18 34224|1549527724|1
=|0.0.0.0/0|40191 3257|216.221.157.162|i||||216.221.157.162 40191|1549493033|1
=|0.0.0.0/0|18106|202.73.40.45|i||||202.73.40.45 18106|1549493010|1
=|1.0.0.0/24|6762 13335|195.22.216.188|i||13335 173.245.63.1|6762:31 6762:40|195.22.216.188 6762|1549781054|1
=|1.0.0.0/24|34224 13335|94.156.252.18|i||13335 162.158.84.1|34224:333 34224:334 34224:2040|94.156.252.18 34224|1549873473|1

それにしても bgpdump-M (one-line output) すると COMMUNITIES は出力されないんでしたかね。

早さ

試しに測ると早いです。私の環境では bgpscanner のほうが30%程度高速でした。これは有り難い場面もありそう。

% ls -lh rib.20190211.1400.bz2 | awk '{print $5}'
113M

% /usr/bin/time bgpdump -Hm -t dump rib.20190211.1400.bz2 > /dev/null
      134.11 real       133.18 user         0.42 sys

% /usr/bin/time bgpscanner rib.20190211.1400.bz2 > /dev/null
       91.89 real        82.53 user         9.17 sys

完全に余談ですが Macのbashビルトインコマンドのtimeと/usr/bin/timeは別物 - StupidDog's blog ということを初めて知りました。

フィルタリング

せっかくなのでいくつかフィルタリングをやってみます。

-a/-A: feeder AS number

当該経路の feeder の AS 、つまり AS-PATH の1番左の AS でフィルタリングができます。 -p で AS-PATH の正規表現が使えるのにも関わらずわざわざ別のオプションにしてるのは、Isolario プロジェクトが BGP コレクターをやっているからでしょうか。分かりません。 -A ではファイル指定が可能。便利。

## 単一の feeder AS を渡す
% bgpscanner -a 701 rib.20190211.1400.bz2 | head -n5
=|1.0.0.0/24|701 2914 13335|137.39.3.55|i||13335 4.14.97.106||137.39.3.55 701|1549494007|1
=|1.0.4.0/22|701 174 4826 38803 56203|137.39.3.55|i||||137.39.3.55 701|1549493600|1
=|1.0.4.0/24|701 174 4826 38803 56203|137.39.3.55|i||||137.39.3.55 701|1549493600|1
=|1.0.5.0/24|701 174 4826 38803 56203|137.39.3.55|i||||137.39.3.55 701|1549493600|1
=|1.0.6.0/24|701 174 4826 38803 56203|137.39.3.55|i||||137.39.3.55 701|1549493600|1

## 複数の feeder AS を渡す
% bgpscanner -a 701 -a 6939 rib.20190211.1400.bz2 | head -n5
=|1.0.0.0/24|6939 13335|64.71.137.241|i||13335 172.68.188.1||64.71.137.241 6939|1549494051|1
=|1.0.0.0/24|701 2914 13335|137.39.3.55|i||13335 4.14.97.106||137.39.3.55 701|1549494007|1
=|1.0.4.0/22|6939 4826 38803 56203|64.71.137.241|i||||64.71.137.241 6939|1549494433|1
=|1.0.4.0/22|701 174 4826 38803 56203|137.39.3.55|i||||137.39.3.55 701|1549493600|1
=|1.0.4.0/24|6939 4826 38803 56203|64.71.137.241|i||||64.71.137.241 6939|1549494433|1

## 複数の feeder AS をファイルで渡す
% echo '701\n6939' > feeder_as.txt
% bgpscanner -A feeder_as.txt rib.20190211.1400.bz2 | head -n5
=|1.0.0.0/24|6939 13335|64.71.137.241|i||13335 172.68.188.1||64.71.137.241 6939|1549494051|1
=|1.0.0.0/24|701 2914 13335|137.39.3.55|i||13335 4.14.97.106||137.39.3.55 701|1549494007|1
=|1.0.4.0/22|6939 4826 38803 56203|64.71.137.241|i||||64.71.137.241 6939|1549494433|1
=|1.0.4.0/22|701 174 4826 38803 56203|137.39.3.55|i||||137.39.3.55 701|1549493600|1
=|1.0.4.0/24|6939 4826 38803 56203|64.71.137.241|i||||64.71.137.241 6939|1549494433|1

-f: feeder IP

feeder の IP アドレスを sort | uniq した結果が見られます。

% bgpscanner -f rib.20190211.1400.bz2 | head -n5
12.0.1.63 7018|1
37.139.139.0 57866|1
45.61.0.85 22652|1
64.57.28.241 11537|1
64.71.137.241 6939|1

-l/-L: with(out) AS-PATH loop

-l では AS-PATH がループしているエントリを、 -L ではループしていないエントリを表示。

% bgpscanner -l rib.20190211.1400.bz2 | head -n5
=|5.144.132.0/22|7018 6762 12880 12880 12880 12880 12880 12880 1288 12880 12880 12880 59441|12.0.1.63|i|||7018:5000 7018:37232|12.0.1.63 7018|1549889812|1
=|5.144.132.0/22|6762 12880 12880 12880 12880 12880 12880 1288 12880 12880 12880 59441|195.22.216.188|i|||6762:30 6762:40|195.22.216.188 6762|1549889835|1
=|5.144.132.0/22|286 6762 12880 12880 12880 12880 12880 12880 1288 12880 12880 12880 59441|134.222.87.1|i|||286:18 286:19 286:28 286:29 286:49 286:800 286:888 286:3031 286:4517 286:4990 286:28610 6762:1 6762:92 6762:14900|134.222.87.1 286|1549889812|1
=|5.144.132.0/22|3303 6762 12880 12880 12880 12880 12880 12880 1288 12880 12880 12880 59441|217.192.89.50|i|||3303:1004 3303:1006 3303:3056 3303:8199 6762:1 6762:92 6762:14900|217.192.89.50 3303|1549892534|1
=|5.144.132.0/22|57463 6762 12880 12880 12880 12880 12880 12880 1288 12880 12880 12880 59441|87.121.64.4|i|||0:5394 0:43561 0:60501 1:1089 6762:1 6762:30 6762:40 6762:14900 64700:6762 65400:1 65400:65400|87.121.64.4 57463|1549889838|1

-m/-M: COMMUNITIES

BGP COMMUNITIES によるフィルタリング。複数指定した時に OR じゃなくて AND でフィルタして欲しいケースの方が多いような気がします。。subnet などは複数指定で OR になるのは分かりますが果たして。 -M は反対に指定された BGP COMMUNITIES を含まない経路を表示。

% bgpscanner -m 6762:31 rib.20190211.1400.bz2 | head -n3
=|1.0.0.0/24|6762 13335|195.22.216.188|i||13335 173.245.63.1|6762:31 6762:40|195.22.216.188 6762|1549781054|1
=|1.0.4.0/22|6762 174 4826 38803 56203|195.22.216.188|i|||6762:31|195.22.216.188 6762|1549494497|1
=|1.0.4.0/24|6762 174 4826 38803 56203|195.22.216.188|i|||6762:31|195.22.216.188 6762|1549494497|1

% bgpscanner -m 6762:31 -m 6762:40 rib.20190211.1400.bz2 | head -n3
=|1.0.0.0/24|6762 13335|195.22.216.188|i||13335 173.245.63.1|6762:31 6762:40|195.22.216.188 6762|1549781054|1
=|1.0.4.0/22|6762 174 4826 38803 56203|195.22.216.188|i|||6762:31|195.22.216.188 6762|1549494497|1
=|1.0.4.0/24|6762 174 4826 38803 56203|195.22.216.188|i|||6762:31|195.22.216.188 6762|1549494497|1

-p/-P: AS-PATH Expression

-p "^701"-p "701 15169" ができるようです。
が、割と Segmentation fault が出がちです。今後の改善に期待です。(PR を出そう)

% bgpscanner -p "15169$" rib.20190211.1400.bz2 | head -n3
=|8.8.4.0/24|2905 15169|196.7.106.245|i||||196.7.106.245 2905|1549799014|1
=|8.8.4.0/24|6762 15169|195.22.216.188|i|||6762:31|195.22.216.188 6762|1549893400|1
=|8.8.4.0/24|34224 15169|94.156.252.18|i|||34224:333 34224:334 34224:2090|94.156.252.18 34224|1549527763|1

-e/-E他: subnet

-e subnet で引数で与えた subnet に Exact Match する prefix のみを表示。

% bgpscanner -e 1.4.252.0/22 rib.20190211.1400.bz2 | head -n3
=|1.4.252.0/22|37100 38040 23969|105.16.0.247|?|||NO_EXPORT|105.16.0.247 37100|1549758853|1
=|1.4.252.0/22|34224 38040 23969|94.156.252.18|?|||34224:333 34224:334 34224:2040|94.156.252.18 34224|1549709323|1
=|1.4.252.0/22|2914 38040 23969|129.250.1.71|?|||2914:410 2914:1405 2914:2406 2914:3400|129.250.1.71 2914|1549494890|1

subnet でフィルタリング可能なオプションがいくつか用意されています。大文字はファイル指定。

オプション フィルタリング効果
-e (-E) 引数で与えられた subnet に Exact Match するエントリを表示
-s (-S) 引数で与えられた subnet に Or Longer Match するエントリを表示
-r (-R) 引数で与えられた subnet に Related な(?) エントリを表示
-u (-U) 引数で与えられた subnet の Supernet となるエントリを表示

Related とは何かというところですが、やってみると -e, -s, -u を合わせたような結果になります。 "ような" というのは、試した限りでは完全に各オプションの出力が合算される訳ではなさそうという自信の無さから。 codeを深くまで追ってはいないのです。

所感

フィルタリングはまだ不安定な部分もありますが、高機能でかゆいところに手が届くため様々な場面で活用できそうな有り難いツールです。気になるところがあったら PR しよう。

蛇足

コンテナ化しました。nstgt/bgpscanner
こういった類のツールをコンテナ化する利点はあまり思い付きませんが、インストールの過程で寄り道した副産物なのでいずれ何かで使える日が来ることを切に願います。