Upgrade to Pro — share decks privately, control downloads, hide ads and more …

SONiCのNETCONFサーバ機能を試してみた

 SONiCのNETCONFサーバ機能を試してみた

SONiCのNETCONFサーバ機能を試してみた

NTTネットワークイノベーションセンタ
中野 寛二

SONiC Workshop Japan 2026
https://sonic.connpass.com/event/385386/

Avatar for SONiC Users Group Japan

SONiC Users Group Japan

June 19, 2026

More Decks by SONiC Users Group Japan

Other Decks in Technology

Transcript

  1. 1 © NTT, Inc. 2026 目次 1. 背景 2. 3.

    ビルドと動作確認 4. 修正の詳細 まとめ
  2. 3 © NTT, Inc. 2026 SONiC とは • SONiC は

    Microsoft 発のNetwork OS で、現在は Linux Foundation / SONiC Foundation が運営している。 • Debian ベースに swss / syncd 等の Docker マイクロサービス構成、CONFIG_DB を Redis で保持しており、SAIによりASICの抽象化を行う設計である。
  3. 4 © NTT, Inc. 2026 SONiCの課題 プレーン 分類 コミュニティSONiCの状況/課題 検討したアプローチ

    マネジメント 設定変更コマンド体系 コマンド数が少ない。 KLISH CLI拡張 (Management Framework) L2/L3設定コマンド体系が異なる 外部制御プロトコル 設定項目が限定的 YANG拡張 (NETCONF, gNMI) (Management Framework) REST, gNMIのみ。旧来から利用する NETCONFに対応不可。相互接続性に難あり。 NETCONF拡張 (Management Framework) コントロール ルーティングプロトコ ル 標準ではBGPのみ利用可。OSPF等のIGPサ ポート不可。 COPP関連の設定ファイル変更 ECMP経路処理 旧来の経路追加メッセージのみ利用可。 Nexthop Group (netlinkメッセージ)が利用 不可。 Fpmsyncd機能*拡張 *fpm形式のnetlinkメッセージの経路更新メッセージをRedis DBに同期す る機能 データ 伝送機能のサポート • Alibabaによる伝送機能のサポートの議論 しているが対応ハードウェアの入手性に難 あり。 • 市中製品による伝送機能の実装 (クローズド機 能) SAIのサポート • SAIサポートの対応状況がASIC毎に異なる。 • BroadcomはSAIフルスペックをサポート 不可 • SAIの多くのAPIに準拠していたIntel Tofinoが 開発中止。機能拡張には他チップ検討要 • Broadcomはコミュニティ版libsaiに意図的に 制限があるためメーカとの連携検討要 • 2022年からSONiCの取り組みをしていく中で検討してきた課題
  4. 5 © NTT, Inc. 2026 SONiCのNETCONFサーバ機能 • Orange社主導で2024年初頭からOSS化が進んでいる。getやedit-configなどのRPCに対応している。 • SONiCのビルドシステムにはNETCONFサーバー機能がマージされていないため、2026年6月時点で

    利用するにはPR(プルリクエスト)のパッチを手動で適用してビルドする必要がある。 • SONiCでは、OpenConfigとSONiC YANGの2つのYANGモデルを利用することができる。 RPC対応状況 RPC デザインドキュメント記載状況 <get> ◦ <get-config> ◦ <edit-config> ◦ <copy-config> ◦ <delete-config> × <lock> ◦ <unlock> ◦ <close-session> ◦ <kill-session> ◦ <commit> × <discard-changes> × <cancel-commit> × <validate> × <get-schema> ◦ <create-subscription> × SONiCのManagement framework https://github.com/aseaudi/SONiC/blob/6b5a7e3de3e1ec0cb8205fd6bae5812fa72ff2fc/doc/mgmt/Management%20Framework.md
  5. 7 © NTT, Inc. 2026 NETCONFサーバ組み込んでSONiCビルド • NETCONFサーバのPRを手動パッチ適用してビルドを行う。 • ビルド設定で、INCLUDE_NETCONF_SERVER=yをすることでNETCONFサーバコンテナの

    ビルドができる。 • ビルドしたイメージでSONiC起動後にconfig feature state enabledすることでNETCONFサー バが動作する。 $ git clone https://github.com/sonic-net/sonic-buildimage.git && cd sonic-buildimage $ curl -L .../pull/19492.patch -o /tmp/pr-19492.patch && git am /tmp/pr-19492.patch $ git submodule update --init --recursive $ echo 'INCLUDE_NETCONF_SERVER = y' >> rules/config $ make configure PLATFORM=vs && make SONIC_BUILD_JOBS=4 target/sonic-vs.img.gz $ sudo config feature state netconf-server enabled && sudo config save -y $ git clone https://github.com/sonic-net/sonic-buildimage.git && cd sonic-buildimage $ curl -L .../pull/19492.patch -o /tmp/pr-19492.patch && git am /tmp/pr-19492.patch $ git submodule update --init --recursive $ echo 'INCLUDE_NETCONF_SERVER = y' >> rules/config $ make configure PLATFORM=vs && make SONIC_BUILD_JOBS=4 target/sonic-vs.img.gz $ sudo config feature state netconf-server enabled && sudo config save -y
  6. 8 © NTT, Inc. 2026 get/edit-configの実装状況確認 • container 起動から get/edit-config動作確認において、12

    課題を確認した。 • <get> parser に 5 件、<edit-config> に 3 件、container / SSH / rpc-error に 3 件、capabilities 広告に 1 件 # エリア 課題概要 1 container 起動 NETCONF サーバ起動スクリプトの権限不足による起動エラー 2 SSH 接続 ホスト鍵が古い RSA-1024 のみで、現代の SSH クライアントから接続拒 否 3 <get> parser <filter> 要素の名前空間が無視され、prefix 付き要求で空応答を返す 4 <get> parser subtree フィルタが浅い階層しか処理できず、深い GET が空応答になる 5 <get> parser list のキー条件 (content match) が認識されず、絞り込みが効かない 6 <get> parser 値取得用の空要素 (selection node) が誤解釈され、目的の leaf 値が返らな い 7 <get> parser 複数 YANG モジュールにまたがる応答で内側の名前空間宣言が抜け、解析 破綻 8 <edit-config> OC OpenConfig 経路の edit-config dispatcher が未実装で常にエラー応答 9 <edit-config> OC YANG list を JSON 配列形式で扱わず、translib が型エラーで拒否 10 <edit-config> SONiC SONiC YANG 経路の payload に余分な module 名 prefix が付き拒否される 11 rpc-error <rpc-error> 応答に必須の <error-tag> が欠落し、エラー詳細も塗りつぶさ れる 12 capabilities <hello> が未実装の :startup を広告(copy-config も startup datastore も無 し)— 実装と広告の乖離 2 2 SSH transport (main.go) × RSA-1024 のみ→拒否 12 12 Session + <hello> (handler.go) × :startup 過剰広告 handleRequest dispatch handler.go · get / get-config · get-schema · edit-config · lock / unlock / commit 4 4 5 5 6 6 ParseGetRequest (parser.go) × 手書き3階層→空応答 3 3 7 7 GetRequestHandler+ xmlns × ns 無視・内側 xmlns 抜け 8 8 9 9 10 10 ParseEditRequest OC / SONiC (parser.go) × OC dispatcher 無→reject translib (sonic-mgmt-common) Get / Set → CONFIG_DB(無修正) 失敗時 11 11 rpc-error 応答 × error-tag 欠落・塗潰し NETCONFサーバ 1 1 × 権限不足で起動エラー 起動: Dockerfile.j2 / supervisord
  7. 9 © NTT, Inc. 2026 各課題の修正 • 各課題に対して修正を実施した。 • parser.go

    完全再帰化・parseEditConfigOC・rpcerror.go・ed25519に対応した。 • 各モジュールに当てた修正を ✓ で示す(translibは無修正、数字は前ページ表の課題番号)。 2 2 SSH transport (main.go) × RSA-1024 のみ→拒否 12 12 Session + <hello> (handler.go) × :startup 過剰広告 handleRequest dispatch handler.go · get / get-config · get-schema · edit-config · lock / unlock / commit 4 4 5 5 6 6 ParseGetRequest (parser.go) × 手書き3階層→空応答 3 3 7 7 GetRequestHandler+ xmlns × ns 無視・内側 xmlns 抜け 8 8 9 9 10 10 ParseEditRequest OC / SONiC (parser.go) × OC dispatcher 無→reject translib (sonic-mgmt-common) Get / Set → CONFIG_DB(無修正) 失敗時 11 11 rpc-error 応答 × error-tag 欠落・塗潰し NETCONFサーバ 1 1 × 権限不足で起動エラー 起動: Dockerfile.j2 / supervisord 2 2 SSH transport (main.go) ✓ ed25519 を併設 12 12 Session + <hello> (handler.go) ✓ 実装済のみ広告 handleRequest dispatch handler.go · get / get-config · get-schema · edit-config · lock / unlock / commit 4 4 5 5 6 6 ParseGetRequest (parser.go) ✓ 完全再帰+ns/predicate 3 3 7 7 GetRequestHandler+ xmlns ✓ ns 解決・xmlns 都度宣言 8 8 9 9 10 10 ParseEditRequest OC / SONiC (parser.go) ✓ parseEditConfigOC + unwrap translib (sonic-mgmt-common) Get / Set → CONFIG_DB(無修正) 失敗時 11 11 rpc-error 応答 ✓ RFC error-tag 分類 (rpcerror.go) NETCONFサーバ 1 1 ✓ 権限の追加 起動: Dockerfile.j2 / supervisord 修正前 修正後
  8. 12 © NTT, Inc. 2026 課題 1 container 起動 •

    起動スクリプトの権限不足による NETCONF サーバ起動失敗 • Dockerfile.j2 の COPY が source mode を保つため、start.shがexec bitなしsupervisord FATAL となる。 • Dockerfile.j2 に RUN chmod 0755 を追加することで解消。 実行コマンド (BEFORE / AFTER 共通) $ docker exec netconf-server supervisorctl status $ docker exec netconf-server supervisorctl status BEFORE reply (改善前イメージ) start FATAL command at '/usr/bin/start.sh' is not executable start FATAL command at '/usr/bin/start.sh' is not executable AFTER reply (修正後イメージ) start RUNNING netconf_server RUNNING pid 42, uptime 0:00:04 start RUNNING netconf_server RUNNING pid 42, uptime 0:00:04
  9. 13 © NTT, Inc. 2026 課題 2 SSH 接続 •

    古い RSA-1024 鍵による現代 SSH クライアントの接続拒否。 • 既存 RSA を残しつつ ed25519 を 2 本目の host key として追加 load する。 • 既存 known_hosts を壊さず modern client が ed25519 を自動選択できるようになる。 ncclient 接続 (BEFORE / AFTER 共通) mgr = manager.connect(host, port=830, username="admin", hostkey_verify=False) mgr = manager.connect(host, port=830, username="admin", hostkey_verify=False) BEFORE reply (改善前イメージ) paramiko: server key ssh-rsa Exception (client): Incompatible ssh peer (no acceptable host key) paramiko: server key ssh-rsa Exception (client): Incompatible ssh peer (no acceptable host key) AFTER reply (修正後イメージ) paramiko: server key ssh-rsa, ssh-ed25519 HostKey: ssh-ed25519 Auth (password) successful! paramiko: server key ssh-rsa, ssh-ed25519 HostKey: ssh-ed25519 Auth (password) successful!
  10. 14 © NTT, Inc. 2026 課題 3 <get> parser •

    <filter> の名前空間無視による prefix 付き要求の空応答になる。 • NETCONF base namespace のクライアント prefix (nc:, ncbase: 等) は自由なので prefix 非依存にする 送信 RPC (BEFORE / AFTER 共通) mgr.dispatch("<get><nc:filter xmlns:nc='urn:ietf:params:xml:ns:netconf:base:1.0'> <interfaces><interface><name>Ethernet0</name> </interface></interfaces></nc:filter></get>") mgr.dispatch("<get><nc:filter xmlns:nc='urn:ietf:params:xml:ns:netconf:base:1.0'> <interfaces><interface><name>Ethernet0</name> </interface></interfaces></nc:filter></get>") BEFORE reply (改善前イメージ) <rpc-reply> <data></data> </rpc-reply> (181 bytes / filter hit せず) <rpc-reply> <data></data> </rpc-reply> (181 bytes / filter hit せず) AFTER reply (修正後イメージ) <rpc-reply> <data><interfaces> <interface>...</interface> </data></rpc-reply> <rpc-reply> <data><interfaces> <interface>...</interface> </data></rpc-reply>
  11. 15 © NTT, Inc. 2026 課題 4 <get> parser •

    ParseGetRequest が手書きで 3 階層分しか降りないため、深い filter は常に空応答を返す。 • 完全再帰版に置換し、任意深さ + content match + selection の全組合せに対応する。 送信 RPC (BEFORE / AFTER 共通) — 同一 subtree を depth 1〜6 で GET mgr.dispatch("<get><filter> ... </filter></get>") depth 1=top container, 2=list, 3=subinterfaces, 4=subinterface, 6=ipv4/addresses mgr.dispatch("<get><filter> ... </filter></get>") depth 1=top container, 2=list, 3=subinterfaces, 4=subinterface, 6=ipv4/addresses BEFORE reply (改善前イメージ) depth 1 EMPTY 181 depth 2 EMPTY 181 depth 4 EMPTY 181 depth 6 EMPTY 181 depth 1 EMPTY 181 depth 2 EMPTY 181 depth 4 EMPTY 181 depth 6 EMPTY 181 AFTER reply (修正後イメージ) depth 1 OK 58695 depth 2 OK 2100 depth 6 OK 458 [ip=10.10.10.1] OK 441 depth 1 OK 58695 depth 2 OK 2100 depth 6 OK 458 [ip=10.10.10.1] OK 441
  12. 16 © NTT, Inc. 2026 課題 5 <get> parser •

    list キー条件 (content match) 未対応で絞り込みが効かない • BEFORE は単なる「子要素」として扱うため、list の全 entry が返るか path 不一致で空応答。 • [name=Ethernet0] 形式に変換するように修正。 送信 RPC (BEFORE / AFTER 共通) mgr.dispatch("<get><filter><interfaces> <interface><name>Ethernet0</name></interface> </interfaces></filter></get>") mgr.dispatch("<get><filter><interfaces> <interface><name>Ethernet0</name></interface> </interfaces></filter></get>") BEFORE reply (改善前イメージ) predicate 化されず → <data> に全 interface または <data/> 空応答 predicate 化されず → <data> に全 interface または <data/> 空応答 AFTER reply (修正後イメージ) [name=Ethernet0] 化 → <data><interface> <name>Ethernet0</name>... (Ethernet0 のみ返却) [name=Ethernet0] 化 → <data><interface> <name>Ethernet0</name>... (Ethernet0 のみ返却)
  13. 17 © NTT, Inc. 2026 課題 6 <get> parser •

    空要素 (selection node) 誤解釈による leaf 値の欠落する • BEFORE は子要素 として再帰しようとして失敗する。 • 「子要素なし + text 値なし」を判定し、path 追加だけで再帰を打ち切る。 送信 RPC (BEFORE / AFTER 共通) mgr.dispatch("<get><filter><interfaces> <interface><name/></interface> </interfaces></filter></get>") mgr.dispatch("<get><filter><interfaces> <interface><name/></interface> </interfaces></filter></get>") BEFORE reply (改善前イメージ) container 扱いで再帰 → <data></data> (leaf 値が取れない) container 扱いで再帰 → <data></data> (leaf 値が取れない) AFTER reply (修正後イメージ) selection node と判定 → <data><interface> <name>Ethernet0</name> (leaf 値のみ返却) selection node と判定 → <data><interface> <name>Ethernet0</name> (leaf 値のみ返却)
  14. 18 © NTT, Inc. 2026 課題 7 <get> parser •

    内側モジュールの名前空間宣言欠落による応答解析ができない • OpenConfig はモジュールをまたがってネストするが (例: interface 配下に openconfig-if-ip:ipv4)、 • BEFORE 実装は response 構築で outer 1 ヶ所しか xmlns を宣言しない。 • YangModules 逆引きし、 xmlns:prefix=uri を都度宣言する。 送信 RPC (BEFORE / AFTER 共通) mgr.dispatch("<get><filter><interfaces xmlns='http://openconfig.net/yang/interfaces'> ...<ipv4>...</filter></get>") mgr.dispatch("<get><filter><interfaces xmlns='http://openconfig.net/yang/interfaces'> ...<ipv4>...</filter></get>") BEFORE reply (改善前イメージ) <openconfig-if-ip:ipv4> (xmlns 宣言なし) → client decode 破綻 undefined namespace <openconfig-if-ip:ipv4> (xmlns 宣言なし) → client decode 破綻 undefined namespace AFTER reply (修正後イメージ) <openconfig-if-ip:ipv4 xmlns:openconfig-if-ip= "...interfaces/ip"> → client decode OK <openconfig-if-ip:ipv4 xmlns:openconfig-if-ip= "...interfaces/ip"> → client decode OK
  15. 19 © NTT, Inc. 2026 課題 8 <edit-config> OC •

    OpenConfig 用 edit-config 経路の未実装によるエラー応答になる • OpenConfig モジュールが来ると module-prefix 付きで全部 wrap して translib に渡し reject される。 • OC/SONiC YANGを判別し、OC は新設経路で処理するように追加実装。 送信 RPC (BEFORE / AFTER 共通) mgr.edit_config(target='running', config="<interfaces xmlns='http://openconfig.net/yang/interfaces'>... 10.10.10.1/24 on Ethernet0 ...</interfaces>") mgr.edit_config(target='running', config="<interfaces xmlns='http://openconfig.net/yang/interfaces'>... 10.10.10.1/24 on Ethernet0 ...</interfaces>") BEFORE reply (改善前イメージ) <rpc-error> JSON contains unexpected field openconfig-interfaces: interfaces <rpc-error> JSON contains unexpected field openconfig-interfaces: interfaces AFTER reply (修正後イメージ) <ok/> (173 bytes) $ redis-cli -n 4 KEYS: INTERFACE|Ethernet0| 10.10.10.1/24 <ok/> (173 bytes) $ redis-cli -n 4 KEYS: INTERFACE|Ethernet0| 10.10.10.1/24
  16. 20 © NTT, Inc. 2026 課題 9 <edit-config> OC •

    YANG list の JSON 配列化漏れによる translib 型エラー • RFC 7951では YANG list は単一 entry でも JSON array [{}] で表現する必要があるため配列化するよう に修正。 送信 RPC (BEFORE / AFTER 共通) — interface list が単一 entry mgr.edit_config(config="<interfaces ...> <interface><name>Ethernet0</name>... </interface></interfaces>") mgr.edit_config(config="<interfaces ...> <interface><name>Ethernet0</name>... </interface></interfaces>") BEFORE reply (改善前イメージ) payload: interface:{...} → <rpc-error> got type map, expect [] payload: interface:{...} → <rpc-error> got type map, expect [] AFTER reply (修正後イメージ) payload: interface:[{...}] → <ok/> translib 受理 payload: interface:[{...}] → <ok/> translib 受理
  17. 21 © NTT, Inc. 2026 課題 10 <edit-config> SONiC YANG

    • SONiC YANG payload の余分な module prefix による拒否される。 • 余分なprefix を削除し {innerContainer} のみに変更する。 送信 RPC (BEFORE / AFTER 共通) mgr.edit_config(config="<sonic-port xmlns='http://github.com/sonic-net/sonic-port'> <PORT><PORT_LIST><name>Ethernet4</name> <mtu>9050</mtu></PORT_LIST></PORT></sonic-port>") mgr.edit_config(config="<sonic-port xmlns='http://github.com/sonic-net/sonic-port'> <PORT><PORT_LIST><name>Ethernet4</name> <mtu>9050</mtu></PORT_LIST></PORT></sonic-port>") BEFORE reply (改善前イメージ) <rpc-error> JSON contains unexpected field sonic-port:sonic-port <rpc-error> JSON contains unexpected field sonic-port:sonic-port AFTER reply (修正後イメージ) <ok/> (173 bytes) $ redis-cli -n 4 HGETALL PORT|Ethernet4: mtu 9050 <ok/> (173 bytes) $ redis-cli -n 4 HGETALL PORT|Ethernet4: mtu 9050
  18. 22 © NTT, Inc. 2026 課題 11 rpc-error • <error-tag>

    欠落による rpc-error の失敗種別判別不能になる。 • rpcerror.go を新設し RFC 標準 error-tag に分類する。 送信 RPC (BEFORE / AFTER 共通) — 不正 IP 999.999.999.999 mgr.edit_config(config="<interfaces ...><address> <ip>999.999.999.999</ip>...</address>...") mgr.edit_config(config="<interfaces ...><address> <ip>999.999.999.999</ip>...</address>...") BEFORE reply (改善前イメージ) <rpc-error> <error-type>rpc <error-message>Failed to handle request (error-tag 欠落) <rpc-error> <error-type>rpc <error-message>Failed to handle request (error-tag 欠落) AFTER reply (修正後イメージ) <rpc-error> <error-type>application <error-tag>invalid-value <error-message>"999..." does not match pattern <rpc-error> <error-type>application <error-tag>invalid-value <error-message>"999..." does not match pattern
  19. 23 © NTT, Inc. 2026 課題 12 capabilities • 未実装

    capability (:startup) の誤広告による実装との乖離した状態で広告していた。 • 実装済 capability だけを広告するよう是正。 送信 RPC (BEFORE / AFTER 共通) — <hello> の capability を確認 mgr = manager.connect(host, port=830, username='admin', hostkey_verify=False) print(mgr.server_capabilities) # <hello> が広告する base capability を列挙 # 併せて <lock><target><startup/></target></lock> を送り startup 操作の可否も確認 mgr = manager.connect(host, port=830, username='admin', hostkey_verify=False) print(mgr.server_capabilities) # <hello> が広告する base capability を列挙 # 併せて <lock><target><startup/></target></lock> を送り startup 操作の可否も確認 BEFORE reply (改善前イメージ) :writable-running:1.0 :xpath:1.0 :startup:1.0 ←未実装 copy-config 無し lock startup→error :writable-running:1.0 :xpath:1.0 :startup:1.0 ←未実装 copy-config 無し lock startup→error AFTER reply (修正後イメージ) :writable-running:1.0 :xpath:1.0 (:startup を削除) 差分は :startup のみ 86 module 不変 :writable-running:1.0 :xpath:1.0 (:startup を削除) 差分は :startup のみ 86 module 不変
  20. 24 © NTT, Inc. 2026 まとめ • SONiCのNETCNOFサーバ機能の動作確認を行った • 2026年6月時点でSONiCのビルドシステムにNETCONFサーバー機能がマージ

    されていないため、PRパッチを手動で適用してビルドした。 • 動作検証の結果、Openconfigなど動作しない機能が判明したため修正の実施 を行った。
  21. 27 © NTT, Inc. 2026 RPC 動作確認 • RFC 6241

    / 6022 / 5277 が定義する標準 RPC を、HLD(ドキュメント)の記載と実装で対比した。 • get・get-config・edit-config・lock・unlock・get-schema は動作。 • mandatory の copy-config / delete-config は未実装、candidate 系も commit 以外は非対応。 RPC RFC ドキュメント 動作確認結果 <get> 6241 §7.7 ◦ ◦ <get-config> 6241 §7.1 ◦ ◦ <edit-config> 6241 §7.2 ◦ ◦ <copy-config> 6241 §7.3 ◦ × <delete-config> 6241 §7.4 × × <lock> 6241 §7.5 ◦ ◦ <unlock> 6241 §7.6 ◦ ◦ <close-session> 6241 §7.8 ◦ ◦ <kill-session> 6241 §7.9 ◦ △ <commit> 6241 §8.4 × ◦ <discard-changes> 6241 §8.3.4.2 × × <cancel-commit> 6241 §8.4.4.2 × × <validate> 6241 §8.6.4 × × <get-schema> 6022 §3.1 ◦ ◦ <create-subscription> 5277 × × (◦=対応 / ×=非対応 / △=スタブ)