🎄

Next Hop Group on SONiC

2022/12/05に公開

SONiC Advent Calendar 2022 Day 5

SONiC.202111 で追加された "Better route scalability with multiple next-hops" 機能を解説します。

Next Hop Group とは?

ホスト(Linux等)や Switch/Router によらず、パケットを送信・転送する場合は通常 FIB (Forwarding Information Base) や Routing Table と呼ばれるテーブルを参照し、パケットの宛先アドレスを Key として次に到達すべき宛先を Lookup します。

この "次に到達すべき宛先" が nexthop と呼ばれます。

FIB エントリ(route object)は Lookup 対象となるプレフィックス/長さ(Prefix/Len)と、nexthop のアドレス、送信インターフェース(デバイス)、等の情報を保持します。

この route object のフォーマットは実装により様々であり、例えば Linux Kernel の場合は v5.2 以前は nexthop 情報を route object の一部として保持していますが、v5.3 からは route object と nexthop object を分離しています。

ある宛先(Prefix/Len)の nexthop が複数ある場合は Multipath とも呼ばれます。
Multipath の場合、 route object と nexthop object を分離して保持しする事により、nexthop を複数の route で共有(参照)する事が可能となるため、以下メリットがあります。

  • メモリ消費量の削減
  • 追加・更新に必要な時間の短縮
  • Prefix/Len と nexthop で異なるアドレスファミリーを利用(e.g. IPv4, IPv6)

特に、エントリの更新コスト(Network OS -> ASIC の通信コスト)が大きい Switch/Router 等のハードウェア機器では、route と nexthop を分離し別々のテーブルで管理する事によりパフォーマンスやリソース(SRAM/TCAM)消費量の節約といった大きなメリットがあるため、多くの実装で分離して管理されています。

SONiC の Multipath 設定方法は2種類

SONiC における Multipath の設定方法は、 "CLIの有無" や "APPL_DB形式" が異なる2種類の方式あります。どちらの設定方法でも ASIC_DB は同じエントリとなります。

従来の方法(図・左)

設定方法:CLIから config コマンドを使用して設定可能です。

config route add prefix 10.99.0.0/24 nexthop 10.0.0.100
config route add prefix 10.99.0.0/24 nexthop 10.0.0.101

APPL_DB には、 ROUTE_TABLE エントリに nexthop に関する情報を "列挙" します。(CLIで設定すると自動的に生成されます)

Next Hop Group を用いる方法(図・右)

設定方法:CLIから設定はできず、直接 APPL_DB にエントリを追加する必要があります。

APPL_DB には、 NEXT_HOP_GROUP_TABLE エントリを作成し、ROUTE_TABLE からそのエントリ(ID)を参照します。具体的には、 ROUTE_TABLE エントリの nexthop_group に NEXT_HOP_GROUP_TABLE エントリの Key (e.g. nhg1)を ID として指定します。

Next Hop Group: APPL_DB エントリ追加方法

APPL_DB へのエントリ追加方法を3種類ご紹介します。

  • swssconfig コマンド(swssコンテナ)
  • sonic-db-cli コマンド(ホスト)
  • Python スクリプト(ホスト)

例として、NEXT_HOP_GROUP_TABLE エントリを追加しています。

パケット転送を試す際には、NEXT_HOP_GROUP_TABLE に加えて、ROUTE_TABLE に ROUTE_TABLE:10.99.0.0/24 {'nexthop_group': 'nhg1'} エントリを追加しましょう。
sonic-db-cli コマンドに例示しています)

swssconfig コマンド(swssコンテナ)

APPL_DB へのエントリの追加は swss コンテナ上で swssconfig <xxxx.json> コマンドを実行する事で可能です。(JSONファイルを docker cp で swss コンテナにコピーして実行)

admin@sonic:~$ cat nhg88.json
[
  {
    "NEXTHOP_GROUP_TABLE:nhg88": {
        "nexthop": "10.0.0.100,10.0.0.101", "ifname": "Ethernet0,Ethernet0"
    },
    "OP": "SET"
  }
]
admin@sonic:~$ docker cp nhg88.json swss:.
admin@sonic:~$ docker exec -it swss swssconfig nhg88.json

admin@sonic:~$ sonic-db-cli APPL_DB HGETALL NEXTHOP_GROUP_TABLE:nhg88
{'ifname': 'Ethernet0,Ethernet0', 'nexthop': '10.0.0.100,10.0.0.101'}

sonic-db-cli コマンド(ホスト)

sonic-db-cli コマンドを利用して追加する事も可能です。

admin@sonic:~$ sonic-db-cli APPL_DB HSET NEXTHOP_GROUP_TABLE:nhg99 \
'nexthop' '10.0.0.100,10.0.0.101' \
'ifname' 'Ethernet0,Ethernet0'
2

admin@sonic:~$ sonic-db-cli APPL_DB HGETALL NEXTHOP_GROUP_TABLE:nhg99
{'nexthop': '10.0.0.100,10.0.0.101', 'ifname': 'Ethernet0,Ethernet0'}

Route Object の追加方法も例示します。

admin@sonic:~/script$ sonic-db-cli APPL_DB HSET \
ROUTE_TABLE:10.99.0.0/24 'nexthop_group' 'nhg99'
1

admin@sonic:~/script$ sonic-db-cli APPL_DB HGETALL ROUTE_TABLE:10.99.0.0/24
{'nexthop_group': 'nhg99'}

Python スクリプト(ホスト)

admin@sonic:~$ cat nhg_push_appldb.py
#!/usr/bin/python3

from swsscommon import swsscommon

db = swsscommon.DBConnector("APPL_DB", 0, True)
table = swsscommon.ProducerStateTable(db, "NEXTHOP_GROUP_TABLE")

key = "nhg1"
fieldValues = {"nexthop": "10.0.0.100,10.0.0.101", "ifname": "Ethernet0,Ethernet0"}
fvs = swsscommon.FieldValuePairs(list(fieldValues.items()))
table.set(key, fvs)
admin@sonic:~$ ./nhg_push_appldb.py

admin@sonic:~$ sonic-db-cli APPL_DB HGETALL NEXTHOP_GROUP_TABLE:nhg1
{'nexthop': '10.0.0.100,10.0.0.101', 'ifname': 'Ethernet0,Ethernet0'}

Next Hop Group: ASIC_DB エントリ

APPL_DB に nexthop, route object のエントリを追加すると、swss/orchagent により ASIC_DB にエントリが追加されます。

例として、以下 APPL_DB エントリを追加した際の ASIC_DB エントリを図示します。

> APPL_DB entry
ROUTE_TABLE:10.99.0.0/24 {'nexthop_group': 'nhg1'}
NEXTHOP_GROUP_TABLE:nhg1 {'nexthop': '10.0.0.100,10.0.0.101', 'ifname': 'Ethernet0,Ethernet0'}

図のように、APPL_DB の NEXT_HOP_GROUP エントリは、ASIC_DB では NEXT_HOP, NEXT_HOP_GROUP_MEMBER, NEXT_HOP_GROUP の3種類のエントリになります。

Next Hop や Next Hop Group の object id (oid) は自動的に採番されます。
図中では簡略化のために1桁の数字で記載していますが、実際は後述の通り 0x2d0000000003a9 といった数値となります。

ASIC_DBのエントリは sonic-db-cli コマンドを利用して確認できます。

admin@sonic:~/script$ sonic-db-cli APPL_DB HGETALL NEXTHOP_GROUP_TABLE:nhg1
{'nexthop': '10.0.0.100,10.0.0.101', 'ifname': 'Ethernet0,Ethernet0'}

admin@sonic:~/script$ sonic-db-cli ASIC_DB keys \* | grep NEXT
ASIC_STATE:SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER:oid:0x2d0000000003a9
ASIC_STATE:SAI_OBJECT_TYPE_NEXT_HOP_GROUP:oid:0x50000000003a8
ASIC_STATE:SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER:oid:0x2d0000000003aa
ASIC_STATE:SAI_OBJECT_TYPE_NEXT_HOP:oid:0x40000000003a7
ASIC_STATE:SAI_OBJECT_TYPE_NEXT_HOP:oid:0x40000000003a5

admin@sonic:~/script$ sonic-db-cli ASIC_DB HGETALL ASIC_STATE:SAI_OBJECT_TYPE_NEXT_HOP_GROUP:oid:0x50000000003a8
{'SAI_NEXT_HOP_GROUP_ATTR_TYPE': 'SAI_NEXT_HOP_GROUP_TYPE_DYNAMIC_UNORDERED_ECMP'}

admin@sonic:~/script$ sonic-db-cli ASIC_DB HGETALL ASIC_STATE:SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER:oid:0x2d0000000003a9
{'SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID': 'oid:0x50000000003a8', 'SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_ID': 'oid:0x40000000003a5'}

admin@sonic:~/script$ sonic-db-cli ASIC_DB HGETALL ASIC_STATE:SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER:oid:0x2d0000000003aa
{'SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID': 'oid:0x50000000003a8', 'SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_ID': 'oid:0x40000000003a7'}

admin@sonic:~/script$ sonic-db-cli ASIC_DB HGETALL ASIC_STATE:SAI_OBJECT_TYPE_NEXT_HOP:oid:0x40000000003a5
{'SAI_NEXT_HOP_ATTR_TYPE': 'SAI_NEXT_HOP_TYPE_IP', 'SAI_NEXT_HOP_ATTR_IP': '10.0.0.100', 'SAI_NEXT_HOP_ATTR_ROUTER_INTERFACE_ID': 'oid:0x60000000003a1'}

admin@sonic:~/script$ sonic-db-cli ASIC_DB HGETALL ASIC_STATE:SAI_OBJECT_TYPE_NEXT_HOP:oid:0x40000000003a7
{'SAI_NEXT_HOP_ATTR_TYPE': 'SAI_NEXT_HOP_TYPE_IP', 'SAI_NEXT_HOP_ATTR_IP': '10.0.0.101', 'SAI_NEXT_HOP_ATTR_ROUTER_INTERFACE_ID': 'oid:0x60000000003a1'}

Next Hop Group の利用方法(まとめ)

SONiC の Next Hop Group について、APPL_DB へのエントリ追加方法を含めて解説しました。

今回はコマンドや Python Script により手動で追加しましたが、実際には BGPコンテナの FRR ( GoBGP) や Juniperが提供するcRPDのような商用ルーティングデーモンが APPL_DB にエントリを追加する事が想定されます。

コミュニティ版(オープンソース) SONiCでは fpmsyncd が Next Hop Group に未対応なためBGPコンテナ(FRR)で Next Hop Group を利用できませんが、将来的な拡張が期待されます。

Discussion