📌

CEF(Cisco Express Forwarding)の動作検証メモ

2021/04/11に公開

はじめに

現在普及しているCisco機器では、以下のIPフォワーディング処理を、CEF(Cisco Express Forwarding)というCisco独自の方式で実現しています。

  • パケット受信
  • パケット送信先機器の決定(等コストのパスが複数ある場合、どれを使うかの選択を含む)
  • パケット送信

本機能について、IOSで動作確認した結果をメモしておきます。

1. CEF概要

詳細はCiscoサイトや他のブログにお任せして、ポイントだけ記載しておきます。

①フォワーディング処理にあたり、以下テーブルを作成・参照。

テーブル 説明
FIBテーブル ルーティングテーブルをベースに作成される。宛先ネットワークとネクストホップアドレス情報を含む。
Adjacencyテーブル ARPテーブルをベースに作成される。ネクストホップアドレスに紐付くMACアドレス、出力インターフェースとそのMACアドレス情報を含む。

②等コストパスのロードバランシング方式は、以下の2種類がある。

方式 説明
宛先単位 (Per-destination) デフォルトで採用。名前が紛らわしいが送信元と宛先ホストの組み合わせでパスが決定される。
パケット単位 (Per-packet) パケット毎にパスを決定。1つのセッションが複数パスを通り得るため、パケット到着順序逆転により、音声やビデオの通信品質に影響が出る可能性あり。

③ロードバランシングアルゴリズムとして、代表的なものは以下。

アルゴリズム 説明
Original 送信元、宛先アドレスから計算したハッシュ値をもとに、パスを決定。名前の通り当初からあるアルゴリズムで、冗長パスが全く使用されなくなるCEFの極性(※)が課題。
Universal デフォルトで採用。CEFの極性を防ぐため、送信元、宛先アドレスに加え、機器に割り振られた4バイト長のユニバーサルIDの組み合わせでハッシュ値を計算。ユニバーサルIDの採番方法は非公開。手動でも設定可能。
Include-ports Universalアルゴリズムに加え、さらに送信元、宛先ポート番号のいずれかもしくは両方をハッシュ計算に利用。
Tunnel こちらもUniversalアルゴリズムの改良版で、トンネルをはっていて、送信元、宛先ペアが少ないケースで利用。

※ CEFの極性(Polarization)の詳細はこちら
https://www.cisco.com/c/ja_jp/support/docs/ip/express-forwarding-cef/116376-technote-cef-00.html

2. 事前準備

2-1. 検証構成

iosv-0iosv-1(IOSv、15.8(3)M2)を3本のリンクで互いに接続し、desktop-0からdesktop-1(Alpine Linux)向けの通信が、3つのパスでバランシングされるようにしました。

2-2. ルーティング設定、CEFテーブル確認

以下のStaticルーティングにより、等コストを実現しています。

iosv-0の設定
ip route 10.2.2.0 255.255.255.0 10.3.3.2
ip route 10.2.2.0 255.255.255.0 10.4.4.2
ip route 10.2.2.0 255.255.255.0 10.5.5.2
iosv-1の設定
ip route 10.1.1.0 255.255.255.0 10.3.3.1
ip route 10.1.1.0 255.255.255.0 10.4.4.1
ip route 10.1.1.0 255.255.255.0 10.5.5.1

iosv-0のルーティングテーブルを見ると、10.2.2.0/24宛てのネクストホップが3つ表示されています。

iosv-0#show ip route 10.2.2.0
Routing entry for 10.2.2.0/24
  Known via "static", distance 1, metric 0
  Routing Descriptor Blocks:
    10.5.5.2
      Route metric is 0, traffic share count is 1
    10.4.4.2
      Route metric is 0, traffic share count is 1
  * 10.3.3.2
      Route metric is 0, traffic share count is 1

CEFはデフォルトで有効化されていますので、このタイミングでFIBテーブルにも反映されていました。

iosv-0#show ip cef 10.2.2.0/24
10.2.2.0/24
  nexthop 10.3.3.2 GigabitEthernet0/1
  nexthop 10.4.4.2 GigabitEthernet0/2
  nexthop 10.5.5.2 GigabitEthernet0/3

2-3. Adjacencyテーブル確認

こちらも事前に確認しておきます。ARPテーブルの中で、自分自身(Ageが-のエントリ)以外は、Adjacencyテーブルに反映されている事が分かります。

iosv-0#show ip arp
Protocol  Address          Age (min)  Hardware Addr   Type   Interface
Internet  10.1.1.1                -   5254.0015.00ca  ARPA   GigabitEthernet0/0
Internet  10.1.1.100              4   5254.0017.2fe6  ARPA   GigabitEthernet0/0
Internet  10.3.3.1                -   5254.0007.cf14  ARPA   GigabitEthernet0/1
Internet  10.3.3.2              117   5254.0015.29b4  ARPA   GigabitEthernet0/1
Internet  10.4.4.1                -   5254.0003.aafb  ARPA   GigabitEthernet0/2
Internet  10.4.4.2              116   5254.001b.27e2  ARPA   GigabitEthernet0/2
Internet  10.5.5.1                -   5254.0014.86d7  ARPA   GigabitEthernet0/3
Internet  10.5.5.2               83   5254.0011.03b7  ARPA   GigabitEthernet0/3
iosv-0#show adjacency 
Protocol Interface                 Address
IP       GigabitEthernet0/0        10.1.1.100(7)
IP       GigabitEthernet0/1        10.3.3.2(13)
IP       GigabitEthernet0/2        10.4.4.2(13)
IP       GigabitEthernet0/3        10.5.5.2(13)

2-4. CEF統計情報の有効化

以下設定により、CEFロードバランシングに関する統計情報を収集可能です。具体的には、各パス(ハッシュバケット)へフォワーディングされたパケット数、バイト数、割合などを閲覧できます。

ip cef accounting load-balance-hash

3. Universalアルゴリズム(デフォルト)の動作

3-1. CEF設定内容

設定項目
ロードバランシング方式 宛先単位
アルゴリズム Universal

show cef stateコマンドの※部分で設定が確認できます。ユニバーサルIDは「C9C9DAD7」になっています。

iosv-0#show cef state
CEF Status:
 RP instance
 common CEF enabled
IPv4 CEF Status:
 CEF enabled/running
 dCEF disabled/not running
 CEF switching enabled/running
 universal per-destination load sharing algorithm, id C9C9DAD7 ※
IPv6 CEF Status:
 CEF disabled/not running
 dCEF disabled/not running
 universal per-destination load sharing algorithm, id C9C9DAD7

3-2. ロードバランシングの内部データ構造

show ip cef <宛先アドレス> internalコマンドで確認できます。10.2.2.0/24の結果を見ると、0~14のハッシュバケットがあり、1:1:1で3つのパスが割り振られています。具体的には、0,3,6,9,12は10.3.3.2、1,4,7,10,13は10.4.4.2、2,5,8,11,14は10.5.5.2をそれぞれネクストホップとしています。

送信元、宛先ホスト情報から計算したハッシュ値に従い、どのバケットに割り振られるか決定されます。

下の方のHash Bucket Usageで、ハッシュバケット単位の使用状況が確認できます。今回はバケット4,6,10,12でそれぞれ8,1,1,1パケットが使われています。
また、Choice usageでChoice(パス)単位の使用状況も確認可能です。今回はChoice0(10.3.3.2宛て)、Choice1(10.4.4.2宛て)でそれぞれ2,9パケットが使われています。

iosv-0#show ip cef 10.2.2.0 internal
10.2.2.0/24, epoch 0, RIB[S], refcnt 5, per-destination sharing
  sources: RIB 
  feature space:
    IPRM: 0x00048000
  ifnums:
    GigabitEthernet0/1(3): 10.3.3.2
    GigabitEthernet0/2(4): 10.4.4.2
    GigabitEthernet0/3(5): 10.5.5.2
  path list 0FA962EC, 3 locks, per-destination, flags 0xE9 [shble, rif, rcrsv, hwcn, hwmod]
    path 0FA96484, share 1/1, type recursive, for IPv4
      recursive via 10.3.3.2[IPv4:Default], fib 0F642708, 1 terminal fib, v4:Default:10.3.3.2/32
      path list 0EE08CE4, 2 locks, per-destination, flags 0x49 [shble, rif, hwcn]
          path 10E99260, share 1/1, type adjacency prefix, for IPv4
            attached to GigabitEthernet0/1, IP adj out of GigabitEthernet0/1, addr 10.3.3.2 0FCDC728
    path 0FA964F0, share 1/1, type recursive, for IPv4
      recursive via 10.4.4.2[IPv4:Default], fib 0F642684, 1 terminal fib, v4:Default:10.4.4.2/32
      path list 0FA9624C, 2 locks, per-destination, flags 0x49 [shble, rif, hwcn]
          path 10E991F4, share 1/1, type adjacency prefix, for IPv4
            attached to GigabitEthernet0/2, IP adj out of GigabitEthernet0/2, addr 10.4.4.2 0FCDC5F8
    path 0FA9655C, share 0/1, type recursive, for IPv4
      recursive via 10.5.5.2[IPv4:Default], fib 0F642600, 1 terminal fib, v4:Default:10.5.5.2/32
      path list 0FA9629C, 2 locks, per-destination, flags 0x49 [shble, rif, hwcn]
          path 10E99188, share 1/1, type adjacency prefix, for IPv4
            attached to GigabitEthernet0/3, IP adj out of GigabitEthernet0/3, addr 10.5.5.2 0E7526A0
  output chain:
    loadinfo 0F640BA8, per-session, 3 choices, flags 0003, 5 locks
      flags [Per-session, for-rx-IPv4]
      15 hash buckets
        < 0 > IP adj out of GigabitEthernet0/1, addr 10.3.3.2 0FCDC728
        < 1 > IP adj out of GigabitEthernet0/2, addr 10.4.4.2 0FCDC5F8
        < 2 > IP adj out of GigabitEthernet0/3, addr 10.5.5.2 0E7526A0
        < 3 > IP adj out of GigabitEthernet0/1, addr 10.3.3.2 0FCDC728
        < 4 > IP adj out of GigabitEthernet0/2, addr 10.4.4.2 0FCDC5F8
        < 5 > IP adj out of GigabitEthernet0/3, addr 10.5.5.2 0E7526A0
        < 6 > IP adj out of GigabitEthernet0/1, addr 10.3.3.2 0FCDC728
        < 7 > IP adj out of GigabitEthernet0/2, addr 10.4.4.2 0FCDC5F8
        < 8 > IP adj out of GigabitEthernet0/3, addr 10.5.5.2 0E7526A0
        < 9 > IP adj out of GigabitEthernet0/1, addr 10.3.3.2 0FCDC728
        <10 > IP adj out of GigabitEthernet0/2, addr 10.4.4.2 0FCDC5F8
        <11 > IP adj out of GigabitEthernet0/3, addr 10.5.5.2 0E7526A0
        <12 > IP adj out of GigabitEthernet0/1, addr 10.3.3.2 0FCDC728
        <13 > IP adj out of GigabitEthernet0/2, addr 10.4.4.2 0FCDC5F8
        <14 > IP adj out of GigabitEthernet0/3, addr 10.5.5.2 0E7526A0
      Subblocks:
        Hash Bucket Usage:
          Bucket/Choice   Packets         Bytes     Usage  Histogram
             < 0/0 >            0             0      0.0%  
             < 1/1 >            0             0      0.0%  
             < 2/2 >            0             0      0.0%  
             < 3/0 >            0             0      0.0%  
             < 4/1 >            8           634     72.7%  ==============-
             < 5/2 >            0             0      0.0%  
             < 6/0 >            1            46      9.0%  =-
             < 7/1 >            0             0      0.0%  
             < 8/2 >            0             0      0.0%  
             < 9/0 >            0             0      0.0%  
             <10/1 >            1            46      9.0%  =-
             <11/2 >            0             0      0.0%  
             <12/0 >            1            46      9.0%  =-
             <13/1 >            0             0      0.0%  
             <14/2 >            0             0      0.0%  
          -----------------------------------------------
             Totals            11           772    100.0% (ideal:6.6%)
        Choice usage:
          Choice/Share    Packets         Bytes     Usage  Histogram
             < 0/1 >            2            92     18.1%  ===-
             < 1/1 >            9           680     81.8%  ================
             < 2/1 >            0             0      0.0%  
          -----------------------------------------------
             Totals            11           772    100.0%

ちなみに、等コストパスが2つの場合、0~15の計16個のハッシュバケットを1:1で分割します。(3つの場合は最後が端数のため計15個しか使用されない。)

3-3. ロードバランシング例

以下パケットを例に、どのパスが採用されるか確認してみます。

設定項目
送信元アドレス 10.1.1.100
宛先アドレス 10.2.2.100

show ip cef exact-route <送信元アドレス> <宛先アドレス>コマンドで、どのパスが採用されるか確認可能です。今回の例では、10.5.5.2がネクストホップとなっています。

iosv-0#show ip cef exact-route 10.1.1.100 10.2.2.100
10.1.1.100 -> 10.2.2.100 =>IP adj out of GigabitEthernet0/3, addr 10.5.5.2

実際にdesktop-0からTracerouteを実行してみると、上記結果と一致していました。

desktop-0:~$ traceroute 10.2.2.100
traceroute to 10.2.2.100 (10.2.2.100), 30 hops max, 46 byte packets
 1  10.1.1.1 (10.1.1.1)  2.601 ms  3.580 ms  2.445 ms
 2  10.5.5.2 (10.5.5.2)  3.582 ms  4.952 ms  4.937 ms
 3  10.2.2.100 (10.2.2.100)  3.475 ms  3.613 ms  4.632 ms

※IOS-XEベースの仮想プラットフォームCSR1000vで確認した時は、なぜか一致しませんでした。。

4. Include-portsアルゴリズムの動作

4-1. CEF設定内容

設定項目
ロードバランシング方式 宛先単位
アルゴリズム Include-ports

以下設定でアルゴリズムをInclude-portsに変更し、送信元と宛先ポート番号をハッシュ計算に含めるようにします。ロードバランシング方式はインターフェース毎に設定しますが、アルゴリズムはグローバル設定となります。

ip cef load-sharing algorithm include-ports source destination

show cef stateコマンドの※部分を見ると、設定が反映されています。

iosv-0#sh cef state
CEF Status:
 RP instance
 common CEF enabled
IPv4 CEF Status:
 CEF enabled/running
 dCEF disabled/not running
 CEF switching enabled/running
 include-ports source destination per-destination load sharing algorithm, id C9C9DAD7 ※
IPv6 CEF Status:
 CEF disabled/not running
 dCEF disabled/not running
 universal per-destination load sharing algorithm, id C9C9DAD7

4-2. ロードバランシング例

以下パケットを例に、どのパスが採用されるか確認してみます。

設定項目
送信元アドレス 10.1.1.100
宛先アドレス 10.2.2.100
プロトコル UDP
送信元ポート 49188
宛先ポート 33435から1ずつインクリメント

show ip cef exact-route <送信元アドレス> src-port <送信元ポート> <宛先アドレス> dest-port <宛先ポート>コマンドで、どのパスが採用されるか確認可能です。

LinuxのTracerouteはデフォルトでUDPが使われます。各ホップで3回実行する中で、宛先ポート番号が1つずつインクリメントされる動作のため、2ホップ目にあたる33438,33439,33440で確認しました。今回のパターンでは、10.5.5.210.4.4.210.3.3.2の3つに分散されました。

iosv-0#show ip cef exact-route 10.1.1.100 src-port 49188 10.2.2.100 dest-port 33438
10.1.1.100 -> 10.2.2.100 =>IP adj out of GigabitEthernet0/3, addr 10.5.5.2
iosv-0#show ip cef exact-route 10.1.1.100 src-port 49188 10.2.2.100 dest-port 33439
10.1.1.100 -> 10.2.2.100 =>IP adj out of GigabitEthernet0/2, addr 10.4.4.2
iosv-0#show ip cef exact-route 10.1.1.100 src-port 49188 10.2.2.100 dest-port 33440
10.1.1.100 -> 10.2.2.100 =>IP adj out of GigabitEthernet0/1, addr 10.3.3.2

Traceroute結果は上記と一致しています。

desktop-0:~$ traceroute 10.2.2.100
traceroute to 10.2.2.100 (10.2.2.100), 30 hops max, 46 byte packets
 1  10.1.1.1 (10.1.1.1)  2.681 ms  3.021 ms  3.516 ms
 2  10.5.5.2 (10.5.5.2)  6.206 ms  10.4.4.2 (10.4.4.2)  6.241 ms  10.3.3.2 (10.3.3.2)  4.941 ms
 3  10.2.2.100 (10.2.2.100)  6.918 ms  8.867 ms  6.341 ms

TracerouteのプロトコルをICMPに変更すると、ポート番号情報が無いためパスは1種類だけになりました。WindowsもデフォルトでICMPを利用するため、同様の結果になると思います。

desktop-0:~$ traceroute -I 10.2.2.100
traceroute to 10.2.2.100 (10.2.2.100), 30 hops max, 46 byte packets
 1  10.1.1.1 (10.1.1.1)  5.041 ms  3.424 ms  4.228 ms
 2  10.4.4.2 (10.4.4.2)  4.637 ms  5.575 ms  5.683 ms
 3  10.2.2.100 (10.2.2.100)  11.712 ms  8.464 ms  9.388 ms

5. (参考) Cisco機器発通信の動作

注意が必要なのは、CEFが適用されるのはあくまでも受信してフォワーディングするパケットのみという点です。自身発の通信は、送信元、宛先が同じでもラウンドロビン方式でネクストホップがパケットごとに変わります。

実際に、iosv-0からdesktop-1宛てにTracerouteを2回実行してみると、1回目は10.3.3.210.4.4.210.5.5.2...の順番でネクストホップが変わり、4回試行×2ホップ=計8パケット送信(2と2/3周)した後、2回目は10.5.5.2から始まっています。

iosv-0#traceroute 10.2.2.100 probe 4
Type escape sequence to abort.
Tracing the route to 10.2.2.100
VRF info: (vrf in name/id, vrf out name/id)
  1 10.3.3.2 4 msec
    10.4.4.2 5 msec
    10.5.5.2 4 msec
    10.3.3.2 4 msec
  2 10.2.2.100 7 msec 7 msec 9 msec 8 msec
iosv-0#traceroute 10.2.2.100 probe 4
Type escape sequence to abort.
Tracing the route to 10.2.2.100
VRF info: (vrf in name/id, vrf out name/id)
  1 10.5.5.2 5 msec
    10.3.3.2 3 msec
    10.4.4.2 5 msec
    10.5.5.2 5 msec
  2 10.2.2.100 12 msec 12 msec 11 msec 10 msec

Discussion