LGTM

Looks Good To Me

パブリックデータから経路リークを探る

2017/08/25 12:30 (JST) ごろ、日本国内で大規模な通信障害が観測されました。

通信障害の内容について、とても詳細にまとめられている記事があります。

d.hatena.ne.jp

障害の内容はさておき、このエントリでは障害のしくみについて探ってみようと思います。

MRT Dump から見るBGP Update 数の急増

MRT Dump をもとに、該当時刻のBGP Update 数(毎分) をバーチャートにしました。

f:id:codeout:20170827220015p:plain

  • 横軸: 時刻(UTC)
  • 縦軸: BGP Update されたのべPrefix 数
    • 正: NLRI
    • 負: Withdraw

単純にBGP Update の回数をカウントしているため、Path Attribute だけの変更だったり、NLRI → Withdraw → 同じNLRI の場合でも すべて1回と数えています。

普段と比べるとUpdate 数が激増している期間があります。03:23 ~ 03:35 (UTC) の間です。

www.asahi.com

報道によれば「8分以内に正しい情報に修正した」とのことですが、実際にはすぐにBGP Update が収束しているわけではなさそうで、AS2497 からの経路変化でみると 発生(03:23) ~ 収束(03:34) とすこし時間幅が大きくなっています。これはおそらく経路を仲介しているAS の設計に依存し、MRAI などで伝搬を遅延させる影響を受けていると考えられます。

トータルでおおよそ10万経路が影響を受けていることは、MRT Dump からも観測できます。

route_leak=# SELECT count(DISTINCT prefix) FROM updates WHERE ix='wide' AND neighbor_as=2497 AND time > '2017-08-25 03:23'::TIMESTAMP AND time < '2017-08-25 03:35'::TIMESTAMP;
 count
--------
 114965
(1 row)

経路の急増が引き起こす問題

現在 IPv4 経路数はおおよそ70万弱とされているため、フルルートが一時的に 70万→80万 に増加したことになります。運悪くちょうどRIB / FIB キャパシティが限界を迎えることは十分ありえます。

この影響により、バックボーンルーター(ISP間など上位ネットワークで通信を行う装置)が、全体的に高負荷な状況に陥り、結果として16:16頃、弊社サーバー群と繋がるバックボーンルーターの一部が停止いたしました

http://hiroba.dqx.jp/sc/news/detail/a495eebbfa243b79c5b9b224c482d0c2/

限界値はさまざまですが、

  1. フルルート運用している場合で、フルルートが閾値を超えた
  2. パーシャルルート運用だが、経路フィルターを通過する経路が閾値を超えた

どちらの場合もルーターが不安定になったり、あるネットワークに通信できなくなったりします。

これは問題の原因のひとつと思われますが、これにあたった事業者はおそらく少数なのでは?と想像しています。

経路の中身は?

次のテーブルは観測されたAS_PATH の一例です。一部報道のとおり、AS15169 (Google) が経路をトランジットしているのがわかります。

route_leak=# SELECT aspath, count(distinct prefix) FROM updates WHERE ix='wide' AND neighbor_as=2497 GROUP BY aspath ORDER BY count DESC LIMIT 10;
          aspath           | count
---------------------------+-------
 2497 701 15169 4713       | 24831
 2497 701 15169 7029       |  7308
 2497 701 15169 8151       |  4639
 2497 701 15169 9121       |  4606
 2497 701 15169 9264 1659  |  3014
 2497 701 15169 9394       |  2129
 2497 701 15169 3209       |  1757
 2497 701 15169 7303       |  1580
 2497 701 15169 4230 28573 |  1475
 2497 701 15169 7545       |  1420
(10 rows)

少しおかしいですね。AS4713 (OCN) がAS15169 (Google) を介してインターネット接続しているかのようなAS_PATH です。

AS15169 (Google) から見るとAS4713 (OCN) はピアであり、本来であればトランジットであるAS701 (Verizon) に経路広告するべきではありません。このような経路が10万あったということですね。

注: 正確に言えば広告しても構わないのですが、流れてくるトラフィックをさばける回線キャパシティを担保するべきです。

AS701 に流れた経路は、そのままAS2497 (IIJ) に流れます。では、AS2497 はその経路をベストパスとして選択し、パケット転送するでしょうか?

通常ならAS_PATH 勝負で負けるため この経路がベストになることはありませんが、実はこの経路 Prefix Length が違っていました。

route_leak=# SELECT masklen(prefix) AS len, count(distinct prefix) FROM updates WHERE ix='wide' AND neighbor_as=2497 AND aspath ='2497 701 15169 4713' GROUP BY len ORDER BY count DESC LIMIT 10;
 len | count
-----+-------
  24 | 16594
  22 |  3035
  23 |  2432
  21 |  1764
  20 |   868
  19 |    79
  16 |    29
  18 |    15
  17 |    10
  15 |     3
(10 rows)

OCN クラスのISP であれば/12 ~ /20 くらいの大きなPrefix でルーティングすることが多いですが、障害中に観測された経路は/24 が大半です。Longest Match ルールにのっとってこの経路がベストになった、ということは容易に想像できます。

経路の中身について、ここまでまとめ

8/25 の障害時には、一例として AS2497 (IIJ) は「AS4713 (OCN) へのベストパスはAS15169 (Google) 経由」としていたことがMRT Dump から読み取れました。

ここからは想像ですが、10万経路ぶんのトラフィックがAS701、AS15169 に向かったため、

  • 通信路のどこかで輻輳する
  • 事業者の通信ポリシーによって通信が遮断される
  • 遅延が増える (AS701、AS15169 は日本とは限らない)

ことが考えられます。

OCN と IIJ は一例であることに注意

ここまでIIJ → OCN 向きのトラフィックで説明しましたが、これは一例です。始点はIIJ に限らず、終点はOCN に限りません。アイボール側、コンテンツ側、どちらが影響を受けても通信が成り立たないことに注意です。

また、このエントリはMRT Dump を出発点にしています。限られた情報であり、障害時に起こっていた経路変化がすべてDump されているとは思えない = 見えていない影響も当然あると思われます。

大量の/24 はどこから来たか?

MRT Dump 上でみると、これら/24 のOrigin AS は4713 です。「4713 がOriginate した」と考えるのが自然です。

BGPMON の記事 でもそう考察されています。

ピアリング回線が複数あり、特定のトラフィックを特定の回線に乗せるためのトラフィックエンジニアリングですね。「経路はふつうAS15169 で止まるが、誤ってリークした」というのはありそうです。

いっぽう、AS4713 以外の事業者が生成している可能性ありそう、とも考えています。

「途中の事業者がPrefix を分割する」ようなケースです。ふつうはあまりやらないTE ですが、可能性を考えるためにAS15169 の右隣 != Origin AS なAS_PATH に注目してみましょう。観測されたAS_PATH のうち15169 より右を抜き出します。

route_leak=# SELECT substring(aspath from '15169.*') AS path, count(distinct prefix) FROM updates WHERE ix='wide' AND neighbor_as=2497 GROUP BY substring(aspath from '15169.*') ORDER BY count DESC LIMIT 10;
       path       | count
------------------+-------
 15169 4713       | 24831
 15169 7029       |  7308
 15169 8151       |  4639
 15169 9121       |  4606
 15169 9264 1659  |  3014
 15169 9394       |  2129
 15169 3209       |  1757
 15169 7303       |  1580
 15169 4230 28573 |  1475
 15169 7545       |  1420
(10 rows)

たとえば 15169 9264 1659。 Prefix でいうと61.60.96.0/24 など。

RIPEstat によれば、この経路は障害発生中にのみ存在しています。

https://stat.ripe.net/widget/bgplay#w.resource=61.60.96.0/24&w.ignoreReannouncements=false&w.starttime=1503551751&w.endtime=1503810951&w.rrcs=0,1,2,5,6,7,10,11,13,14,15,16,18,20&w.instant=null&w.type=bgp

あくまで想像の域を出ませんが、次のような可能性も考えられます。

経路だけをみれば、AS1659 (TANet) はAS9264 (ASNET) との間に複数回線もち、BGP によるTE を行なっているようです。この影響がAS15169 (Google) に漏れ聞こえ、インターネットに広告されているわけですが、この経路は障害のあった時間帯しか存在しません。

通常のルーティングとしては何か不自然です。AS9264 が他にも広告するためインターネットで常に観測されそうなのに、それがない。どちらかといえば、想像ですが「間の事業者が内部利用のために経路を生成した。それが漏れてしまった」と考えるほうがしっくりきます。

このように障害中のみ観測された経路、かなりの数あるようです。

海外に目を向ける

では、日本以外ではどうでしょう?

Route Views Project はグローバルにコレクターを配置しており、一部海外IX での経路変化を記録しています。

障害のあった期間中のBGP Update 総数を数えてみれば影響のあった事業者、なかった事業者のあたりをつけることができます。次のテーブル中で、count が小さいAS (neighbor_as) ほど影響が軽微だったと考えられます。

(count は観測されたBGP Update のユニークprefix 数、neighbor_as はRouteViews コレクターとピアしているneighbor AS )

route_leak=# SELECT ix, neighbor_as, count(distinct prefix) FROM updates GROUP BY ix, neighbor_addr, neighbor_as ORDER BY ix, count DESC;
    ix    | neighbor_as | count
----------+-------------+--------
 3        |         286 | 101331
 3        |       45352 |      5
 3        |      134708 |      3
 3        |        5645 |      3
 3        |        6939 |      3
 3        |       40387 |      3
 4        |       45177 |  97396
 4        |       48526 |  85617
 4        |       38726 |  75787
 4        |       34288 |  74560
 4        |       36236 |  74365
 4        |       24482 |      8
 4        |       24516 |      7
 4        |       24516 |      7
 4        |       63956 |      5
 4        |       38883 |      3
 4        |       58682 |      3
 4        |       58511 |      3
 4        |       58511 |      3
 4        |       58511 |      3
 4        |       38726 |      3
 4        |        1351 |      3
 6        |       31019 |    100
 6        |       53364 |     10
 eqix     |        3257 |     10
 eqix     |       41095 |      4
 eqix     |       11039 |      3
 eqix     |        6939 |      3
 isc      |        2497 | 114601
 isc      |        6939 |      3
 linx     |       41695 |  91612
 linx     |       34288 |  74560
 linx     |       37271 |     98
 linx     |       37271 |     98
 linx     |       58511 |     28
 linx     |       58511 |     28
 linx     |        3257 |     10
 linx     |       13030 |      5
 linx     |       13030 |      5
 linx     |       14537 |      4
 linx     |        6667 |      3
 linx     |        6939 |      3
 linx     |       37271 |      3
 linx     |       58511 |      3
 linx     |       37271 |      3
 linx     |       58511 |      3
 nwax     |        1798 |     98
 nwax     |       15301 |      3
 nwax     |       54073 |      3
 oregon   |        2497 | 114973
 oregon   |         286 | 101781
 oregon   |         701 |  98183
 oregon   |        7660 |  94091
 oregon   |       23673 |      8
 oregon   |      393406 |      7
 oregon   |       62567 |      7
 oregon   |       31019 |      5
 oregon   |        1221 |      5
 oregon   |       13030 |      5
 oregon   |       37100 |      4
 oregon   |       40191 |      4
 oregon   |        3303 |      4
 oregon   |       11686 |      4
 oregon   |       20912 |      3
 oregon   |        6762 |      3
 oregon   |        6939 |      3
 oregon   |        8492 |      3
 oregon   |       57463 |      3
 oregon   |       58511 |      3
 oregon   |       18106 |      3
 oregon   |       54728 |      3
 oregon   |         293 |      3
 oregon   |       47872 |      1
 perth    |       24516 |      5
 saopaulo |      262757 |  93512
 saopaulo |       53013 |  19034
 saopaulo |       53013 |  18707
 saopaulo |      262612 |  18692
 saopaulo |       52863 |  16650
 saopaulo |       28138 |     11
 saopaulo |       52940 |      7
 saopaulo |       28571 |      7
 saopaulo |      262354 |      7
 saopaulo |      262750 |      7
 saopaulo |       52888 |      7
 saopaulo |      264268 |      7
 saopaulo |      263047 |      4
 saopaulo |       52720 |      4
 saopaulo |        1916 |      4
 saopaulo |      262317 |      4
 saopaulo |       26162 |      4
 saopaulo |      263945 |      4
 saopaulo |       26162 |      4
 saopaulo |       26162 |      4
 saopaulo |       28329 |      3
 sfmix    |       32212 |  73638
 sg       |       59318 |     69
 sg       |       24482 |      7
 sg       |      133165 |      5
 sg       |       24115 |      3
 sg       |       24115 |      3
 sg       |       38880 |      3
 sg       |        9902 |      3
 sg       |       18106 |      3
 sydney   |       58511 |      3
 sydney   |        4739 |      3
 sydney   |       38809 |      3
 sydney   |        4826 |      3
 sydney   |       38880 |      2
 telxatl  |        6082 |      3
 telxatl  |       53828 |      3
 telxatl  |        6939 |      3
 wide     |        2497 | 114965
 wide     |        7500 | 100240
(114 rows)

日本ほどの影響度は少数派ですね? それはなぜか?

よくわかりませんw

わかりませんが、障害トリガーとなった経路は「AS701 (Verizon) 経由でインターネットに流れた」と考えて差し支えなさそうです。観測されたAS_PATH のうち、15169 とすぐ左隣だけ抜き出します。

route_leak=# SELECT substring(aspath from '\d+ 15169') AS transit, count(distinct prefix) FROM updates GROUP BY transit ORDER BY count
   transit    | count
--------------+--------
 701 15169    | 162205
 1798 15169   |     98
 37271 15169  |     98
 43531 15169  |     72
 59318 15169  |     69
 58511 15169  |     28
 31019 15169  |     28
 394625 15169 |     10
 3257 15169   |     10
 62567 15169  |      3
 393406 15169 |      3
 11492 15169  |      1
(12 rows)

では、AS15169 (Google) はAS701 にのみリークしたのか? もちろんその可能性は十分ありますが、もしそうではなく「他のトランジットにもリークしたが、そっちは問題にならなかった」のであれば学ぶべきポイントがありそうですよね。

普通、Tier1 プロバイダーは顧客向けBGP セッションに経路フィルターを設定します。多くの場合Peering DB やIRR から自動生成され、顧客が100% 制御できる かつオペミスを防げるようになっています。

  1. AS701 にはそれがなく、他のトランジット事業者にはあった
  2. AS701 にもあったが、特殊なアレンジをしていた。もしくは顧客がバイパスしていた
  3. 経路がピアを経由する際、うまくmax-prefix filter が効いた

いろいろ想像できますが、根拠がないため想像しても意味はなさそう。。。もし可能であればこのあたりのカラクリを知りたいもんです。

なぜこのエントリーを書いたか

できれば障害から学びたいと思ったからです。次に同じことが起こったとき、防げる気がしない。

BGP におけるネットワークが Autonomous System (自律システム) と呼ばれる通り、これまでのインターネットは各AS が自律的にルーティングすることでうまく動いてきました。隣のAS がミスをしたとき、できれば自分のところで影響を小さくして インターネット全体をなんとなく維持させたいと考えています。

そのために、ご近所さんのルーティングポリシーは可能な範囲で知っておきたい。最悪を想定するためでもあります。各事業者がビジネスでやっている以上「やめてほしい」は通らないかもですが、たぶん備えることはできます。

「BGP 脆弱やん」というご指摘はごもっともで、今後も同じシステムでインターネットを運用できるのかは怪しいです。しかしながら まだ打てる手はありそうで、「なぜ海外で問題なかったか」はヒントになりそうな…という感じがしています。*1

意外と「日本人マイクロマネージメントしすぎ」みたいな話題に流れていくかもしれません。

以上、「Postmortem 見たいです」のラブレターでした。

*1:Path Validation のようなハードル高い必殺技もあります

sFlow は面倒くさいが、fluent-plugin-sflow を再実装する話

背景

ネットワークデバイスからの xFlow を Fluentd で集めて分析、あるいは可視化するということをよくやります。

ルーター製品であれば fluent-plugin-netflow が使えますが、スイッチ製品はそもそも NetFlow がサポートされていません。代わりに sFlow に対応のデバイスが多いものの、現実的に動く fluent-plugin がありません。

NetFlow に比べて sFlow 実装が面倒なためですが、取り組んでみると まあまあ収まりのいい形で実装できた気がする、という記事です。

sFlow の面倒くさい点

パケットデコーダーを内包しないといけない

sFlow は L2 情報が中心で、 L3 + ルーティングの情報は普通ありません。 Ethernet ペイロードの先頭 N バイトをコレクター側でデコードしないといけません。さらに、場合によっては下のような情報を付加してやる必要があります。

  • Prefix Length
  • SRC / DST AS 番号
  • Protocol Nexthop
  • 論理 ifIndex

パフォーマンス

sFlow は IP フローを意識していません。 NetFlow ではうまく Aggregate して Export パケットを減らしたりできますが、 sFlow では Export パケットが増えがちです。

デコードしないといけないわ pps 多いわで、 NetFlow よりパフォーマンスが問題になりやすいです。

sFlow と NetFlow の名寄せ

これは sFlow の問題ではありませんが、 sFlow と NetFlow を同じ基盤で扱うときに面倒な点です。

同じ情報でも、 sFlow の流儀と NetFlow の流儀はちがいます。たとえば、パケットが入ってくるインターフェイスの ifIndex は、 sFlow v5 では input、 NetFlow v9 では input_snmp になっています。

コレクター実装を考えるとき、単純に名寄せすればいいかもしれません。が、「どっちに寄せれば…?」で悩みます。

DNS クエリーはもっと悩ましいです。

NetFlow では

{
  "protocol":    17,  # or 6
  "l4_dst_port": 53
}

で Export されますが、 sFlow では

{
  "protocol":     17,
  "udp_dst_port": 53
}

もしくは

{
  "protocol":     6,
  "tcp_dst_port": 53
}

で出たりします。UDPTCP で別キー。*1 面倒くさい!!

コレクターで UDP / TCP Port を結合して Port にするかどうかは…悩ましい。ネットワークオペレーターの事情に応じて record_transformer プラグインなどで名寄せすればよかろうと思い、今回の実装では sFlow の流儀のまま Export することにしました。

もうひとつ悩ましい例は Export パケットの SRC IP アドレス。sFlow にも Netflow にも該当するフィールドはありません。*2

fluent-plugin-netflow ではそれをhost として格納していますが、 sFlow ではhost は使えません。 HTTP HOST ヘッダーを格納するフィールドとして規定されているためです。。。面倒くさい!

このような流儀の違いが山のようにあります。 filter プラグイン名寄せしつつ、、、でパフォーマンスが出せるか十分に検討していませんが、とりえあず sFlow 流儀に従いました。

既存 fluent-plugin-sflow の BinData 問題

これも sFlow 自体の問題ではありませんが、実は fluent-plugin-sflow という gem は既に存在します。今回はそれを再実装した という形なのですが、既存のものにはいくつか問題があります。

  1. 利用しているパケットデコーダーがメンテされていない → fluent-plugin-netflow と併用できない
  2. スループットが出ない

1 . は最新の BinData では動かないのが根本原因で、仕様上むずかしそう。 2. も BinData が原因です。 ちなみに、fluent-plugin-netflow も当初は BinData ベースでしたが、パフォーマンスのために 低レベルなビット演算に変わったという経緯があります。*3

実装について

InMon 謹製の sflowtool に手を加え、 C 拡張として内包することにしました。

  • 公式のパケットデコーダーを使える
    • 頻度高くないが、まだメンテされているように見える
  • パフォーマンス改善が見込める
  • BinData とさよならできる

のがポイント。実装は こちら

ベンチマーク

手元の Macbook Pro Mid 2015 に 外から sFlow v5 を Export しました。

records / sec
再実装版 14202
オリジナル版 220

まあまあ実用には耐えそう。

TODO

  • テストを足す
    • sflowtool にパッチしたとはいえ、バグを埋めているかもしれない
    • 「動かないよ」という方がいらっしゃれば、ぜひ .pcap ください 🙇
  • fluent-plugin-sflow メンテナー様にコンタクトしてみる
    • 別実装なので…別 gem にするべきか、プルリクしてもいいものか思案中 💦
    • 出力フォーマットが変わる → プルリクするならば互換性を壊す
  • BGP の情報をインポートする

*1:sflowtool の実装

*2:NetFlow v9 の source_id、sFlow の agent_id は Export パケットの SRC IP アドレスではありません

*3:NetFlow v9 はまだ BinData = 遅い

フリーランスの税金対策

ネットワークエンジニアのまま脱サラし、個人事業をはじめて3年がたった。

おかげさまで ある程度の収益が出るようになったが、 節税のためにやってることのうち「これは」というやつについて書いておこうと思う。

みんな大好きお金の話です。

小規模企業共済

毎月7万円まで積み立てることができて、全額所得控除になるというもの。 わりと有名なやつなので加入者も多いと思う。

共済金の請求方法 (多くの場合は事業をたたむ理由) によって金額がかわるタイプのもので、条件を満たさなければ当然元本割れする。最低で元本の 80% だが、それほどのリスクはないと思う。

理由はいくつかあるが、

  • もっとも条件の悪い請求方法である解約手当金は「事業は廃業しないが解約する」とか「金銭以外の出資によって法人成りする」などおそらくレアケース
  • 「事業は廃業しないし、積み立てる余裕はない」というケースもありえそうだが、積立金は月1,000円まで落とせる。それくらいは出せる…はず…
    • この場合、頑張って 20年 加入し続ければ、元本割れを防げる
  • 「廃業する」「死ぬ」「譲渡する」ような、一番ありそうなケースでは (調べた限り) 元本割れしない
  • 「法人成り」のケースでも条件を満たせば継続可能
  • めちゃくちゃ最悪のケース、元本割れして 80% になったとしても それまでの節税額を加味すると さほど条件悪くない

http://www.smrj.go.jp/skyosai/qa/tax/050608.html

小さいリスクに対してありあまるメリットがあって、

  • 全額控除。これがデカい 💰
  • 受け取り方によって税法上の扱いがかわるが、だいたいメリットがある
    • 一括で受け取れば 退職所得
    • 分割で受け取れば 雑所得 (年金相当)
    • 解約手当金でも 一時所得 (65歳以上なら退職所得)
  • 死んでも相続対象になる
  • 長く積み立てれば 結構もどってきそう

制度の見直しがあれば別だけど、受け取りかたを工夫すればメリットしかないと思って 退職金や立ち行かなくなったときの保険がわりに積み立てている。

消費税の簡易課税制度

税理士いわく、こちらは知らない人もいるらしい。

消費税の扱いから書いたほうがいいかもしれないが、消費税は基本「お客さんから預かる」という建てつけなので、決算で売上を確定させたあとは納税しないといけない。

ただし、法人であれ個人事業であれ 税込で売上が1,000万以下であれば その納税義務が免除される。 これが「1,000万を超えないようにしましょう」の根拠。

1,000万の壁を超えた場合は消費税をお納めするわけだけど、いくつか考えることがある。たとえば売上に対する費用について。

売上のために支払った費用には 多くの場合すでに消費税が含まれている。決算で費用を確定したあと、預かった消費税 - 支払った消費税 を納税しましょう、というのが基本。

ここで簡易課税制度という特例があって、基本のやりかただと「支払った消費税」の計算が面倒なことが多いため、小規模事業 (法人、個人によらず税抜売上5,000万以下) であれば「みなしで仕入れ率を決めうちして、その分の消費税を払ったことにしましょう。計算ラクでしょ?」というやりかたを選べる。

みなしの仕入れ率は業種によってちがうが、われわれサービス業であれば 50%。流しのネットワークエンジニアをひとりでやってる限り 普通そんなにいかないので、節税効果がでる。昨年の自分の場合なら 20%強だった。

デメリットとして、外注が増えるなどで仕入れ実態が 50% を超えた場合に還付されなくなるが、基本のやりかた (原則課税という) と簡易課税は 申請すれば事業年度単位でパチパチ切り替えることができる。

一点、簡易課税には2年縛りがあることだけ注意。2年間は原則課税に戻せない。当然ながら申請は適用を受けたい事業年度が始まるまでに済ませておくこと。

専従者給与

複式簿記にして65万の所得控除を受けておくのは基本として、家族が事業を手伝っている場合は 専従者として給与を払うことができる。一般には住民税の壁 = 基礎控除 (33万円) + 給与所得控除 (65万円) = 98万を超えないようにするのが常套手段。

よく考えると 実はもうちょっとパラメーターがあって、「その家族には別の収入がある」「家族ぶんの確定申告がめんどくさくない」場合には、事業にかかる税率とその家族にかかる税率がちがうため最適化の余地がある。極端に振ると目立ってしまう恐れがあるので、あとで書くが税理士の出番。

どちらにせよ 専従者の分の年末調整はやらないといけないが、慣れればそんなにつらくない。

事業割合

個人事業の醍醐味 ⚡️

個人事業はあくまで個人であって、売上はともかく費用についてはどうしても 個人 / 事業の境界があいまいになる。たとえば「自宅を一部オフィスとして使ってるので、家賃の一部は費用のはず」とか。

そういうやつになるべく説得力のある理屈をつけて、「N% は事業に使ってるので費用です」と計上する。(実際は 確定申告時に理由を書く必要はなく、税務署調査が入ったら答えていく感じ )

自動車、通信費、光熱費など多岐にわたる。それぞれの理屈の付け方に (たぶん) 法律やガイドラインはなく、税務署の運用に任されている。

そう、運用の話です。税理士先生の出番ですよ。決算時にスポットで相談するとかで十分だけど、本当にプロの意見を聞いたほうがいい。

大きな理由のひとつは、税務署界隈でもあるとされる習慣や土地勘がわからないから。

「家賃はちょろまかす奴が多いから重点的にみられる。ここらではだいたい N% が相場とされる」とか「通信費は習慣的に K% でいける」とか分かるわけないです。「ここいらは高額納税者が多いから、このレベルの売上だともう一歩踏み込めると思う」とか「IT 業種多くないし極端でも目立たない可能性ある」とか。

さらに言えば税理士のなかでも「石橋を叩くタイプ」「一緒にリスクを取ってくれるタイプ」などさまざまいるみたいなので、感覚の合う税理士と出会えるかはキモ。基本は信用できる仕事仲間に紹介してもらうのがよいと思う。

事前に税理士について詳しく聞けて、気軽に相談できそうか、気が合いそうか、費用感についてもあたりをつけられるし、税理士の側も紹介を好む場合が多いらしい。

RIB / FIB コンバージェンスを可視化する方法論

高価なテスターを使わず、なんとかRIB / FIB コンバージェンスを計測することを考えています。

コンバージェンスとは

ネットワークにBGP イベントが到着してから、さまざまな計算を行い、イベントを送信し、定常状態に落ち着くまでのプロセスをコンバージェンスと呼びます。

インターネットルーティングではその所要時間 = コンバージェンスタイムに注目しながら、ネットワークや経路の設計、パラメーターチューニングをします。

RIB コンバージェンスという場合、多くはBGP Update を受信してからのコンバージェンスを指します。

ルーターバイス単体でみれば

1 . BGP Update を受信する
2 . Adj-RIB-In を更新する
3 . 受信フィルターを適用する
4 . Best Path を計算する
5 . Loc-RIB を更新する
6 . FIB を更新する

さらに、BGP Update を伝搬させるべき全てピアについて

7 . 送信フィルターを適用する
8 . Adj-RIB-Out を更新する
9 . BGP Update を送信する

このようなプロセスです。 1~6 を区別して「FIB コンバージェンス」と呼ぶことがあります。

原理的には 6 と 7~9 は並列処理可能ですが、パケットのループやブラックホールを避けるため、一般には 6 の完了を待って 7~9 を処理することが期待されます。

AS 単位 / インターネット全体でみると

一段マクロな視点では、AS にBGP イベントが到着してからAS 全体として処理するべきプロセスを完了することを BGP コンバージェンスと呼ぶことが多いです。インターネット全体でも同じです。

BGP イベント数について

RIB コンバージェンスという言葉のニュアンスには、イベント数の大小は含まれていません。「Prefix x.x.x.x/y のRIB コンバージェンス」「フルルートのRIB コンバージェンス」のように文脈によります。

「BGP コンバージェンス」の定義については、Informational なRFC4098RFC7747 などにまとまっています。

なぜコンバージェンスに注目するのか

ネットワークとしてのインターネットを制御するのに、AS 運用者はピアをし、経路フィルターを更新します。これによってBGP イベントを発生 / 伝搬させるわけですが、最近はコンバージェンスタイムが予測しづらくなってきました。

AS 内部においては

L3 スイッチに代表されるマーチャントシリコン製品が増え、ネットワークとしてカスタムシリコンのような機敏な動きが期待できない場合があります。

フルルートを食えない製品はもちろんのこと、RIB / FIB のハードウェアコンフィグレーションの個体差が大きくなっていると感じます。FIB のLPM (Longest Prefix Match) / LEM (Largest Exact Match) の塩梅まで制御するような取り組みも見られます。

正直なところ、やってみないとわからない。とくに「IPv4 unicast は128k routes までですっ」という製品に、ミスってフルルート入っちゃった場合のRIB / FIB のふるまいなどは予測できません。

また、VM ベースのルーター製品を使うことも増えました。思わぬボトルネックが存在することがあり、ネットワークに組み込む際にはコンバージェンスを気にしておく必要があります。

このような製品が悪というわけではなくて、利用可能な通信技術とハードウェアとソフトウェアをつかって、CAPEX + OPEX を最小化しつつ、要件を満たすネットワークをつくるのがネットワークエンジニアの腕の見せどころなので、避けて通るわけにはいきません。

頭の弱い製品を使ったとしても ネットワークとして安定すればいいわけです。

AS 外 / インターネット全体として

AS 内部のコンバージェンスがうまくいったとしても、インターネット全体として最適でない場合があります。コンバージェンスタイムは短いことが正義ではなく、お隣さんの処理速度に合わせてイベントをフロー制御することが理想です。

コンバージェンスが速すぎてNeighbor ルーターで無駄にCPU リソースを使い、かえって遅くなることもありますし、保守的に長く取りすぎてパケットロスを引き起こす こともあります。

ここでのフォーカス

うまくフィードバックをいれつつ インターネット全体で、特に自分のAS近辺で最適化することがゴールですが、まずはデバイス単体のRIB / FIB コンバージェンス観測を目的とします。

RIB / FIB コンバージェンスを計測する方法論

RFC7747 を参考にします。

eBGP の場合は

+------------+        +-----------+           +-----------+
|            |        |           |           |           |
|            |        |           |           |           |
|   HLP      |        |  DUT      |           | Emulator  |
|  (AS-X)    |--------| (AS-Y)    |-----------|  (AS-Z)   |
|            |        |           |           |           |
|            |        |           |           |           |
|            |        |           |           |           |
+------------+        +-----------+           +-----------+
        |                                            |
        |                                            |
        +--------------------------------------------+

Figure 2: Three-Node Setup for eBGP and iBGP Convergence

(https://tools.ietf.org/html/rfc7747)

このようなセットアップを使い、

5.1.2.  RIB-OUT Convergence

   Objective:

      This test measures the convergence time taken by an implementation
      to receive, install, and advertise a route using BGP.

(https://tools.ietf.org/html/rfc7747)

を計測します。

  1. Emulator から routeA 向けのパケットを HLP に流す
  2. Emulator から routeADUT に広告する
  3. DUTrouteAHLP に広告する
  4. (1 . のパケットが DUT に届き) DUTrouteA 向けのパケットを Emulator に転送する

3. - 2.routeA のRIB コンバージェンス、4. - 2.routeA のFIB コンバージェンスとします。

フルルートについて言えば、

最後の経路の 3. - 最初の経路の 2. がRIB コンバージェンス、最後の経路の 4. - 最初の経路の 2. がFIB コンバージェンスです。

処理するべき経路数によってふるまいが変わる場合があるため、コンバージェンスタイムの値だけで評価するのではなく、

  • 単位時間あたりに受信した経路数 (上の2. に対応)
  • 単位時間あたりに広告した経路数 (上の3. に対応)
  • 単位時間あたりにFIB インストールした経路数

の時間変化をプロットするのがよさそうです。

単位時間あたりにFIB インストールした経路数?

これを実現する妙案が浮かんでいません。ブラックボックステストで実現するべきなので「外部からパケットを入れて出てくるか確認する」アプローチなのは間違いありませんが、全アドレス空間宛てのパケットを常時生成するのは困難なため、

  1. BGP Update 直前か ほぼ同時に、該当Prefix に含まれるいくつかのアドレス宛てにパケットを送信
  2. DUT (Device Under Test) がフォワードするかを確認

おそらくこの形になります。

ただし、1. でどのアドレスを選択するべきかはLPM ベースなのか / LEM ベースなのかで異なりますし、100,000コ目の経路を処理した瞬間に1コ目の経路がRIB / FIB に存在するかも確認したほうがいいかもしれません。

今のところ、このあたりちょっとアイデアがありません。

バイスのstats を取っておきたい

計測中、デバイスのCPU 使用率、メモリ / RIB / FIB 使用量などを同時取得しておくとよさそう。

実装

機敏に動き、API を備えるgobgp を中心に実装してみます。

DUT で

  • 新しい経路を受信した場合
  • Best Path が変わった場合
  • 経路がなくなった場合

それぞれ ふるまいが違う可能性があるため、次のようなシナリオでテストします。

  1. gobgp 1 からフルルートを DUT に送信
  2. gobgp 2 からより強いフルルートを DUT に送信
  3. gobgp 2 から2. のWithdraw を DUT に送信
  4. gobgp 1 から1. のWithdraw を DUT に送信

2つのgobgp を制御して それぞれのシナリオに応じた経路を生成しつつ、それぞれの受信NLRI、送信NLRI を観測するプログラムを書きました。

経路は逐次生成ではなく、フルルートをロードしておいて送信ポリシーを reject → accept に変える、または accept → reject に変える、という方法で実装しています。

github.com

  • gobgp 制御はgRPC でやる
  • gobgp の動作を阻害したくないため、NLRI 観測にはlibpcap をつかう
  • なるべくリアルタイムに処理し、将来的にはFIB コンバージェンス計測にパケットを生成するため、go で実装
    • gobgp のgo APIとBGP パーサーを流用できるメリットもある

TCP を終端せず 観測者として動作させるためだけにTCP Reassemble を実装するのはアホらしいのですが、黙って実装します。

残念ながら、いまのところFIB コンバージェンスは計測できていません。

結果

このプログラムは上の4つのシナリオを順次実行し、結果をjson で保存します。

このチャートは あるVM ルーター製品のもので、毎秒の累積 送信/受信Prefix 数を描いています。テスト環境ではRIB コンバージェンスに7分かかることを示していて、経路数に対してほぼ線形であると予想できます。

コマンドラインオプションで経路数を指定できるので、実際に線形であるか確かめるシェルスクリプトも書けると思います。

余談ではありますが、この製品では、コンバージェンスまでの間CLI 上の送信経路数と実際の観測NLRI 数が大きく違っていました。

まとめ / これからやること

  • 昨今のルーター製品、とくにL3 スイッチ製品のRIB コンバージェンスが予測できないため、ブラックボックステストを行う必要があると考えています
  • その方法論について検討し、実装しました
  • FIB コンバージェンス計測のためのアイデアがありません…コメントお待ちします!!
  • gobgp がテストのボトルネックになる可能性があります。判断のヒントとなりそうな指標をチャートに載せるべきかもしれません

xlogin でコマンド自動投入→手動制御 を繰り返す

  1. コマンド群を入れる
  2. 手動制御
  3. 別のコマンド群を入れる
  4. 手動制御

を大量デバイス上でやりたい、ということがありました。

codeout.hatenablog.com

これを少しいじると便利になります。

# configure.tcl

source [file join [file dirname [info script]] juniper.tcl]

run "configure
set interfaces ge-0/0/0 description foo
show | compare
commit check
"

run "
set interfaces ge-0/0/1 description bar
show | compare
commit check
"

run "
exit
show chassis routing-engine
"

run の中身を入れ終わった後に手動制御になり、^n キーで自動制御に戻って次のrun に移ります。

configure.tcl の隣に juniper.tcl を置いておいてください。

実行例

codeout $ jlogin -s configure.tcl 192.168.0.81
192.168.0.81
set cli complete-on-space on
Enabling complete-on-space

codeout@vsrx> configure
Entering configuration mode

[edit]
codeout@vsrx# set interfaces ge-0/0/0 description foo

[edit]
codeout@vsrx# show | compare
[edit interfaces ge-0/0/0]
-   description "new 1";
+   description foo;

[edit]
codeout@vsrx# commit check
configuration check succeeds

[edit]
codeout@vsrx#                      <-- ここで手動制御に

[edit]
codeout@vsrx# commit
commit complete

[edit]
codeout@vsrx#                      <-- ^n で自動に戻す

[edit]
codeout@vsrx# set interfaces ge-0/0/1 description bar

[edit]
codeout@vsrx# show | compare
[edit interfaces ge-0/0/1]
-   description "new 2";
+   description bar;

[edit]
codeout@vsrx# commit check
configuration check succeeds

[edit]
codeout@vsrx#                      <-- ここで手動制御に

[edit]
codeout@vsrx# commit
commit complete

[edit]
codeout@vsrx#                      <-- ^n で自動に戻す

[edit]
codeout@vsrx# exit
Exiting configuration mode

codeout@vsrx> show chassis routing-engine
Routing Engine status:
    Total memory              2048 MB Max   635 MB used ( 31 percent)
      Control plane memory    1150 MB Max   449 MB used ( 39 percent)
      Data plane memory        898 MB Max   189 MB used ( 21 percent)
    CPU utilization:
      User                       0 percent
      Background                 0 percent
      Kernel                     0 percent
      Interrupt                  0 percent
      Idle                     100 percent
    Model                          FIREFLY-PERIMETER RE
    Start time                     2017-06-13 14:34:07 UTC
    Uptime                         5 minutes, 48 seconds
    Last reboot reason             Router rebooted after a normal shutdown.
    Load averages:                 1 minute   5 minute  15 minute
                                       0.01       0.10       0.07

codeout@vsrx>                      <-- ここで手動制御に

codeout@vsrx> %                                                                                                    codeout $

jlogin の例でした。

Routing protocols' seed metrics for redistributing

When routes are redistributed into another routing protocol, their metrics are also translated to different values depending on vendor implementation and routing protocol which the routes are being redistributed to. Tables below show what value will be chosen when redistributing between protocols with no default metric configured explicitly, that is called as “seed metric”.

The seed metrics listed below are picked from Juniper vSRX and Cisco IOS-XRv default behavior.

Juniper vSRX

from \ to ospf isis rip bgp (med)
direct 0 (E2) 0 (L1/L2) 0 none
static 0 (E2) 0 (L1/L2) 0 none
ospf ospf metric (L1/L2) 0 ospf metric
isis isis metric (E2) 0 none
rip rip metric (E2) rip metric (L1/L2) rip metric
aggregate 0 (E2) 10 (L1/L2) 0 none
bgp bgp med (E2) 10 (L1/L2) 0

Cisco IOS-XRv

from \ to eigrp ospf isis rip bgp (med)
connected variable (*1) 20 (E2) 0 (L2) (x) variable 0
static (x) 2^32-1 20 (E2) 0 (L2) (x) variable 0
eigrp 20 (E2) 0 (L2) (x) variable eigrp metric
ospf (x) 2^32-1 0 (L2) (x) variable ospf metric
isis (x) 2^32-1 20 (E2) (x) variable isis metric
rip (x) 2^32-1 20 (E2) 0 (L2) rip metric
bgp (x) 2^32-1 (*2) 1 (E2) (*2) 0 (L2) (*2) (x) variable
  • (x): default-metric must be configured to redistribute
    • (x) 2^32-1: Default metric is squashed by max value even when default-metric is configured. Note that redistribution cannot be done without default-metric.
    • (x) variable: Metric specified by default-metric is assigned.
  • (*1): Composite metric calculated from interface metrics
  • (*2): router bgp <ASN>; bgp redistribute-internal statement is required to restribute

inet-henge にいくつか機能を足した

inet-henge というネットワーク図生成ライブラリーに

  • リンク太さを変えられる
  • リンク両端に加え,中央にラベルを置ける

地味な機能を足した.

github.com

inet-henge とは?

JSON データを元にネットワーク図を生成してくれる js ライブラリー.オートレイアウトする.

このようなコンセプトで作っている.

  • 自動更新
    • 入力少なく
    • このくらいの外部データから生成したい.手動でレイアウトしたくない
{
  "nodes": [{ "name": "A" },{ "name": "B" }],
  "links": [{ "source": "A", "target": "B" }]
}
  • 美しくなくていい.見てわかる範囲でやってくれれば OK

  • 動かしたい

    • 運用しながら / 設計しながら見る.デバイスやPOP 単位でノードを動かしたい
    • レイアウトは保存しなくてもいい.再計算しても毎回結果が同じならOK
    • ズームしたい.ある程度拡大したときのみ細かい情報を表示したい
    • ブラウザでネットワーク図を表示したその画面で実現したい.ドキュメント内でもやりたい

デモ

youtu.be

Shownet 2016 Network

リンク太さを変える

こんな感じでメタデータを定義しておいて 👇

  "links": [
    { "source": "Node 1", "target": "Node 2", "meta": { "bandwidth": "1G" }},
    { "source": "Node 1", "target": "Node 3", "meta": { "bandwidth": "10G" }},
    { "source": "Node 2", "target": "Node 3", "meta": { "bandwidth": "100G" }}
  ]

こんな感じで描画する.👇 メタデータをもとにSVGstroke-width を返す関数を渡す.

var diagram = new Diagram('#diagram', 'index.json');
diagram.link_width(function (link) {
  if (!link)
    return 1;  // px
  else if (link.bandwidth === '100G')
    return 10; // px
  else if (link.bandwidth === '10G')
    return 3;  // px
});
diagram.init('bandwidth');

何も返さない場合はSVG のデフォルト = 1px になる.

リンクにラベルを置く

こんな感じのリンク情報があったとすると 👇

  "links": [
    {
      "source": "Node 1", "target": "Node 2",
      "meta": {
        "bandwidth": "10G",
        "intf-name": { "source": "interface A", "target": "interface B" }
      }
    }
  ]

こう書くことで 👇

new Diagram('#diagram', 'index.json').init('bandwidth', 'intf-name');

こうなる 👇

スタイルを変える

(追加機能ではないけれど) inet-henge はSVG を出力するので,CSS でスタイルを変えることができる.

.node rect {
  fill: #25271e !important;
  transform: scale(2) translate(-13px, -5px);
}

.node text {
  font-family: sans-serif;
  fill: #fff;
  font-size: 20px;
  transform: translate(0, 5px)
}

.link {
  stroke: #d0e799;
  stroke-opacity: 1;
}

今後

  • LAG をうまく表現できない.なんとかしたい
  • ノード / リンクが増えたときのパフォーマンスが問題.アルゴリズムの調整,計算結果の再利用など考えないといけない

もしご意見などありましたら…気軽にお声がけください!