なんちゃってFlexlink+を実装してみる。

# はじめに
この記事はシスコの同志による Advent Calendar の一部として投稿しています

2017年版: https://qiita.com/advent-calendar/2017/cisco
2018年版: https://qiita.com/advent-calendar/2018/cisco
2019年版: https://qiita.com/advent-calendar/2019/cisco
2020年版: https://qiita.com/advent-calendar/2020/cisco
2020年版(2枚目): https://qiita.com/advent-calendar/2020/cisco2
2021年版: https://qiita.com/advent-calendar/2021/cisco
2021年版(2枚目): https://qiita.com/advent-calendar/2021/cisco2
2022年版: https://qiita.com/advent-calendar/2022/cisco
2023年版：https://qiita.com/advent-calendar/2023/cisco

:::note info
本記事は2023年版Advent Calendarの11日目の投稿になり、私自身としては4回目の投稿となります。今年はPythonではなく、IOS-XEの簡易プログラミング機能としてのEEMの活用例を記載させていただきます。
:::

# 背景：
みなさん、Flexlink+というテクノロジーはご存じでしょうか。昔、C3850時代にFlexlink(当時は「+」無し)という名前で実装され、STPを使わないアップリンクの冗長化技術として非常に便利な機能があり、それがC9000シリーズにおいても実装されています。ところが、C9500の新しいモデルだとなんとこの技術がサポートされていないのですΣ(ﾟДﾟ)。

:::note warn
ちなみにStackWise Virtual構成だとそもそもC9500ではFlexlink+はサポートされておりません。
:::
> Restrictions for FlexLink+
 This feature is not supported on C9500-24Y4C, C9500-32C, C9500-32QC, C9500-48Y4C, and model of Cisco Catalyst 9500 High Performance Series Switches.
 FlexLink+ is not supported in a Cisco StackWise Virtual solution.

[参考 Configuring Flexlink+](https://www.cisco.com/c/en/us/td/docs/switches/lan/catalyst9500/software/release/17-12/configuration_guide/lyr2/b_1712_lyr2_9500_cg/configuring_flexlink_.html)

なんらかの事情でSTPが使えない場合、アップリンクが同じ速度であれば、MEC（multichassis EtherChannel）を使えば、リンクの冗長化は出来るのですが、環境によっては10G、1Gのような異速度でWAN向けのアップリンクを構成されていることもあると思います。そんなときにはFlexlink+の出番になるのですが、C9500だと使えないのです。もどかしいですね。そこでなんとか異速度アップリンク時に冗長化が出来ないかと考えていきついたのが、EEM（Embedded Event Manager）の活用です。

:::note info
EEMについてはQiitaにもたくさん記事がありますのでご参照ください。
https://qiita.com/tags/eem
:::

# 動作概要：
検証構成としては下記になります。機器はC9500が準備出来なかったので、C9300Xで検証していますが、EEMの内容については同じIOS-XEですので差異はないです。

![C9300X-flex.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/866339/40108ca5-8244-6740-32ea-3b88ec3b86f9.png)

動作概要としては下記です。
* 切替：Tw1/0/1がリンクダウンするとTw1/0/2のリンクを`no shut`する
* 切戻し：Tw1/0/1がリンクアップするとTw1/0/2のリンクを`shut`する

非常に簡単です。では、それぞれの動作についてもう少しブレイクダウンしていきます。

:::note info
ちなみにインタフェースの「Tw」というのは「TwentyFiveGigE」の略で25Gbpsまで対応しているという意味です。C9300シリーズでもダウンリンクが25Gbps対応しているのを見ると時代を感じますよね。
:::

### 切替時：
* リンクダウン検知のログとしては下記のようなログが出ます。

```
%LINEPROTO-5-UPDOWN: Line protocol on Interface TwentyFiveGigE1/0/1, changed state to down
```

* このログから事前定義したインタフェースタイプ、ポート番号かどうかを確認します。
* 対象のポートの場合、バックアップインタフェースを`no shut`します。
* このときにログに下記のようなメッセージを出力させます。

```
%HA_EM-6-LOG: main_uplink_down: Main uplink TwentyFiveGigE1/0/1 is down(T_T) (T_T) (T_T). So  TwentyFiveGigE1/0/2 was NO shut by detecting main uplink down
```

### 切戻し時：
* リンクアップ検知のログとしては下記のようなログが出ます。
```
%LINEPROTO-5-UPDOWN: Line protocol on Interface TwentyFiveGigE1/0/1, changed state to up
```
* このログから事前定義したインタフェースタイプ、ポート番号かどうかを確認します。
* 対象のポートの場合、バックアップインタフェースを`shut`します。
* このときにログに下記のようなメッセージを出力させます。
```
%HA_EM-6-LOG: main_uplink_up: Main uplink TwentyFiveGigE1/0/1 is UP. So  TwentyFiveGigE1/0/2 was shut by detecting main uplink up
```

# 作成したスクリプト
では、実際、上記のフローに従って、EEMでスクリプトを作成します。

### 切替時のスクリプト

```config:link-up
event manager session cli username "cisco"
event manager applet backup-link-up
event syslog pattern "LINEPROTO-5-UPDOWN: Line protocol on .*, changed state to down"
action 0.01 set lower_port_number "1"
action 0.02 set upper_port_number "1"
action 0.5 regexp "Interface (.*)," "$_syslog_msg" match1 int
action 0.501 regexp "^TwentyFiveGigE1/0/(.*)" "$int" match2 sub2
action 0.502 if $_regexp_result eq "0" goto 3.3
action 0.71 if $sub2 lt "$lower_port_number" goto 3.3
action 0.72 if $sub2 gt "$upper_port_number" goto 3.3
action 0.8 cli command "enable"
action 1.0 cli command "conf t"
action 1.1 cli command "interface TwentyFiveGigE1/0/2"
action 1.2 cli command "no shutdown"
action 2.0 syslog msg "Main uplink $int is down(T_T) (T_T) (T_T). So  TwentyFiveGigE1/0/2 was NO shut by detecting main uplink down"
action 3.3 cli command "end"
```

### 切戻し時のスクリプト
```config:link-down
event manager session cli username "cisco"
event manager applet backup-link-down
event syslog pattern "LINEPROTO-5-UPDOWN: Line protocol on .*, changed state to up"
action 0.01 set lower_port_number "1"
action 0.02 set upper_port_number "1"
action 0.5 regexp "Interface (.*)," "$_syslog_msg" match1 int
action 0.501 regexp "^TwentyFiveGigE1/0/(.*)" "$int" match2 sub2
action 0.502 if $_regexp_result eq "0" goto 3.3
action 0.71 if $sub2 lt "$lower_port_number" goto 3.3
action 0.72 if $sub2 gt "$upper_port_number" goto 3.3
action 0.8 cli command "enable"
action 1.0 cli command "conf t"
action 1.1 cli command "interface TwentyFiveGigE1/0/2"
action 1.2 cli command "shutdown"
action 2.0 syslog msg "Main uplink $int is up!!!!! So  TwentyFiveGigE1/0/2 was shut by detecting main uplink up"
action 3.3 cli command "end"
```

# 動作確認
では、早速、動作確認してみましょう。

## 切替り時
対向のネットワーク機器のインタフェースを`shutdown`してみると、C9300Xに下記のようなログが出力します。

### ログ
```:syslog
*Oct  4 06:24:11.488: %LINEPROTO-5-UPDOWN: Line protocol on Interface TwentyFiveGigE1/0/1, changed state to down
*Oct  4 06:24:11.831: %HA_EM-6-LOG: backup-link-up: Main uplink TwentyFiveGigE1/0/1 is down(T_T) (T_T) (T_T). So  TwentyFiveGigE1/0/2 was NO shut by detecting main uplink down
*Oct  4 06:24:11.832: %SYS-5-CONFIG_I: Configured from console by cisco on vty0 (EEM:backup-link-up)
*Oct  4 06:24:12.490: %LINK-3-UPDOWN: Interface TwentyFiveGigE1/0/1, changed state to down
*Oct  4 06:24:13.488: %LINEPROTO-5-UPDOWN: Line protocol on Interface Vlan100, changed state to down
*Oct  4 06:24:13.489: %LINEPROTO-5-UPDOWN: Line protocol on Interface Vlan101, changed state to down
*Oct  4 06:24:13.732: %LINK-3-UPDOWN: Interface TwentyFiveGigE1/0/2, changed state to down
*Oct  4 06:24:16.655: %LINK-3-UPDOWN: Interface TwentyFiveGigE1/0/2, changed state to up
*Oct  4 06:24:18.656: %LINEPROTO-5-UPDOWN: Line protocol on Interface TwentyFiveGigE1/0/2, changed state to up
```

### 切替り前コンフィグ
```diff:切替前
interface TwentyFiveGigE1/0/2
 switchport trunk allowed vlan 100,101
 switchport mode trunk
 shutdown
end
```

### 切替り後コンフィグ
```diff:切替後
interface TwentyFiveGigE1/0/2
 switchport trunk allowed vlan 100,101
 switchport mode trunk
                                        <--- shutdownが削除される（コマンド的にはno shutされる）
end
```

このように、バックアップインタフェースの設定を前後で比較してみると、切替後には`shutdown`が無くなっているので、インタフェースが有効化されていることが分かります。

## 切戻し時
次に対向のネットワーク機器のインタフェースを`no shutdown`してみると、C9300Xには下記のようなログが出力します。

### ログ
```:syslog
*Oct  4 06:32:15.219: %LINK-3-UPDOWN: Interface TwentyFiveGigE1/0/1, changed state to up
*Oct  4 06:32:17.220: %LINEPROTO-5-UPDOWN: Line protocol on Interface TwentyFiveGigE1/0/1, changed state to up
*Oct  4 06:32:17.467: %HA_EM-6-LOG: backup-link-down: Main uplink TwentyFiveGigE1/0/1 is up!!!!! So  TwentyFiveGigE1/0/2 was shut by detecting main uplink up
*Oct  4 06:32:17.468: %SYS-5-CONFIG_I: Configured from console by cisco on vty0 (EEM:backup-link-down)
*Oct  4 06:32:19.466: %LINK-5-CHANGED: Interface TwentyFiveGigE1/0/2, changed state to administratively down
*Oct  4 06:32:20.466: %LINEPROTO-5-UPDOWN: Line protocol on Interface TwentyFiveGigE1/0/2, changed state to down
```

### 切戻し前コンフィグ
```diff:切戻し前
interface TwentyFiveGigE1/0/2
 switchport trunk allowed vlan 100,101
 switchport mode trunk
end
```

### 切戻し後コンフィグ
```diff:切戻し後
interface TwentyFiveGigE1/0/2
 switchport trunk allowed vlan 100,101
 switchport mode trunk
 shutdown                                <--- shutdownが追加される
end
```

バックアップインタフェースの設定を前後で比較してみると、切戻し後には`shutdown`が入っているので、インタフェースが無効化されていることが分かります。

# まとめと注意事項
こんな感じに簡単なスクリプトで疑似的なFlexlink+を実装することが出来ました。ただし、実際のFlexlink+とは違うので下記の点をご注意ください。
* メインアップリンクのリンクダウン検知に基づいて、バックアップリンクをリンクアップさせる策ですので、リンクダウン検知出来ない場合は機能しません。
* その場合、IP SLAを組み合せてIPリーチャビリティ有無でのコントロールは可能ですが、ACL等を使ってメインアップリンクからしかPINGが届かないターゲットの作成が必要です。
* 対抗機器と直結でない場合、対抗機器はリンクダウン検知しないため、対抗側から発生する端末向け通信は端末から通信が発生しないとすぐには通信が復旧しない可能性があります（※）。
* EEMはDNA-Eのためサービス提供期間のライセンスが（道義上）必要

:::note info
※ 本家Flexlink+はこの問題に対処するために、切替時にダミーマルチキャストを使います。賢いですね。
:::

# 免責事項
本サイトおよび対応するコメントにおいて表明される意見は、投稿者本人の個人的意見であり、シスコの意見ではありません。本サイトの内容は、情報の提供のみを目的として掲載されており、シスコや他の関係者による推奨や表明を目的としたものではありません。各利用者は、本Webサイトへの掲載により、投稿、リンクその他の方法でアップロードした全ての情報の内容に対して全責任を負い、本Web サイトの利用に関するあらゆる責任からシスコを免責することに同意したものとします。