Topics で読み物として読む
この HLD は実装詳細を含みます。機能の概念・設定・運用を読み物として読みたい場合は Topics 09 章: Telemetry / SNMP / ログ を参照。
裏取りステータス: Code-verified
sonic-swss/orchagent/portsorch.h L30 (PORT_RATE_COUNTER_FLEX_COUNTER_GROUP) と intfsorch.h L20 (RIF_RATE_COUNTER_FLEX_COUNTER_GROUP)、Lua プラグイン port_rates.lua / rif_rates.lua / trap_rates.lua / tunnel_rates.lua(Makefile.am L20-32)、flexcounterorch.cpp L73/L83 で PORT_RATES / RIF_RATES の counterpoll キー登録を確認。sonic-utilities/config/main.py L9586 smoothing_interval CLI が RATES:PORT / RATES:RIF / RATES:TRAP を COUNTERS_DB に書き込み、alpha = 2/(N+1) で EMA 係数を計算 (verified at: 2026-05-09)。
バイト/パケットレートとポート使用率(RATES テーブル + EMA)¶
概要¶
portstat / intfstat が表示する RX_BPS / RX_PPS / RX_UTIL 等のレート列は、長らく CLI 側でカウンタの差分を計算する 方式で実装されていた。問題は次の通り1:
- ユーザが
sonic-clear countersを打つとカウンタの基準点が動き、レート計算がガタつく。 - 「ユーザ毎に独立したカウンタ」アプローチと組み合わせるとレートの定義が揺れる。
- 計算間隔がユーザ操作に依存するため、ある瞬間のレートが固定的でない。
本機能は Flex Counter インフラの上にレート計算用のグループ (PORT_RATES, RIF_RATES) を新設 し、Lua プラグインが固定インターバルで生レートを算出 → 指数移動平均 (EMA) で平滑化したうえで COUNTERS_DB の RATES テーブル に保存する設計である。portstat / intfstat はそこを読むだけ。sonic-clear counters を打っても影響を受けない1。
動作仕様¶
全体経路¶
flowchart LR
SAI["SAI port/RIF stats"] --> FC1["Flex Counter\n(既存 port/rif counters, 1s)"]
FC1 --> CDB1[(COUNTERS_DB\nCOUNTERS:vid)]
CDB1 -->|新 FC group| FC2["Flex Counter\n(PORT_RATES / RIF_RATES)"]
FC2 -->|Lua plugin| CALC["計算\n(diff/delta + EMA)"]
SP[("CONFIG_DB\nPORT speed / RIF speed")] --> CALC
SCFG[(CONFIG_DB\nRATES.PORT_ALPHA, RIF_ALPHA)] --> CALC
CALC --> CDB2[(COUNTERS_DB\nRATES:vid)]
CDB2 --> CLI["portstat / intfstat"]
要点1:
- 既存の port / RIF 用 Flex Counter は元の SAI カウンタを
COUNTERS_DB:COUNTERS:vidに書き続ける。 - 新規
PORT_RATES/RIF_RATESグループは独自インターバル(既定 1s、設定可)で動き、対応 Lua プラグインが計算を行う。 - 計算は
RATES:vidというキーに保存される。COUNTERS:vidと同じ vid をキーに使うが、テーブル名で完全分離。 - Lua プラグインは前回値 (
*_last) もRATES:vid内に持ち、自分で更新する。
SAI カウンタの選択¶
| 計算 | port 用 SAI カウンタ | RIF 用 SAI カウンタ |
|---|---|---|
| octets | SAI_PORT_STAT_IF_IN/OUT_OCTETS |
SAI_ROUTER_INTERFACE_STAT_IN/OUT_OCTETS |
| packets | SAI_PORT_STAT_IF_IN/OUT_UCAST_PKTS + SAI_PORT_STAT_IF_IN/OUT_NON_UCAST_PKTS |
SAI_ROUTER_INTERFACE_STAT_IN/OUT_PACKETS |
port の PPS は UCAST と NON_UCAST の合算 を使う点が独特1。RIF はもともと IN/OUT_PACKETS が両方を含むためそのまま。
計算式(生レート)¶
[RX|TX]_BPS = (octets - octets_last) / delta
[RX|TX]_PPS = (packets - packets_last) / delta # port は UCAST + NON_UCAST の合算
[RX|TX]_UTIL = [RX|TX]_BPS / [PORT|RIF]_RATE # PORT_RATE はリンク速度
delta は 対応する FC グループのインターバル。port の場合は PORT_RATES の POLL_INTERVAL、RIF の場合は RIF_RATES の POLL_INTERVAL1。
EMA による平滑化¶
瞬間値はマイクロバーストで揺れやすいため、EMA を適用する1。
N = [PORT|RIF]_SMOOTH_INTERVAL (CLI で設定可)
ALPHA = 2 / (N + 1)
EMA = ALPHA * VALUE + (1 - ALPHA) * EMA_last
ALPHA は CONFIG_DB に 事前計算した値 を入れる設計。Lua プラグインから毎回計算しなくて済む。
SMOOTH_INTERVAL を変えると EMA の応答性が変わる: N=1 で実質 EMA 無効、N を大きくすると遅延と引き換えに滑らかになる。
📋 検証エビデンス: sonic-net/SONiC/doc/rates-and-utilization/Rates_and_utilization_HLD.md#L137-L148 (sha: 49bab5b5ff0e924f1ea52b3d9db0dfa4191a7c06)
出典:
sonic-net/SONiC/doc/rates-and-utilization/Rates_and_utilization_HLD.md#L137-L148 (sha: 49bab5b5ff0e924f1ea52b3d9db0dfa4191a7c06)
抜粋:
ALPHA (precalculated):
N = [PORT|RIF]_SMOOTH_INTERVAL
ALPHA = 2/(N+1)
EMA = ALPHA * VALUE + (1 - ALPHA) * EMA_last
判断根拠: EMA の係数決定式と「事前計算 ALPHA を CONFIG_DB に置く」設計の根拠。
COUNTERS_DB スキーマ¶
RATES:port_vid / RATES:rif_vid に下記を保持1:
RATES:<port_vid>
# 前回値(Lua plugin が diff 計算に使う)
SAI_PORT_STAT_IF_IN_UCAST_PKTS_last
SAI_PORT_STAT_IF_IN_NON_UCAST_PKTS_last
SAI_PORT_STAT_IF_OUT_UCAST_PKTS_last
SAI_PORT_STAT_IF_OUT_NON_UCAST_PKTS_last
SAI_PORT_STAT_IF_IN_OCTETS_last
SAI_PORT_STAT_IF_OUT_OCTETS_last
# 計算結果(CLI が参照)
RX_BPS, TX_BPS, RX_PPS, TX_PPS, RX_UTIL, TX_UTIL
RATES:<rif_vid>
SAI_ROUTER_INTERFACE_STAT_IN_OCTETS_last
SAI_ROUTER_INTERFACE_STAT_IN_PACKETS_last
SAI_ROUTER_INTERFACE_STAT_OUT_OCTETS_last
SAI_ROUTER_INTERFACE_STAT_OUT_PACKETS_last
RX_BPS, TX_BPS, RX_PPS, TX_PPS, RX_UTIL, TX_UTIL
CONFIG_DB 側は次のキーで設定が入る1:
Flex Counter グループの動的登録¶
ポートと RIF はそれぞれ portsorch / intfsorch がライフサイクルを管理する。RIF 側は addRifToFlexCounter() / removeRifFromFlexCounter() メソッドで動的に登録/解除する1。新しい RIF が増えたタイミングで自動で RIF_RATES の対象になり、削除時に外れる。
sequenceDiagram
participant ORCH as portsorch / intfsorch
participant FC as Flex Counter (PORT_RATES/RIF_RATES)
participant LUA as Lua plugin
participant CDB as COUNTERS_DB
Note over ORCH,FC: 起動 / RIF 追加
ORCH->>FC: register vid
loop interval 毎
FC->>CDB: read COUNTERS:<vid>
FC->>LUA: invoke (vid, current, last)
LUA->>CDB: read RATES:<vid>.*_last, port speed
LUA->>LUA: diff / delta, EMA
LUA->>CDB: write RATES:<vid> (rate values + new *_last)
end
CLI への影響¶
ユーザ向けの show 出力は 既存と同じ列 を返す。CLI は内部で COUNTERS:vid ではなく RATES:vid を参照するように切り替わるだけ1。
-p / --period オプションを使うと「指定期間で計算したレート」を見せる必要があるが、その場合は CLI 側でスナップショット差分を取る方式 に切り替えるとされている1。常用は RATES テーブル、-p 指定時のみスナップショット計算という二系統。
counterpoll 拡張¶
counterpoll [port_rates|rif_rates] interval <seconds>
counterpoll [port_rates|rif_rates] [enable|disable]
ガード条件1:
- 対応する counter polling (port / rif counters) が disable の状態で
port_rates/rif_ratesを enable しようとするとエラー。 port_ratesの interval を counter polling の interval より短く 設定しようとすると 警告 を出し、counter polling と同じ interval にそろえる。
EMA の窓だけは別 CLI で設定する:
設定¶
関連する CONFIG_DB¶
| Table | Key | フィールド | 説明 |
|---|---|---|---|
RATES |
(単一エントリ) | PORT_SMOOTH_INTERVAL |
EMA の N(port 用) |
RIF_SMOOTH_INTERVAL |
EMA の N(RIF 用) | ||
PORT_ALPHA |
事前計算: 2/(N+1) |
||
RIF_ALPHA |
事前計算 | ||
FLEX_COUNTER_TABLE |
PORT_RATES |
FLEX_COUNTER_STATUS, POLL_INTERVAL |
port レート計算 FC group |
FLEX_COUNTER_TABLE |
RIF_RATES |
同上 | RIF レート計算 FC group |
関連する COUNTERS_DB¶
RATES:<vid> に上述の前回値 + レート結果。CLI / telemetry は基本的にこれを読む。
関連する CLI¶
| Command | 用途 |
|---|---|
counterpoll port_rates {enable\|disable} |
PORT_RATES グループ ON/OFF |
counterpoll rif_rates {enable\|disable} |
RIF_RATES 同 |
counterpoll port_rates interval <sec> |
port レート計算間隔 |
counterpoll rif_rates interval <sec> |
RIF 同 |
config rate smoothing_interval {all\|port\|rif} <N> |
EMA の窓を変更 |
portstat / intfstat |
既存の表示 CLI(バックエンドが RATES に切替) |
設定例¶
counterpoll port_rates enable
counterpoll port_rates interval 1
config rate smoothing_interval port 5 # EMA N=5
干渉する機能¶
sonic-clear counters: 旧来は CLI 側で差分計算していたためカウンタクリアでレート初期化が起きていた。本機能ではRATESテーブル経由となり 影響を受けない。これは仕様上の意図。- counter polling との関係:
port_ratesの interval を counter polling より短くしても意味がない(生カウンタが更新されないため)。CLI が警告して合わせる仕様1。 - EMA の応答性: 瞬間ピークを見たいユースケースでは
smoothing_intervalを 1 にするのが直感的。スパイクを丸めたい運用では大きめの値を。 - port speed:
[RX|TX]_UTILは CONFIG_DB のPORT.speedを分母に使うため、speed設定が誤っていると UTIL が % で歪む。 -pオプション: 指定された期間で計算する場合は本機能の RATES テーブルではなく、CLI 内のスナップショット計算に切り替わる。意味的に別系統である点に注意。
トラブルシューティング¶
portstatで BPS / PPS が常に 0:RATES:<port_vid>が COUNTERS_DB に書かれているかredis-cli -n 2 keys 'RATES*'で確認。Lua プラグインが回っていない、または Flex Counter group が disable の可能性。- 値がガタつく:
smoothing_intervalを上げて EMA を効かせる。 RATESの値とCOUNTERSの差分が合わない: EMA で平滑化されているため、瞬時カウンタの素差分とは一致しない。これが意図。counter poll port_rates enableでエラー: 既存portcounter polling が disable の可能性。先にそちらを enable する。- 新しい RIF を作ったのに RATES に反映されない:
intfsorchのaddRifToFlexCounterが呼ばれていない可能性。syslogで SWSS 起動エラーを確認。
参考リンク¶
引用元¶
関連 Topics¶
参考リンク¶
本ページに関連する参照ドキュメント: