コンテンツにスキップ

NAT ゾーン設定 (nat_zone フィールド)

概要

nat_zoneINTERFACEVLAN_INTERFACEPORTCHANNEL_INTERFACELOOPBACK_INTERFACE テーブルに共通して存在するフィールドで、L3 インタフェースごとに NAT ゾーン ID (0〜3) を割り当てる1

NAT 変換はゾーンをまたぐパケットにのみ行われる。デフォルト値 0 は「内側 (inside)」インタフェースを意味し、値を 1 などに変えると「外側 (outside)」インタフェースとして扱われる。natmgrd が iptables mangle テーブルに MARK ルールを設定し、orchagent / IntfsOrch が SAI の SAI_ROUTER_INTERFACE_ATTR_NAT_ZONE_ID を設定する23

データフロー (自動生成)

flowchart LR
  CDB[("CONFIG_DB<br/>INTERFACE|&lt;port&gt;<br/>nat_zone=N")]
  NM["natmgrd<br/>(NatMgr)"]
  IA["orchagent<br/>(IntfsOrch)"]
  IPT["kernel<br/>iptables mangle"]
  SAI["SAI<br/>SAI_ROUTER_INTERFACE_ATTR_NAT_ZONE_ID"]
  CDB --> NM
  CDB --> IA
  NM --> IPT
  IA --> SAI

凡例

CONFIG_DB から SAI までの典型経路。natmgrd は iptables mangle MARK ルールを管理し、orchagent は SAI RIF 属性を設定する。

key 構造

INTERFACE|<port_name>
VLAN_INTERFACE|<vlan_name>
PORTCHANNEL_INTERFACE|<portchannel_name>
LOOPBACK_INTERFACE|<loopback_name>

nat_zone は各 L3 インタフェーステーブルのポート単位エントリ (key サイズ 1) に付与するフィールドであり、IP プレフィックス付きエントリ (key サイズ 2) では無視される。

主要フィールド

フィールド 既定値 説明
nat_zone uint8 (0..3) 0 インタフェースの NAT ゾーン ID。0 = inside、1 = outside (典型)

フィールド暗黙デフォルト (Phase A — コード由来)

YANG default 以外の実装 hardcode fallback。

フィールド YANG default コード hardcode fallback 源
nat_zone "0" m_nat_zone_id = 0 intfsorch.cpp:1361 (インタフェース削除時リセット)
iptables mark nat_zone_value + 1 natmgr.cpp:7512-7514 (0 mark 回避オフセット)

全フィールドで YANG default と実装 hardcode は一致。ただし以下の暗黙挙動・乖離がある。

iptables mark のオフセット (+1)

natmgrd は DB の nat_zone 値に +1 した値を iptables mangle の MARK 値として使用する (natmgr.cpp:7512-7514)。これは mark=0 が iptables のデフォルト動作と衝突するのを避けるため。

// natmgr.cpp:7499-7514
if (fvField(idx) == NAT_ZONE)
{
    nat_zone_value = stoi(fvValue(idx));  // DB 値を読む
    nat_zone_value++;                      // +1 して mark=0 を避ける
    nat_zone = to_string(nat_zone_value);
}
DB の nat_zone iptables mangle MARK
0 (inside / デフォルト) 1
1 (outside / 典型) 2
2 3
3 4

フィールド省略時は SAI 書き込みなし

nat_zone フィールドが CONFIG_DB に存在しない場合、IntfsOrchnat_zone 文字列変数は空のままとなり、SAI 呼び出し (setRouterIntfsNatZoneId) はスキップされる (intfsorch.cpp:974)。この場合 m_nat_zone_id は初期値 0 のままで SAI には降りない。

// intfsorch.cpp:974-986
if ((!nat_zone.empty()) and (port.m_nat_zone_id != nat_zone_id))
{
    port.m_nat_zone_id = nat_zone_id;
    if (gIsNatSupported)
        setRouterIntfsNatZoneId(port);
    else
        SWSS_LOG_NOTICE("Not set router interface %s NAT Zone Id to %u, as NAT is not supported", ...);
}

NAT 未サポートプラットフォームでの silent skip

gIsNatSupported == false のプラットフォーム(SAI_SWITCH_ATTR_AVAILABLE_SNAT_ENTRY == 0)では、nat_zone を設定しても setRouterIntfsNatZoneId() が呼ばれず SWSS_LOG_NOTICE のみ出力される。CONFIG_DB / iptables には書き込まれるが SAI へは降りない。

ローカル変数の初期値 vs DB 値

NatMgr::doNatZoneIntfTask 内でローカル変数 nat_zone_value = 1 として初期化されるが (natmgr.cpp:7388)、NAT_ZONE フィールドが DB に存在する場合は必ずその値で上書きされるため、この初期値が最終的な iptables mark に影響することはない。

制約

  • 有効範囲: 0〜3sonic-interface.yangrange "0..3")。範囲外は YANG バリデーションで拒否。
  • key サイズが 1 (ポート単位エントリ) の場合のみ処理。key サイズ 2 (IP プレフィックス付き) のエントリに付与しても natmgr は読み取らない (natmgr.cpp:7492)。
  • 対応インタフェース種別: Ethernet / Vlan / PortChannel / Loopback。それ以外のプレフィックスで始まるキーは natmgr がスキップする (natmgr.cpp:7412-7420)。

購読者

  • natmgrd (NatMgr::doNatZoneIntfTask): INTERFACEVLAN_INTERFACEPORTCHANNEL_INTERFACELOOPBACK_INTERFACE テーブルを購読し、nat_zone フィールドの変化を検知して kernel iptables mangle テーブルの MARK ルールを更新する。
  • orchagent / IntfsOrch (doIntfTask): 同テーブルを購読し、nat_zone フィールドの変化を検知して SAI RIF 属性 SAI_ROUTER_INTERFACE_ATTR_NAT_ZONE_ID を更新する。

関連 CONFIG_DB / YANG / CLI

  • 関連 CONFIG_DB: NAT_GLOBALNAT_POOLNAT_BINDINGS
  • 関連 CLI: config interface nat-zone <port> <zone_id>
  • 関連 YANG: sonic-interface

関連リファレンス

引用元

運用ヒント

典型設定

# Ethernet28 を outside (zone 1) に設定
config interface nat-zone Ethernet28 1

# Loopback0 を outside と同じゾーンに設定 (DC 構成)
config interface nat-zone Loopback0 1

確認コマンド

sonic-db-cli CONFIG_DB hget 'INTERFACE|Ethernet28' nat_zone
show nat config zones

よくある誤設定

  • nat_zone=1 を IP プレフィックス付きエントリ (INTERFACE|Ethernet28|10.0.0.1/24) に書いた場合、natmgr が無視してゾーン設定が有効にならない。ポート単位エントリ (INTERFACE|Ethernet28) に書くこと。
  • iptables mangle MARK は DB 値 + 1 であるため、nat_zone=0 のインタフェースのパケットには mark=1 が付く。この MARK 値を手動の iptables ルールで参照する際は注意が必要。

例外条件・特殊挙動

  • key サイズが 1 または 2 以外 → スキップ: natmgr は L3_INTERFACE_KEY_SIZE (2) または L3_INTERFACE_ZONE_SIZE (1) 以外のキーサイズを無効として erase する (natmgr.cpp:7400-7406)。
  • Loopback インタフェースは iptables ルールを設定しない: strncmp(keys[0].c_str(), LOOPBACK_PREFIX, ...) が真の場合、setMangleIptablesRules の呼び出しをスキップする (natmgr.cpp:7526-7528)。SAI への zone_id 設定は行われる。
  • 同一 nat_zone を受信 → スキップ: m_natZoneInterfaceInfo[port] == nat_zone の場合、SWSS_LOG_INFO("Received same nat_zone") としてエントリを消費してスキップ (natmgr.cpp:7571)。
  • nat_zone 変更時の Static/Dynamic NAT ルール再構築: ゾーン ID が変化した場合、natmgr は既存の Static NAT / NAPT / Dynamic NAT iptables ルールを削除してから新しいゾーン値で再構築する (natmgr.cpp:7534-7566)。
  • 非整数値の nat_zone → SWSS_LOG_ERROR + スキップ: stoi() が例外を投げる場合(文字列等)、ERROR ログを出してフィールドをスキップする (natmgr.cpp:7507-7509)。IntfsOrch も同様に stoul() 例外をキャッチして ERROR ログ + continue (intfsorch.cpp:756)。
  • NAT 未サポートプラットフォーム (gIsNatSupported == false) → SAI 呼び出しスキップ: intfsorch.cpp:978-986 で SWSS_LOG_NOTICE のみ出力し、setRouterIntfsNatZoneId() を呼ばない。

値依存挙動マトリクス

nat_zone iptables mark SAI zone_id 意味
0 (デフォルト / 省略時) 1 (DB 値 +1) 0 inside インタフェース (private realm)
1 2 1 outside インタフェース (public realm / 典型)
2 3 2 追加ゾーン (Twice NAT 等)
3 4 3 追加ゾーン (最大値)
フィールド省略 設定なし 設定なし SAI / iptables ともに変更なし

enum 等なし(uint8 数値のみ)。

CDB → 実コンテナ動作トレース

段階 1: Consumer 登録

  • natmgrd (NatMgr): CFG_INTF_TABLE_NAMECFG_VLAN_INTF_TABLE_NAMECFG_LAG_INTF_TABLE_NAMECFG_LOOPBACK_INTERFACE_TABLE_NAME を購読し doNatZoneIntfTask にディスパッチ。
  • orchagent (IntfsOrch): 同テーブルを SubscriberStateTable で購読し doIntfTask にディスパッチ。

段階 2: CFG → iptables / SAI

  • NatMgrnat_zone 値を読み、+1 した値を mangle MARK として kernel iptables に設定。
  • IntfsOrchnat_zone 値を uint32_t に変換し、setRouterIntfsNatZoneId(port) 経由で SAI RIF 属性 SAI_ROUTER_INTERFACE_ATTR_NAT_ZONE_ID を更新。

段階 3: タイミング + 副作用

  • ゾーン変更時は既存の Static / Dynamic NAT iptables ルールが一度削除され再構築される(数十ルールが対象の場合は数百 ms 要する可能性あり)。
  • iptables mangle mark の変更は即座に新規パケットから有効。既存 conntrack セッションは削除されない。

書き込み入り口 (Direction A)

nat_zone フィールドへの書き込みが発生するコード経路。

CLI

  • config interface nat-zone <interface_name> <zone_value>config/interface.pyCONFIG_DB.INTERFACE[interface_name]['nat_zone'] = zone_value を書き込む (sonic-utilities)。

minigraph / sonic-cfggen

  • minigraph.py に NAT ゾーン生成なし。

REST / gNMI

  • REST/gNMI 書き込み経路なし(YANG を通じた設定は可能だが現状 CLI 経由が主)。

db_migrator

  • db_migrator.pynat_zone マイグレーションなし。

ビルド時デフォルト (build-time default)

  • init_cfg.json.j2 にエントリなし。