LGTM

Looks Good To Me

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

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

Large BGP Community がやってくる前に,Community マッチをおさらいしよう

2017 / 02月,BGP Large Communities Attribute (RFC8092) がRFC 化された.

これは新たに 4Bytes:4Bytes:4Bytes のBGP Community を使えるようにするもので,既存の

  • BGP Community (RFC1997) - 2Bytes:2Bytes
  • Extended BGP Community (RFC4360) - 4Bytes:2Bytes もしくは 2Bytes:4Bytes

に比べて空間を広く使うことができる.BGP Community の先頭2バイト(もしくは4バイト) はGlobal Administrator と呼ばれ,ふつうは事業者のグローバルAS番号をあてる.加えて操作対象のAS番号,たとえば顧客のAS番号をBGP Community に含めたいケースがあり,これまでのBGP Community では空間が足りなかった.

近々BGP Community 空間が拡張されるにあたり「いま設定しているBGP Community 正規表現だいじょうぶなんだっけ?」と思って,いくつかの実装でマッチ方法を復習した.

Community マッチ方法

Juniper JUNOS

  • Community 表現(横) がマッチ対象(縦) にマッチするか
  • アルファベットはBGP Community を10進で表現したときの1ケタ.4ケタ = 2Bytes,6ケタ = 4Bytes
  • Large BGP Community 実装はなさそう
⬇️対象 \ 表現➡️ bbb:xxx bbb:xxx.* bbbL:xxx.*
bbb:xxx ⭕️ する ⭕️ する ❌ しない
abbb:xxx ❌ しない ⭕️ する ❌ しない
target:abbb:xxx ❌ しない ⭕️ する ❌ しない
target:aaabbb:xxx ❌ しない ❌ しない ⭕️ する
bbb:xxxy ❌ しない ⭕️ する ❌ しない

想像するに

  • L キーワードの有無で長さマッチ
  • \d+:\d+ パターンであれば^\d+:\d+$ と解釈.それ以外はそのまま

Cisco IOS-XR

  • 正規表現(横) がマッチ対象(縦) にマッチするか
  • アルファベットはBGP Community を10進で表現したときの1ケタ.4ケタ = 2Bytes
  • community-set の例.ほかにextcommunity-set キーワードがある
  • Large BGP Community 実装はなさそう
⬇️対象 \ 表現➡️ bbb:xxx bbb:* ios-regex ‘bbb:xxx’ ios-regex ‘bbb:xxx.*’
bbb:xxx ⭕️ する ⭕️ する ⭕️ する ⭕️ する
abbb:xxx ❌ しない ❌ しない ⭕️ する ⭕️ する
target:abbb:xxx ❌ しない ❌ しない ❌ しない ❌ しない
target:aaabbb:xxx ❌ しない ❌ しない ❌ しない ❌ しない
bbb:xxxy ❌ しない ⭕️ する ⭕️ する ⭕️ する

想像するに

  • community-set キーワード,extcommunity-set キーワードで分離.異なるものにマッチしない
  • ワイルドカードは 文頭 / 文末 を前提にしてマッチ
  • 正規表現は 文頭 / 文末 でなくてもマッチ

gobgp

  • 正規表現(横) がマッチ対象(縦) にマッチするか
  • アルファベットはBGP Community を10進で表現したときの1ケタ.4ケタ = 2Bytes,6ケタ = 4Bytes
  • community の例.ほかにext-communitylarge-community キーワードがある
  • Large BGP Community 対応バージョン
⬇️対象 \ 表現➡️ bbb:xxx bbb:xxx.*
bbb:xxx ⭕️ する ⭕️ する
abbb:xxx ❌ しない ⭕️ する
target:abbb:xxx ❌ しない ❌ しない
target:aaabbb:xxx ❌ しない ❌ しない
bbb:xxxy ❌ しない ⭕️ する
aaa:bbb:xxx ❌ しない ❌ しない
  • communityext-communitylarge-community キーワードで分離.異なるものにマッチしない
  • \d+:\d+ パターンであれば^\d+:\d+$ と解釈.それ以外はそのまま

Quagga

  • 正規表現(横) がマッチ対象(縦) にマッチするか
  • アルファベットはBGP Community を10進で表現したときの1ケタ.4ケタ = 2Bytes,6ケタ = 4Bytes
  • community-list の例.ほかにextcommunity-listlarge-community-list キーワードがある
  • Large BGP Community 対応バージョン
⬇️対象 \ 表現➡️ bbb:xxx bbb:xxx.*
bbb:xxx ⭕️ する ⭕️ する
abbb:xxx ⭕️ する ⭕️ する
target:abbb:xxx ❌ しない ❌ しない
target:aaabbb:xxx ❌ しない ❌ しない
bbb:xxxy ⭕️ する ⭕️ する
aaa:bbb:xxx ❌ しない ❌ しない
  • community-listextcommunity-listlarge-community-list キーワードで分離.異なるものにマッチしない
  • そのまま正規表現マッチ

Large BGP Community に対する懸念

2バイトの5ケタAS事業者が^ccccc:xxx$ と書くべきところを「ふつう2Bytes:2Bytes だし」とサボってccccc:xxx$ と書いてしまった場合に,意図しないLarge BGP Community にマッチして誤動作しないかを気にしていた.aaa:ccccc:xxxaaa:bccccc:xxx にマッチするかもなと.

4ケタ以下事業者は^ 忘れてないだろうし,4バイト事業者はうまくBGP Community を使えていないのでは と思われるので,問題になるとすれば2バイト5ケタかなと.

上記のようにまとめてみると,各実装とも既存の2Bytes:2Bytes Community と4Bytes:4Bytes:4Bytes のLarge BGP Community をキーワードで分離させる方針のようなので,杞憂かもしれない.

(JUNOS でExtended Community にマッチしてしまう細かな問題はあるかもしれない)

JUNOS のL キーワードはこれでいいんだっけ?

「4バイトの場合はL キーワードを使え」とドキュメントに書いているが,4Bytes:2Bytes もしくは 2Bytes:4Bytes だけであればこれでよかった.ところが4Bytes:4Bytes:4Bytes になると破綻するように思う.

aaa:bbb:ccc のうち,aaa はAS番号固定かもしれないが,bbb, ccc は2バイトレンジかもしれないし,4バイトレンジかもしれない.L の有無について4パターン併記しないといけない? それはつらい.

どういう実装で出してくるか楽しみだが,「L キーワードは捨てて,あらゆるCommunity について文頭~文末まで正規表現で文字列マッチします」というのがかえって分かりやすい気がする.

*1:手元に古いのしかなかった 😭

ステルスWiFi AP を駆逐した

macos がステルスWiFi AP に接続したときに脅してくるこれ,しばらく意味が分からなくて放置していた.

たぶんこういうことかな,というのを教えてもらって「なるほど,良くないかもしれん」と思い駆逐した.

ステルスAP が接続リストにいるリスク

アクティブにProbe Request を投げるため,接続可能なSSID の一部が漏れるから.せっかくMac Randomization してもSSID がリストで漏れており,個体識別されるリスクが高まる.ステルスじゃなくしたら漏れないかというと そうではないので「漏れやすさ」の問題.

ステルスAP が設定されているmacos 10.12.2 とIOS 10.2 の動き

ちゃんと調べたわけではありません.もし違っていたらご指摘ください.あれこれ操作したときの振る舞いを1時間くらい観察しました.

  • ステルスなSSID を探して,すべてのSSID についてProbe Request を投げまくる
  • ステルスAP に接続中のときも,そのSSID を含めて投げまくる

  • 違うAP がそのSSID を偽装したら

    • 正規のステルスAP がいない環境で,偽のステルスAP (SSID 同じ,認証なし) をつくる
    • 自動でそいつに接続することはなかった

ステルスAP が設定されていないmacos 10.12.2 とIOS 10.2 の動き

  • WiFi をON にした瞬間はActive Scan する = Probe Request を投げる
  • 放っておくとIOS 10.2 はActive Scan する
    • 端末がSleep しているのと関係あるかも (くわしく調べてない)
    • macos はそんな動きをしない (こちらはSleep していない)
  • それ以外SSID を投げていない.

かなりProbe Request が減った.

ステルスをやめる

そもそもステルスにしていたのは視界に入れたくなかったから.ほとんどメンテ不要なやつは消えていてほしい.とはいうものの,どこに持ち込むかわからない端末のほうのセキュリティリスクを下げたい.ステルスをやめることでAP のセキュリティリスクはさほど上がらない.

a/b/g/n/ac など広く802.11 を受けられる端末で

sudo tcpdump -I -ien0 -e -s0 type mgt subtype probe-req

を実行しつつ,一台ずつWiFI off/on してヘンなSSID を投げなくなるまで設定を削除した.

IOS はAP が存在しないと消せないので面倒だが,めちゃくちゃ古いSSID を探していて「おお…こいつ…こんなになっても〇〇を覚えてるのか…」って感傷的になれるのでオススメです.

BGP Community を透過する事業者がどれくらいいるか調べた

11月末にInternet Week 2016 というイベントで,「BGP Community の基本設計」について発表してきた.内容については 発表スライド をご覧いただければ良いかな と思うが,壇上から挙手アンケートを取ってみてびっくりした.

「顧客から受信したBGP Community を消さずに透過しているかた,どのくらいいますか?」の結果が 1%ほどだった.

該当するけど手を上げられなかった方もいると思うし,母数として全員がAS 運用者じゃなかったかもしれない.が,「えっ! 少なすぎる!」と思った.世の中そんなもんなのかな,と思ってざっと調査した内容を書いておく.

結果から書いておくと「割合的にはまあそんなもん」だった.

BGP Community は API なんですよ

BGP Community は「便利なタグ」だったり「他社ネットワーク内での自社経路のふるまいを定義できるノブ」だったりする.たとえば

  • 経路がネットワークに入ってきたのはどの国か,顧客に伝えるタグ
  • 他社ネットワーク内でLocal Preference を下げるためのノブ

のように,BGP プロトコルの範囲のなかで付加価値をつけることができる.「HTTP(S) でやれば?」という考えも頭をよぎるが,IP レイヤーの操作をさらに上のレイヤーに依存するのは危険かもしれないし,レイヤーをまたぎすぎている感がある.「HTTP(S) でもできる」が理想だけれど,IP ならではの柔軟性と拡張性を得るためにもBGP プロトコルでやりたいところ.

上のように AS65000 がBGP Community に乗せて便利情報を提供してくれている場合,AS65001 の立場からすると「自社に不利益がある」「AS65000 の利用規約に反する」ような場合を除いてAS65002 に透過しない理由はないはず.逆もしかりで,AS65002 が「AS65000 内での経路のふるまいを制御したい」と考えているとしてAS65001 がそれを遮断する理由はないように思う.

が,アンケート結果では「でも止めてる」だし,観測範囲内でも止めてる事業者がほとんどに見える.

特にAS65002 がAS65001 の顧客だった場合,情報を透過するほうがAS65001 サービスの付加価値につながりそうだし,ぜんぶ透過しなくても工夫してやればいいのに…と思う.

「将来,トランジット事業者(上の絵でいえばAS65000) を変えるかもしれない」という懸念はあるが,トランジット事業者が似たAPI を提供してさえすればAS65001 で変換するのがよさそう.他社のサービスや製品を組み合わせてうまいこと抽象化することは,サービスを作る側の手腕の見せ所かな と思う.

調査結果

AS間の関係を transit / peer / customer / unknown に分類し「X から受信したBGP Community をY に透過する事業者数」を数えた.調査の方法はあとで.

たとえば transit からcustomer に向かう矢印は93 だが,「transit から受信したBGP Community をcustomer に透過するAS は93 個あった」という意味.4バイトAS は除外してカウントしている.

BGPlay コレクターの配置的にすべてのAS をカバーしていないかもしれないが,フルルートの1/11 ほどのサンプル数.

  • customer から受信した経路を透過する事業者が比較的多そう
    • 送信先によって透過 / 不透過を区別してそう
    • 特にtransit 方向にはフィルターしてそう
  • 実際に使われている2バイトAS 約6万個に対して,透過しているAS はおよそ1% 程度しかない

ということがわかる.unknown が多いのは,参照したAS間の関係データベースが良くなかったかもしれない.

調査方法

BGPlayThe CAIDA UCSD as-relationships - 20161201 のデータを使った.

2バイトAS のすべてについて

  1. そのAS がoriginate している適当な1 prefix を選ぶ
  2. BGPlay でBGP Community が透過しているかどうか調べ,AS_PATH 上の各AS について transit / peer / customer のどれからどれに送信する際に透過するかをマークする
  3. AS 間の関係についてはCAIDA のas-relationships を参照する

仮定として

  • BGPlay コレクターはcustomer 相当と考える
  • BGP Community のGlobal Administrator がAS_PATH 上に現れるもののみをカウント
    • 現れない場合,BGP Community がどこでつけられたか判別できない
    • そのBGP Community は,AS_PATH 上のGlobal Administrator より右でつけられたものと考える

たとえば

  • AS_PATH: 65000 65001 65002 65003
  • BGP Community: 65002:100

の場合

  • Community は65002 か65003 でつけられたと仮定
    • → 65001 はCommunity を透過する
  • 65001 から見て65002 は transit で,65000 は customer
    • → 65001 は transit から受信したBGP Community を customer に透過する
  • 65000 から見て65001 は customer で,BGPlay コレクターも customer
    • → 65000 は customer から受信したBGP Community をcustomer に透過する

経路数でいえばフルルート68万経路に対して6万経路分,1/11 サンプルを調査した.BGPlay コレクターの配置から「透過しているんだけど観測できない」AS があることにも注意.

なお,今回は割合を概算したかったので 4バイトAS は除外してカウントしている.

Internet Week 2016 発表スライド

発表スライドをリンクしておきます.

  • AS 運用者向け
  • BGP Community 設計のコツ
  • API と思って設計しよう

のような内容です.よければご覧ください.

https://speakerdeck.com/codeout/bgp-communityfalse-ji-ben-she-ji

xlogin でコマンド自動投入したあと,手動制御にもどす

xlogin -s に渡すexpect スクリプトを書けばよい.

設定投入は自動でやって,温かみのある commit を打ちたい場合などにつかう.( そんなのcommit まで自動でやれよ,という話ではある)

jlogin の例

log_user 1

# 既存のrun_commands を参考に
proc run { prompt command } {
    # 補完を有効にしておく
    send "set cli complete-on-space on\r"
    expect -re $prompt {}

    # handle escaped ;s in commands, and ;; and ^;
    regsub -all {([^\\]);;} $command "\\1;\u002;" esccommand
    regsub {^;} $esccommand "\u002;" command
    set sep "\\1\u001"
    regsub -all {([^\\])\;} $command "$sep" esccommand
    set sep "\u001"
    set commands [split $esccommand $sep]
    set num_commands [llength $commands]
    for {set i 0} {$i < $num_commands} { incr i } {
        send "[lindex $commands $i]\r"
        expect {
            -re "^\[^\n\r *]*$prompt $" {}
            -re "^\[^\n\r]*$prompt." { exp_continue }
            -re "(\r\n|\n)" { exp_continue }
        }
    }
}


# 自動で入力したいコマンド群
set cmd_text "configure
set interfaces ge-0/0/0 description foo
show | compare
commit check
"

set command [join [split $cmd_text \n] \;]
run $prompt $command
interact

コマンド群を自動で send したあと,interact を呼べばいい.

実行例

configure という名前で保存してあるとして,

codeout $ jlogin -s configure router1
router1
set cli complete-on-space on
Enabling complete-on-space

codeout> configure
Entering configuration mode
The configuration has been changed but not committed

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

[edit]
codeout# show | compare
[edit interfaces ge-0/0/0]
+   description foo;

[edit]
codeout# commit check
configuration check succeeds

[edit]
codeout#

[edit]
codeout# <-- ここで手動制御にもどる

複数台に対して同じことをやりたい場合,

codeout $ jlogin -s configure router1 router2 ...

のようにまとめて呼ぶ.

ほかのclogin などで試してないが,同じような処理でいけるはず.