今日のCCO
読んだ
Anycast RP - Cisco
そっか、デフォルトで最大のIPアドレスを利用されるから、AnycastRP用のLoopbackインタフェースが選択されないようにIGP/EGPでのrouter-idは手動設定するべきなのね
Configuration example to migrate Spanning Tree from PVST+ to MST - Cisco
Spanning Tree Protocol Problems and Related Design Considerations - Cisco
BPDUの最大HOP数は覚えてなかった
Troubleshooting STP on Catalyst Switches Running Cisco IOS System Software - Cisco
Spanning-Tree Protocol Enhancements using Loop Guard and BPDU Skew Detection Features - Cisco
Spanning Tree PortFast BPDU Guard Enhancement - Cisco
When STP BPDU guard disables the port, the port remains in the disabled state unless the port is enabled manually. You can configure a port to reenable itself automatically from the errdisable state. Issue these commands, which set the errdisable-timeout interval and enable the timeout feature
Note: The default timeout interval is 300 seconds and, by default, the timeout feature is disabled.
Understanding and Tuning Spanning Tree Protocol Timers - Cisco
diameter of the STP domain (dia)—This value is the maximum number of bridges between any two points of attachment of end stations. The IEEE recommendation is to consider a maximum diameter of seven bridges for the default STP timers.
max age, forward delayがその他のパラメータによって決まってたとは知らんかった
max age
= End-to-end_BPDU_propa_delay + Message_age_overestimate
= 14 + 6
2 x forward delay
= end-to-end_BPDU_propagation_delay + Message_age_overestimate +
Maximum_frame_lifetime + Maximum_transmission_halt_delay
= 14 + 6 + 7.5 + 1 = 28.5 )
These calculations leave you with these two final formulas (if you round the 0.5 value):
max_age = (4 x hello) + (2 x dia) – 2
forward_delay = *1 / 2
hello, diaによってmax_age, forward_delayの導出ができるので、helloをいじればその他のタイマーも変わるけど
A decrease of the hello time to 1 sec is the easiest and surest way to decrease the STP parameters. However, remember that if you drop the hello time from 2 sec to 1 sec, you double the number of BPDUs that are sent/received by each bridge.
each BPDU includes the hello, forward delay, and max age STP timers. An IEEE bridge is not concerned about the local configuration of the timers value. The IEEE bridge considers the value of the timers in the BPDU that the bridge receives. Effectively, only a timer that is configured on the root bridge of the STP is important.
タイマーの定義はrootのものが使われるので
you must at least configure any timer changes on the root bridge and on the backup root bridge.
Understanding EtherChannel Inconsistency Detection - Cisco
EtherChannelの対向がチャネル解除されてる状態か…
*1:4 x hello) + (3 x dia
再配送についての整理(メモ)
再配送時のトラブルには3パターン
■High AD -> Low AD -> High AD(Fed Back)
Summary)
GatewayがLow ADから入手した情報をHigh ADへ渡すことでHigh AD側が誤ってLow ADからの再配送を信頼してしまい、High AD側でLow ADからの再配送経路を広告してしまうため自側の経路情報が消えてしまう
Solution)
High AD -> Low ADの再配送経路にタグ情報を付加し、Low AD -> High ADの再配送時に上記タグ付き経路を再配送対象から除外する。(route-map)
GatewayルータはLow AD側の情報を信頼するので、そこも修正したい場合は同一のroute-mapによってdistribute-listでLow AD側からRIBへ取り込む経路情報をフィルタする。
■複数プロトコルでの経路情報取得ループ(AD起因)
Prerequisite)
・複数のGateway(AおよびB)が複数のプロトコルでネイバリングし
それぞれ再配送を行っている
Summary)
1.GatewayAにてHigh AD -> Low ADの再配送を行う
2.同様に、GatewayBにてLow AD -> High AD(逆向き)の再配送を行う
3.GatewayAがHigh AD -> Low ADの再配送経路をRIBに乗せるためGatewayBにはLow ADにて再配送経路が広告される
4.GatewayBはHigh ADではなくLow ADで受け取った再配送経路情報をRIBに乗せる
5.GatewayAはGatewayBのLow ADから広告された経路情報(再配送)が信頼性が高いため自身がHigh ADから再配送した経路のネクストホップをGatewayBとする(##Control Planeでの選択ミス##)
6.GatewayBはGatewayAから広告された再配送経路のネクストホップが自分になっているため、送信先が解決できず経路情報が有効にならない(=無効経路)
7.GatewayBにて、再配送経路がLow ADで無効経路となったため、High ADでの経路情報がGatewayAに広告される。
8.GatewayAはLow ADでの広告がなくなるため、High AD -> Low ADの再配送が動作する。
【以降3〜8をループ】
Reason)
Low AD -> High ADの再配送によるFed Backではなく、複数プロトコルでの経路情報交換によってLow ADに再配送された経路情報がHigh ADではなくLow AD側で交換されることにより、ネクストホップ選択不正が発生するため
Solution)
Low AD側でHigh ADからの再配送経路(外部経路)のADをHigh ADよりも高くする。それによって再配送経路の生成元をHigh AD側であると判断させることができる。
■複数プロトコルでの経路情報取得ループ(Metric)
Prerequisite)
・複数のGateway(AおよびB)が複数のプロトコルでネイバリングしそれぞれ再配送を行っている
・再配送がディスタンスベクタとリンクステートなど、Metric情報が伝搬しないプロトコル間である
・ディスタンスベクタ側がHigh ADである
Summary)
1.GatewayAがディスタンスベクタ -> リンクステートへ再配送する
(Metric情報の喪失)
2.GatewayBはリンクステート側がLow ADであるため再配送経路をRIBに乗せる
3.GatewayBがリンクステート -> ディスタンスベクタへ、再配送元より低いシードメトリックで再配送する(誤ったメトリック設定)
4.ディスタンスベクタ ドメイン内で、もともとの生成元のメトリックより低いメトリックで経路情報が広告されることにより、再配送元経路のネクストホップがGatewayBになる。それにより隣接するノードはGatewayBに近い経路を最適経路と判断する。そのため正しい生成元経路(再配送シードメトリックより高いメトリック)情報がドメイン内で喪失する。(##経路選択不正発生##)
6.GatewayBはLow ADであるリンクステートドメイン側経路情報を利用しGatewayA(リンクステートへの再配送元)への経路を選択する。またGatewayAはディスタンスベクタ ドメイン内の経路情報に基づきGatewayBに到達するための最適経路がネクストホップとなる
7.GatewayA,Bはリンクステートからの再配送経路情報がなくなるためディスタンスベクタ ドメインの正しい生成元経路情報が復活する
【以降1-7をループ】
Reason)
再配送時に喪失したメトリック情報より低いシードメトリックで経路情報が戻ってくることにより、本来の生成元経路情報が喪失するため
Solution)
・シードメトリックが再配送前のメトリックより低くならないようにする
・再配送対象とならないようタグでフィルタする
重要知識)
・再配送は「RIB上の情報」をベースに行われる。
・RIP/IGRP/EIGRPはIGPの動作するインタフェースのネットワーク情報が再配送対象となる。
・再配送を行うノード上ではConnectedしかRIBに乗らないが、再配送先ではIGPの動作するインタフェースのネットワーク情報が広告される。
BGP Dumpning計算
Cisco公式のコマンドリファレンス見ても公式しか書いてないし、ワークブックで展開してくれてる式も「なぜそうなるの?」っていうところにいきなり飛んでてさっぱり分かんなかった。対数とかわかんないよ…
と嘆きながら調べてみるといい記事があったのでそこからの考え方を自分なりに整理。
例:ワークブックの問題そのままでいくと、公式に当てはめたら
となる。ここからWindows標準の計算機で計算できるようにしようとすると
- 2000 / 750 = 2^(5/x)
- func_logtwo(2000 / 750) = func_logtwo(2^(5/x))
- func_logtwo(2000 / 750) = 5/x
- ln(2000 / 750) / ln(2) = 5/x
- x = 5 / ln(2000 / 750) * ln(2) = 3.5334... ≒ 4
で、正解のhalf_timeである4が出てくる。max_suppress_timeはhalf_timeの4倍なので16
よって、デフォルトも含めて記載すると
bgp dampening 4 750 2000 16
が出てくる。ということ。ワークブックに書いてあった式にいきなり飛んだのはこういう流れねーと納得
※func_logtwo(x) = log2(x)を求める関数と仮定義。計算式は ln(x) / ln(2)
■
#!/bin/bash pushd ~/test/ine.ccie.rsv5.workbook.initial.configs > /dev/null CONFIG_DIR="" CONFIG_DIR_PRE="" LIST=($(dir | egrep "^" | awk -F. '{print $1}' | sort | uniq)) GNS3HOST=127.0.0.1 BASEPORT=2100 TFTPHOST=192.168.200.200 function sendconfig () { # enter selected config directory pushd $CONFIG_DIR > /dev/null # do expect scripting for R1 to R20, SW1 to SW4. ROUTER_NUM=`expr $(ls -l R*.cfg | wc -l) + 1` expect -c " match_max 20 set timeout 5 log_user 0 log_file -noappend -a /tmp/sendconfig.log set i 1 while {\$i < $ROUTER_NUM} { puts \"------------------------------------------------------------\" puts [exec \"date\"] send_user \"Send config to R\$i...\" puts \"\r\n------------------------------------------------------------\" set PORT [expr $BASEPORT + \$i] spawn telnet $GNS3HOST \$PORT set timeout 1 expect \"Connection refused\" { send_user \"\\033\\[1;31m\" send_user \"R\$i connect NG!\r\n\" send_user \"\\033\\[0;39m\" incr i 1 continue } #if {\$i==1} { exp_internal 1} else { exp_internal 0 } send \"\r\n\" expect \"R\$i\\u0007\" send \"\r\n\r\n\" expect \"\r\n\r\nR\$i#\" set timeout 60 send \"config replace tftp://$TFTPHOST/$CONFIG_DIR.\$i.cfg force\r\n\" expect { \"\r\nError: \" { send \"config replace tftp://$TFTPHOST/default.R\$i.cfg force\r\n\" expect \"Rollback Done\" set timeout 1 send \"\r\n\" expect \"R\$i#\" set fp [open \"R\$i.cfg\"] while {! [eof \$fp]} { gets \$fp line send \"\$line\r\n\" expect \"R\$i\(\" } close \$fp expect \"R\$i#\" set timeout 60 send \"\copy run tftp://$TFTPHOST/$CONFIG_DIR.\$i.cfg\r\n\" expect \"]\" send \"\r\n\" expect \"]\" send \"\r\n\" expect \"R\$i#\" close } \"\r\nRollback Done\" { expect \"R\$i#\" close } } incr i 1 } if {[file exists \"SW1.cfg\"]} { set i 1 while {\$i < 5} { puts \"------------------------------------------------------------\" puts [exec \"date\"] send_user \"Send config to SW\$i...\" puts \"\r\n--------------------------------------------------------\" set PORT [expr $BASEPORT + 10 + \$i] spawn telnet $GNS3HOST \$PORT send \"\r\n\r\n\" expect \"SW\$i#\" set fp [open \"SW\$i.cfg\"] while {! [eof \$fp]} { gets \$fp line send \"\$line\r\n\" expect \"SW\$i\(\" } close \$fp expect \"SW\$i#\" incr i 1 } } send_user \"send Configuration done.\r\n\" exit " popd > /dev/null } if [ ! -z $1 ]; then CONFIG_DIR=$1 echo ------------------------------------------------------------ echo SELECTED: [ $CONFIG_DIR ] echo ------------------------------------------------------------ sendconfig exit fi # create menu PS3="complete=0 > " while : do clear echo ------------------------------------------------------------ echo SELECTED: [ $CONFIG_DIR ] echo ------------------------------------------------------------ if [ ${#LIST[*]} -eq 0 ]; then break fi select SEL in ${LIST[*]} do if [ ${REPLY} = "q" ]; then # || [ ${REPLY} = "0" ]; then echo "Exit Menu." exit 0; else case "${REPLY}" in # Top "t" ) echo "Goto Top." CONFIG_DIR="" NUMBER_OF_FIELD=0 break ;; # Upper "u" ) # Not last 1 hop to top menu. if [ ${NUMBER_OF_FIELD} -gt 1 ]; then let NUMBER_OF_FIELD=${NUMBER_OF_FIELD}-1 CONFIG_DIR=${CONFIG_DIR_PRE} else NUMBER_OF_FIELD=0 CONFIG_DIR="" CONFIG_DIR_PRE="" fi break ;; "0" ) # complete menu check if [ -d $CONFIG_DIR ]; then break 2 fi echo "### Directory NOT Exist! ###" continue ;; * ) # Check mishit-key if [ -z $SEL ]; then # complete directory if [ ! -z $CONFIG_DIR ] && [ -d $CONFIG_DIR ]; then break 2 fi echo "### Directory NOT Exist! ###" continue 2 fi if [ -z $CONFIG_DIR ]; then NUMBER_OF_FIELD=1 CONFIG_DIR=${SEL} else CONFIG_DIR_PRE=${CONFIG_DIR} CONFIG_DIR=${CONFIG_DIR}.${SEL} NUMBER_OF_FIELD=`echo "$CONFIG_DIR" | awk -F. '{print NF}'` fi esac fi break done LIST=($(dir | egrep "^${CONFIG_DIR}" | awk -v NUMFIELD=$NUMBER_OF_FIELD -F. 'BEGIN{NUMFIELD = NUMFIELD + 1} {print $NUMFIELD}' | sort | uniq)) done sendconfig popd > /dev/null
コンフィグ自動投入シェル改造
config replaceに使えるようにTFTPへコンフィグ保管するように変更
#!/bin/bash pushd ~/test/ine.ccie.rsv5.workbook.initial.configs > /dev/null CONFIG_DIR="" CONFIG_DIR_PRE="" LIST=($(dir | egrep "^" | awk -F. '{print $1}' | sort | uniq)) GNS3HOST=127.0.0.1 BASEPORT=2100 TFTPHOST=127.0.0.1 # create menu PS3="complete=0 > " while : do clear echo ------------------------------------------------------------ echo SELECTED: [ $CONFIG_DIR ] echo ------------------------------------------------------------ if [ ${#LIST[*]} -eq 0 ]; then break fi select SEL in ${LIST[*]} do if [ ${REPLY} = "q" ]; then # || [ ${REPLY} = "0" ]; then echo "Exit Menu." exit 0; else case "${REPLY}" in # Top "t" ) echo "Goto Top." CONFIG_DIR="" NUMBER_OF_FIELD=0 break ;; # Upper "u" ) # Not last 1 hop to top menu. if [ ${NUMBER_OF_FIELD} -gt 1 ]; then let NUMBER_OF_FIELD=${NUMBER_OF_FIELD}-1 CONFIG_DIR=${CONFIG_DIR_PRE} else NUMBER_OF_FIELD=0 CONFIG_DIR="" CONFIG_DIR_PRE="" fi break ;; "0" ) # complete menu check if [ -d $CONFIG_DIR ]; then break 2 fi echo "### Directory NOT Exist! ###" continue ;; * ) # Check mishit-key if [ -z $SEL ]; then # complete directory if [ ! -z $CONFIG_DIR ] && [ -d $CONFIG_DIR ]; then break 2 fi echo "### Directory NOT Exist! ###" continue 2 fi if [ -z $CONFIG_DIR ]; then NUMBER_OF_FIELD=1 CONFIG_DIR=${SEL} else CONFIG_DIR_PRE=${CONFIG_DIR} CONFIG_DIR=${CONFIG_DIR}.${SEL} NUMBER_OF_FIELD=`echo "$CONFIG_DIR" | awk -F. '{print NF}'` fi esac fi break done LIST=($(dir | egrep "^${CONFIG_DIR}" | awk -v NUMFIELD=$NUMBER_OF_FIELD -F. 'BEGIN{NUMFIELD = NUMFIELD + 1} {print $NUMFIELD}' | sort | uniq)) done # enter selected config directory pushd $CONFIG_DIR > /dev/null # do expect scripting for R1 to R20, SW1 to SW4. ROUTER_NUM=`expr $(ls -l R*.cfg | wc -l) + 1` expect -c " set timeout 5 log_user 0 log_file -noappend -a /tmp/sendconfig.log set i 1 while {\$i < $ROUTER_NUM} { puts \"------------------------------------------------------------\" puts [exec \"date\"] send_user \"Send config to R\$i...\" puts \"\r\n------------------------------------------------------------\" set PORT [expr $BASEPORT + \$i] spawn telnet $GNS3HOST \$PORT set timeout 1 expect \"Connection refused\" { send_user \"\\033\\[1;31m\" send_user \"R\$i connect NG!\r\n\" send_user \"\\033\\[0;39m\" incr i 1 continue } send \"\r\n\r\n\" expect \"\r\nR\$i#\" set timeout 10 send \"config replace tftp://$TFTPHOST/$CONFIG_DIR.\$i.cfg force\r\n\" expect \"force\r\nError: \" { send \"config replace tftp://$TFTPHOST/default.R\$i.cfg force\r\n\" expect \"Rollback Done\" set timeout 1 set fp [open \"R\$i.cfg\"] while {! [eof \$fp]} { gets \$fp line send \"\$line\r\n\" expect \"R\$i\(\" } close \$fp expect \"R\$i#\" send \"\copy run tftp://$TFTPHOST/$CONFIG_DIR.\$i.cfg\r\n\" expect \"]\" send \"\r\n\" expect \"]\" send \"\r\n\" expect \"R\$i#\#\" close } \"R\$i#\" { close } incr i 1 } if {[file exists \"SW1.cfg\"]} { set i 1 while {\$i < 5} { puts \"------------------------------------------------------------\" puts [exec \"date\"] send_user \"Send config to SW\$i...\" puts \"\r\n--------------------------------------------------------\" set PORT [expr $BASEPORT + 10 + \$i] spawn telnet $GNS3HOST \$PORT send \"\r\n\r\n\" expect \"SW\$i#\" set fp [open \"SW\$i.cfg\"] while {! [eof \$fp]} { gets \$fp line send \"\$line\r\n\" expect \"SW\$i\(\" } close \$fp expect \"SW\$i#\" incr i 1 } } send_user \"send Configuration done.\r\n\" exit " popd > /dev/null popd > /dev/null
自動コンフィグ投入シェル
自動的に投げるためのシェル。
#!/bin/bash pushd ~/test/ine.ccie.rsv5.workbook.initial.configs > /dev/null CONFIG_DIR="" CONFIG_DIR_PRE="" LIST=($(dir | egrep "^" | awk -F. '{print $1}' | sort | uniq)) GNS3HOST=127.0.0.1 BASEPORT=2100 # create menu PS3="complete=0 > " while : do clear echo ------------------------------------------------------------ echo SELECTED: [ $CONFIG_DIR ] echo ------------------------------------------------------------ if [ ${#LIST[*]} -eq 0 ]; then break fi select SEL in ${LIST[*]} do if [ ${REPLY} = "q" ]; then echo "Exit Menu." exit 0; else case "${REPLY}" in # Top "t" ) echo "Goto Top." CONFIG_DIR="" NUMBER_OF_FIELD=0 break ;; # Upper "u" ) # Not last 1 hop to top menu. if [ ${NUMBER_OF_FIELD} -gt 1 ]; then let NUMBER_OF_FIELD=${NUMBER_OF_FIELD}-1 CONFIG_DIR=${CONFIG_DIR_PRE} else NUMBER_OF_FIELD=0 CONFIG_DIR="" CONFIG_DIR_PRE="" fi break ;; "0" ) # complete menu check if [ -d $CONFIG_DIR ]; then break 2 fi echo "### Directory NOT Exist! ###" continue ;; * ) # Check mishit-key if [ -z $SEL ]; then # complete directory if [ ! -z $CONFIG_DIR ] && [ -d $CONFIG_DIR ]; then break 2 fi echo "### Directory NOT Exist! ###" continue 2 fi if [ -z $CONFIG_DIR ]; then NUMBER_OF_FIELD=1 CONFIG_DIR=${SEL} else CONFIG_DIR_PRE=${CONFIG_DIR} CONFIG_DIR=${CONFIG_DIR}.${SEL} NUMBER_OF_FIELD=`echo "$CONFIG_DIR" | awk -F. '{print NF}'` fi esac fi break done LIST=($(dir | egrep "^${CONFIG_DIR}" | awk -v NUMFIELD=$NUMBER_OF_FIELD -F. 'BEGIN{NUMFIELD = NUMFIELD + 1} {print $NUMFIELD}' | sort | uniq)) done # enter selected config directory pushd $CONFIG_DIR > /dev/null # do expect scripting for R1 to R20, SW1 to SW4. ROUTER_NUM=`expr $(ls -l R*.cfg | wc -l) + 1` expect -c " set timeout 1 log_user 0 log_file -noappend -a /tmp/sendconfig.log set i 1 while {\$i < $ROUTER_NUM} { puts \"------------------------------------------------------------\" puts [exec \"date\"] send_user \"Send config to R\$i...\" puts \"\r\n------------------------------------------------------------\" set PORT [expr $BASEPORT + \$i] spawn telnet $GNS3HOST \$PORT expect \"Connection refused\" { send_user \"\\033\\[1;31m\" send_user \"R\$i connect NG!\r\n\" send_user \"\\033\\[0;39m\" incr i 1 continue } send \"\r\n\r\n\" expect \"R\$i#\" set fp [open \"R\$i.cfg\"] while {! [eof \$fp]} { gets \$fp line send \"\$line\r\n\" expect \"R\$i\(\" } close \$fp expect \"R\$i#\" incr i 1 } if {[file exists \"SW1.cfg\"]} { set i 1 while {\$i < 5} { puts \"------------------------------------------------------------\" puts [exec \"date\"] send_user \"Send config to SW\$i...\" puts \"\r\n--------------------------------------------------------\" set PORT [expr $BASEPORT + 10 + \$i] spawn telnet $GNS3HOST \$PORT send \"\r\n\r\n\" expect \"SW\$i#\" set fp [open \"SW\$i.cfg\"] while {! [eof \$fp]} { gets \$fp line send \"\$line\r\n\" expect \"SW\$i\(\" } close \$fp expect \"SW\$i#\" incr i 1 } } send_user \"send Configuration done.\r\n\" exit " popd > /dev/null popd > /dev/null