7-3 gNMI と Model-Driven Telemetry — 購読と送り出し
csr1000v 17.03.08a で NETCONF の購読と CLI の dial-out(gRPC・kvGPB)を、cat9000v-uadp 17.15.03 で gNMI の 4 つの RPC を撮り、誰が接続を張るかと資料の版の違いを並べます。
1. 前節の振り返りと本節の内容
前節 7-2 YANG モデル は、csr1000v 17.03.08a が名乗る YANG のモデルを get-schema で取り出し、同じ Loopback0 を IETF・OpenConfig・Cisco native の 3 系統で読み書きしました。
7-2 の末尾(§14)は、次のことを本節へ渡しています。hello に notification:1.0 と notification:1.1 の capability が並び、ietf-yang-push(2016-10-28・feature は on-change)と ietf-event-notifications(2016-10-27)のモジュールも名乗られていたこと。YANG の notification 文は 1 行の定義だけを置いたこと。Cisco の 17.3 のガイドの Model-Driven Telemetry の章が、telemetry を使うには YANG の知識が要ると書いていること。そして、YANG のモデルのデータを購読と送り出しで受け取る仕組みを次節で扱うことです。7-2 が引いた章の一文は以下のとおりです。
Knowledge of YANG is needed to understand and define the data that is required when using telemetry.
本節は、この予告を同じ順で次の場所で受けます。
| 7-2 §14 の予告 | 本節での受け方 | 場所 |
|---|---|---|
hello の notification:1.0 と notification:1.1 | RFC 5277 が定める notification:1.0・interleave:1.0 と、draft-ietf-netconf-rfc5277bis-01 が定める notification:1.1 に分けて読む。17.3 の章が本文で挙げる draft の版は notification:2.0 を名乗るよう書いていて、本機の hello に 2.0 は無い | §4.1・§11.3 |
ietf-yang-push(2016-10-28・on-change) | 機器から本文を取り出し、reference 文の版(draft-ietf-netconf-yang-push-04)、注釈の中に置かれた yang-version 1.1;、push-update と push-change-update の notification 文を読む | §4.2 |
ietf-event-notifications(2016-10-27) | 本文の reference 文(draft-ietf-netconf-rfc5277bis-01)と rpc establish-subscription。NETCONF の動的購読はこの RPC で作る | §4.2・§5 |
YANG の notification 文 | RFC 6020(YANG 1.0)と RFC 7950(YANG 1.1)の定義。本機の push-update の notification 文と、実際に届いた通知の要素名を並べる | §2.4・§4.2・§5.2 |
| MDT 章の YANG の知識の一文 | 購読先は 7-2 で読んだパス(ietf-interfaces の設定と状態・Cisco native の Loopback・OpenConfig の interfaces)で指す。章の例(memory・CDP)と Cisco の状態のモデル(interfaces-oper)は「章の例・対照」と断って使う | §5〜§9 |
| 購読と送り出しで受け取る仕組み | dial-in(NETCONF の動的購読・gNMI の Subscribe)と dial-out(CLI で設定した購読・gRPC) | §2・§5〜§9 |
7-2 §14 は、この仕組みを「要求への応答ではなく購読と送り出しで受け取る」と書きました。この言い方は、gNMI が持つ要求と応答の RPC を外していて、正確ではありませんでした。Cisco の 17.3 のガイドの gNMI の章は、gNMI が Capabilities・Get・Set・Subscribe の 4 つの RPC を持つと書いています。
This feature describes the model-driven configuration and retrieval of operational data using the gRPC Network Management Interface (gNMI) Capabilities, Get, Set and Subscribe remote procedure calls (RPCs). gNMI version 0.4.0 is supported.
同じ文は gNMI の版を 0.4.0 と書いています。C9K(17.15.03)に当てる 17.15 の gNMI 章も 0.4.0 と書いていて、本ラボの C9K が名乗った版はこれと違いました(§9.2)。
gNMI (gRPC Network Management Interface) の Capabilities・Get・Set は、要求に応答が返る RPC です。購読は Subscribe で、これも要求(SubscribeRequest)で始まります。Subscribe には ONCE・POLL・STREAM の 3 つのモードがあります。仕様の文書(0.4.0)によれば、ONCE は更新を作って送った後にチャネルを閉じ、POLL は長く保つチャネルの上で要求に応じてデータを取り出し、STREAM は更新を送り続けます(§9.6)。
NETCONF の動的購読も、<establish-subscription> の要求に応答(subscription-result)が返るところから始まります。NETCONF の動的購読と gNMI の STREAM の購読は、成立した後は、機器が 1 本ずつの要求を待たずにデータを送り出します。本ラボの C9K(17.15.03)は ONCE と POLL を拒み、成立した gNMI の購読は STREAM(SAMPLE・ON_CHANGE)だけでした(§9.6)。
CLI で設定する購読(configured)は設定の投入で始まり、機器が受信器へ接続を張って送り出します(§7)。
第 7 章は全 6 節で、本節はその 3 つ目の節です。
本節は出典に基づく部分と、本ラボの実測に基づく部分を分けて書きます。実測は 2 台の機器で、版が違います。
| 層 | どこ | 何を根拠にしているか |
|---|---|---|
| 出典層 | §2 と、§4〜§11 の引用の段落 | RFC 5277・RFC 6020・RFC 7950・RFC 7951・RFC 8072、draft-ietf-netconf-rfc5277bis-01 と draft-ietf-netconf-yang-push-04(CSR1 のモジュールの reference 文の版)、draft-ietf-netconf-subscribed-notifications-03 と draft-ietf-netconf-yang-push-07(17.3 の章が本文で挙げる版)、RFC 8639 と RFC 8641(位置付けの 1 文ずつ)、gNMI の仕様の文書(Version 0.4.0)、gnmi.proto(0.4.0 と 0.7.0 の 2 版)、IOS XE の MDT の proto(mdt_grpc_dialout.proto・telemetry.proto)、Cisco の Programmability Configuration Guide の 17.3.x と 17.15.x の gNMI 章・Model-Driven Telemetry 章 |
| 実測層(CSR1) | §3〜§8 | CML 上の csr1000v 17.03.08a(CSR1)。NETCONF の購読と CLI で設定した購読。7-1・7-2 と同じ機種と版 |
| 実測層(C9K) | §3・§9 | CML 上の cat9000v-uadp 17.15.03(C9K)。gNMI だけ |
| 実測層(機器が返した本文) | §4〜§6 | CSR1 が get-schema で返した YANG の本文(応答の CDATA の中身を取り出したもの) |
| ツール側の観測 | §3〜§9・§11.6・§11.9 の〔ツール側〕を付けた出力 | COL(Ubuntu 24.04.2)の gnmic 0.49.0・gnmi_sub.py・受信器 mdt_receiver.py の記録、WSL の NETCONF のクライアント(§3)が送った要求と保存の順、WSL の照合の道具(crosscheck_xr.py。§7.1)の出力、取得スクリプトの判定メモ(§3.3)。機器の出力そのものではない |
| 確かめていないこと | §10 | — |
17.3 の機器(CSR1)で撮ったことを 17.15 の機器(C9K)の話にはせず、その逆もしません。Cisco のガイドも、CSR1 の話には 17.3.x の版、C9K の話には 17.15.x の版を当てます。
以下に貼る実機出力は改変していません。長い出力から一部を抜き出した箇所には …(省略) を置きました。
プロンプトとコマンドを 1 行にまとめた表記(CSR1# show …・C9K# show …・COL の道具の COL $ …)は本節の組み立てで、取得の記録ではコマンドが見出しの行として別に残っています。COL の行は、取得の記録の見出しのコマンドをそのまま写しています(gnmic は /home/labuser/bin/gnmic から)。NETCONF は、WSL のクライアントが送ったバイト列(wire)と、応答から chunk の見出しを外した XML を載せます(7-1 §6 の chunked framing)。
パスワードは撮影ごとの使い捨てで、本文には載せていません。gnmic と gnmi_sub.py には、パスワードを標準入力から渡しました(gnmic は環境変数 GNMIC_PASSWORD)。利用者名は伏せておらず、syslog の行(§5.3・§6.4・§9.6)と §9 の図の CLI の箱に netops のまま出ています。
時刻は機器の時計(UTC)で、show clock・syslog の行頭・通知の eventTime の値をそのまま書きます。COL の道具が記録した時刻(recv_utc・t_utc)は COL の時計で、機器の時計とのずれは測っていません。通知の時刻と CLI の時刻は並べるだけで、その差を遅れとは扱いません。
2. 購読と送り出しの用語
2.1 Model-Driven Telemetry とストリーム
Model-Driven Telemetry(以下 MDT)は、YANG のモデルで形を定めたデータを、購読に応じて機器が送り出す仕組みです。17.3 の章が準拠先に挙げる draft-ietf-netconf-yang-push-07 は、その目的を次のように書いています。
Via the mechanism described in this document, subscriber applications may request a continuous, customized stream of updates from a YANG datastore.
送り出すデータの集まりをストリーム (stream) と呼びます。CSR1 のモジュールの reference 文が挙げる draft-ietf-netconf-rfc5277bis-01 は、ストリームを次のように定義しています。
An event stream is a set of events available for subscription from a publisher.
17.3 の章は、Cisco IOS XE のストリームを 2 つとしています。本ラボの購読は、すべて yang-push のストリームでした(機器の表示は Stream: yang-push)。
Cisco IOS XE supports two streams: yang-push and yang-notif-native.
CSR1 のモジュールの reference 文が挙げる draft-ietf-netconf-yang-push-04 は、yang-push のストリームが設定のデータと状態のデータの両方を含むと書いています。
yang-push includes the entirety of YANG data, including both configuration and operational data.
17.3 の章は、対象のデータストアを running だけとしています。
The only target database that is supported is running.
17.3 の章は、NETCONF を使わない場合でも、telemetry には NETCONF-YANG の設定が要ると書いています。CSR1 には 7-1・7-2 と同じ有効化の行(netconf-yang を含む 6 行)を入れました(§3.3)。
NETCONF-YANG must be configured for telemetry to work, even if NETCONF is not used.
17.15 の章の前提条件の一覧は、NETCONF-YANG の設定と稼働を挙げています。
NETCONF-YANG must be configured and running on the device.
同じ一覧の直後の注は、NETCONF-YANG と gNXI のどちらかの設定が要るとしています。
Either NETCONF-YANG or gNXI must be configured for telemetry to work.
C9K(17.15.03)には netconf-yang を入れず、gnxi と gnxi server を入れて gNMI の購読を撮りました(§9.1・§9.6)。
2.2 dynamic と configured — dial-in と dial-out
購読の作り方は 2 つあります。購読する側が RPC で作るものを動的購読 (dynamic subscription)、機器の設定として作るものを設定購読 (configured subscription) と呼びます。17.3 の章は、前者を dial-in、後者を dial-out と呼ぶ理由を、誰が接続を張るかで説明しています。
Because dynamic subscriptions are created by clients (the subscriber) that connect into the publisher, they are considered dial-in. Configured subscriptions cause the publisher to initiate connections to receivers, and as a result, they are considered dial-out.
draft-ietf-netconf-rfc5277bis-01 は、動的購読を RPC の制御のやり取りで合意した購読と定義し、その寿命を確立に使ったセッションの寿命に結び付けています。
Dynamic subscription: A subscription agreed between subscriber and publisher via create, establish, modify, and delete RPC control plane signaling messages.
The lifetime of a dynamic subscription is limited by the lifetime of the subscriber session used to establish it. Typically loss of the transport session tears down any dependent dynamic subscriptions.
設定購読は、再起動をまたいで残る点と、受信者を購読者と別に指定できる点が動的購読と違います(draft の定義です。IOS XE の 17.3 の章が、再起動の後に設定購読が残る条件として書くことは §8)。
Configured subscriptions persist across reboots, and persist even when transport is unavailable. This also means configured subscriptions do not support negotiation.
Firstly, configuration operations do not support negotiation while RPCs do. Secondly, while RPCs mandate that the subscriber establishing the subscription is the only receiver of the notifications, configuration operations permit specifying receivers independent of any tracked subscriber.
2 つの作り方の違いは以下のとおりです(出典層。本ラボで撮ったものの場所を右の列に書きます)。
| 項目 | 動的購読(dial-in) | 設定購読(dial-out) |
|---|---|---|
| 作り方 | 購読する側が RPC で作る | 機器の設定として作る |
| 接続を張る側 | 購読する側(クライアント)が機器へ | 機器が受信器へ |
| 寿命 | 確立に使ったセッションに結び付く | 設定として残る(再起動の後の条件は §8) |
| 本ラボ | NETCONF の establish-subscription(§5・§6)・gNMI の Subscribe(§9) | CLI の telemetry ietf subscription と gRPC(§7) |
2.3 periodic と on-change、push-update と push-change-update
購読の送り出しの契機 (update trigger) には、一定の間隔で送る periodic と、データが変わった時に送る on-change があります。CSR1 のモジュールの reference 文が挙げる draft-ietf-netconf-yang-push-04 は、2 つを次のように書いています。
For periodic subscriptions, the trigger is defined by a “period”, a parameter that defines the interval with which updates are to be pushed.
On-change subscriptions allow subscribers to subscribe to updates whenever changes to objects occur.
同じ draft は、on-change の購読の値として dampening period を書いています(本機の要求の要素名は dampening-period。§6)。
One parameter specifies the dampening period, i.e. the interval that must pass before a successive update notification for the same Subscription is sent. Note that the dampening period applies to the set of all data nodes within a single subscription. This means that on the first change of an object, an update notification containing that object is sent either immediately or at the end of a dampening period already in effect.
同じ draft は、送り出す通知を 2 種に分けています。push-update は購読したデータの全体の写しで、periodic の更新に使います。push-change-update は前の通知からの変化を運ぶ通知で、on-change の購読で使います。
Notification “push-update” is used to send a complete snapshot of the data that has been subscribed to, with all YANG object filters applied. The notification is used for periodic subscription updates in a periodic subscription.
A push-change-update notification is the most common type of update for on-change subscriptions. It is not used for periodic subscriptions. The update record in this case contains a data snippet that indicates the full set of changes that data nodes have undergone since the last notification of YANG objects.
2.4 通知のメッセージ — RFC 5277 と YANG の notification 文
NETCONF の通知の枠組みは RFC 5277 が定めています。RFC 5277 は、基本の NETCONF の上に載る任意の機能として、非同期の通知の配送を定義します。
This document defines mechanisms that provide an asynchronous message notification delivery service for the [NETCONF] protocol. This is an optional capability built on top of the base NETCONF definition.
通知は <notification> 要素で届き、RFC 5277 が中身として定めるのは eventTime だけです。eventTime はイベントが生じた時刻で、機器が通知を送った時刻ではありません。
The time the event was generated by the event source. This parameter is of type dateTime and compliant to [RFC3339].
Also contains notification-specific tagged content, if any. With the exception of <eventTime>, the content of the notification is beyond the scope of this document.
<notification> の中身の形は、YANG の notification 文が定めます。7-2 §2.2 では 1 行の定義だけを置きました。YANG 1.0(RFC 6020 §7.14)は notification 文を「NETCONF の通知」を定める文とし、YANG 1.1(RFC 7950 §7.16)は定義の文から NETCONF の語を外しています。
The “notification” statement is used to define a NETCONF notification.
The “notification” statement is used to define a notification.
どちらの版でも、notification 文はスキーマの木に notification の節点を作ります。
It takes one argument, which is an identifier, followed by a block of substatements that holds detailed notification information. The “notification” statement defines a notification node in the schema tree.
YANG 1.1(RFC 7950 §7.16)は、通知の木はどのデータストアの一部でもないので、その中の節点の config 文はすべて無視されるとしています。
Since the notification tree is not part of any datastore, all “config” statements for nodes in the notification tree are ignored.
2.5 gRPC と gNMI
gRPC は、RPC(remote procedure call。7-1 §2)の仕組みの 1 つです。C9K(17.15.03)に当てる 17.15 の gNMI 章は、gRPC を次のように書き、gRPC が gNMI を運ぶとしています。
gRPC is a remote procedure call developed by Google for low-latency, scalable distributions with mobile clients communicating to a cloud server. gRPC carries gNMI, and provides the means to formulate and transmit data and operation requests.
gRPC のサービスとメッセージは、.proto のファイルに書かれます。本節が載せる .proto(gNMI の gnmi.proto・IOS XE の dial-out の mdt_grpc_dialout.proto と telemetry.proto)の読み方は §7.1 に置きました。
gNMI は、設定とテレメトリを 1 つの gRPC のサービスで扱うプロトコルです。gNMI の仕様の文書(Version 0.4.0)は、その意図を次のように書いています。
The intention is that a single gRPC service definition can cover both configuration and telemetry - allowing a single implementation on the network element, as well as a single NMS element to interact with the device via telemetry and configuration RPCs.
gNMI の購読は、1 本以上のパスと、送り出しの契機を決めるモード (mode) から成ります(モードの種類は §9.6)。
A subscription consists of one or more paths, with a specified subscription mode. The mode of each subscription determines the triggers for updates for data sent from the target to the client.
gNMI のパスは、gnmi.proto の Path のメッセージで表します。C9K が名乗る版(0.7.0。§9.2)の gnmi.proto の Path は、パスを区別するためのラベルの origin の欄と、パスの要素の列の elem の欄を持ちます(gnmi.proto 0.7.0 の Path。出典層。origin の値ごとのパスの書き方は §9.3)。
…(省略)
message Path {
…(省略)
string origin = 2; // Label to disambiguate path.
repeated PathElem elem = 3; // Elements of the path.
…(省略)2.6 用語のまとめ
用語は以下のとおりです(出典層。本機の表示の語は右の列)。
| 用語 | 意味 | 本機の表示の例 |
|---|---|---|
| ストリーム | 購読できるイベントの集まり。IOS XE は yang-push と yang-notif-native | Stream: yang-push |
| 動的購読(dial-in) | 購読する側が RPC で作る購読。作ったセッションに寿命が結び付く | Type: Dynamic |
| 設定購読(dial-out) | 機器の設定として作る購読。機器が受信器へ接続を張る | Type: Configured |
| periodic | 一定の間隔で送り出す契機 | Update Trigger: periodic |
| on-change | データが変わった時に送り出す契機 | Update Trigger: on-change |
| dampening period | on-change の購読で、同じ購読の次の更新の通知を送るまでに経過すべき間隔(§2.3) | Dampening period: 0(§6.2) |
| push-update | 購読したデータの全体の写しの通知 | <push-update> |
| push-change-update | 前の通知からの変化の通知 | <push-change-update> |
| eventTime | イベントが生じた時刻 | <eventTime> |
| gRPC | gNMI を運ぶ RPC の仕組み(§2.5)。IOS XE の設定購読の送り出しにも使う(§7.1) | protocol grpc-tcp(§7.2) |
| origin | gNMI のパスの Path のメッセージの欄。パスの書き方を区別するラベル(§2.5・§9.3) | rfc7951・legacy(§9.3) |
| 符号化 | 送り出すデータの表し方。17.3 の章は gRPC(設定購読の送り出し)の符号化を kvGPB だけと書く(§7.1)。gNMI は JSON・JSON_IETF・PROTO など | Encoding: encode-xml(CSR1 の NETCONF の動的購読 §5.3・CLI の 105 §7.8)/Encoding: encode-kvgpb(CSR1 の CLI の 101〜104 §7.3・C9K の gNMI の購読 §9.6・§11.6) |
| kvGPB | key-value Google Protocol Buffers。17.3 の章が gRPC の送り出しの符号化に挙げる形(§7.1) | encode-kvgpb(§7.2) |
3. 本ラボの構成
本ラボは CML 上の 5 ノードで、機器は版の違う 2 台です。NETCONF の購読と CLI で設定した購読は CSR1(csr1000v 17.03.08a)で撮り、gNMI は C9K(cat9000v-uadp 17.15.03)で撮りました。CSR1 で gNMI を撮らなかった理由は §3.3 の拒否です。
| ノード | 機種・版 | IF | アドレス | 役割 |
|---|---|---|---|---|
| CSR1 | csr1000v 17.03.08a | Gi1(vrf Mgmt-vrf) | 172.16.1.241/24 | NETCONF の購読(dial-in)を受ける・CLI で設定した購読を送り出す(Mgmt-vrf の経路) |
| CSR1 | 〃 | Gi2(global) | 10.7.31.1/24 | CLI で設定した購読を送り出す(VRF の無い経路) |
| CSR1 | 〃 | Loopback0 | 10.7.3.1/32 | 購読するパスの対象 |
| CSR1 | 〃 | Mgmt-vrf の既定経路 | 0.0.0.0/0 → 172.16.1.1 | ラボの外からの管理の接続のための経路(設計) |
| COL | Ubuntu 24.04.2 | ens2 | 172.16.1.242/24 | dial-out の受信器(mdt_receiver.py)と、gNMI のクライアント(gnmic 0.49.0・gnmi_sub.py)の置き場 |
| COL | 〃 | ens3 | 10.7.31.2/24 | CSR1 の Gi2 と直結 |
| C9K | cat9000v-uadp 17.15.03 | Gi0/0(vrf Mgmt-vrf) | 172.16.1.244/24 | gNMI だけ |
| C9K | 〃 | Loopback0 | 10.7.3.2/32 | gNMI の Get・Set・Subscribe の対象 |
| C9K | 〃 | Mgmt-vrf の既定経路 | 0.0.0.0/0 → 172.16.1.1 | ラボの外からの管理の接続のための経路(設計) |
| mgmt-sw / ext | unmanaged_switch / external_connector | — | — | 管理の L2 とラボの外への出口 |
NETCONF のクライアントと、両機器の CLI(SSH)は、ラボの外の WSL から使いました。機器の表示では、この接続元は 192.168.1.50 に見えます(本ラボの設計では WSL の接続が NAT を経て見えるアドレスですが、出力では確かめていません)。COL のアドレスと経路は、COL の shell の表示(ツール側)です。
NETCONF のクライアントは 7-1 §5 と同じ作りで、WSL の Python(paramiko)で CSR1 の TCP 830 の netconf サブシステムを開きました。機器の hello を受けてから自分の hello を送り(7-1 §5.2)、双方が base:1.1 を名乗るので chunked で送受しています(7-1 §6)。クライアントが送った hello は §4.1 に載せます。
両機器の起動時の設定(day0)は、7-1 §3 と同じ形です。ホスト名・利用者 netops(privilege 15)・Mgmt-vrf と管理の IF・Loopback0(description initial)・CLI 用の SSH を入れ、syslog のバッファは logging buffered 512000 informational にしました(後始末の確認(Phase Z)の running-config の行と、起動時の syslog の %SYS-5-LOG_CONFIG_CHANGE の行の size (512000)。§6.4・§9.6)。NETCONF(CSR1)と gNMI(C9K)の有効化の行は day0 に入れず、§3.3 と §9.1 で投入しました。利用者が privilege 15 であることは、CSR1 の NETCONF の認証の行の PRIV15(§5.3)と、C9K の起動時の syslog の %AAA-6-USER_PRIVILEGE_UPDATE の行の priv-15 に出ています。
3.1 2 つの版
CSR1 の版は 17.03.08a で、§14 の Cisco の設定ガイドの 17.3.x と同じ系列です。CSR1(csr1000v 17.03.08a)の show version は以下のとおりです。
CSR1# show version
Cisco IOS XE Software, Version 17.03.08a
Cisco IOS Software [Amsterdam], Virtual XE Software (X86_64_LINUX_IOSD-UNIVERSALK9-M), Version 17.3.8a, RELEASE SOFTWARE (fc3)
…(省略)
cisco CSR1000V (VXE) processor (revision VXE) with 1104920K/3075K bytes of memory.
…(省略)C9K の版は 17.15.03 で、ガイドの 17.15.x と同じ系列です。C9K(cat9000v-uadp 17.15.03)の show version は以下のとおりです。
C9K# show version
Cisco IOS XE Software, Version 17.15.03
Cisco IOS Software [IOSXE], Catalyst L3 Switch Software (CAT9K_IOSXE), Version 17.15.3, RELEASE SOFTWARE (fc1)
…(省略)
cisco C9KV-UADP-8P (VXE) processor (revision VXE) with 743842K/3075K bytes of memory.
…(省略)3.2 COL — 受信器とクライアントの置き場
COL は、CSR1 が送り出す購読の受信器と、C9K へ要求を送る gNMI のクライアントを置いた Ubuntu です。〔ツール側〕COL の shell が表示した OS と版は以下のとおりです。
COL $ uname -a; python3 -V; head -3 /etc/os-release; date -u
Linux col 6.8.0-59-generic #61-Ubuntu SMP PREEMPT_DYNAMIC Fri Apr 11 23:16:11 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux
Python 3.12.3
PRETTY_NAME="Ubuntu 24.04.2 LTS"
…(省略)COL の道具は 3 つです。どれも機器の外で動く道具で、出力は機器の応答を道具が描いた・記録したもの(ツール側の観測)です。
| 道具 | 役割 | 本文 |
|---|---|---|
| gnmic 0.49.0 | gNMI のクライアント。Capabilities・Get・Set と、Subscribe の ONCE・SAMPLE | §9 |
| gnmi_sub.py | gNMI の Subscribe を送り、応答と、終わった時の gRPC の status を 1 件ずつ記録する Python の道具。POLL・TARGET_DEFINED・ON_CHANGE | §9.6 |
| mdt_receiver.py | CSR1 が送り出す購読の受信器(gRPC)。受け取ったバイト列をそのまま .bin に残し、復号した形を .txt に、受けた順の記録を events.jsonl に書く | §7 |
gnmi_sub.py と mdt_receiver.py は本ラボで書いた道具で、コードは公開していません。mdt_receiver.py の作りは §7.1 に書きます。gnmi_sub.py の作りは次のとおりです。
- gNMI の stub は、§9.2・§14 の gnmi.proto(openconfig/gnmi の commit 00369d9・gnmi_service 0.7.0)から作りました
- TLS なしの gRPC の channel を張り、資格情報(利用者名とパスワード)を gRPC の metadata の
username・passwordのキーで渡します(gnmic と同じ形) - 引数から SubscriptionList の mode・Subscription の mode・パス・encoding を組み、SubscribeRequest を 1 本送ります。パスの先頭の
rfc7951:などは Path の origin の欄に入れます(§2.5) - 送った要求の text_format(
request-0001.txt)と受けた応答(response-NNNN.txt)を残し、要求・応答・終わった時の gRPC の status を、1 件ずつevents.jsonlに記録します --durationの秒数がたつと、クライアントの側から打ち切ります
道具の版と呼び出しの引数は、events.jsonl の 1 行目(開始の行)に記録されています(§9.6 の POLL・TARGET_DEFINED・ON_CHANGE の記録に載せます)。
〔ツール側〕COL の gnmic の版は以下のとおりです(同じコマンドで撮った道具のハッシュ値の行は省きました)。
COL $ /home/labuser/bin/gnmic version; sha256sum /home/labuser/bin/gnmic /home/labuser/collector/mdt_receiver.py /home/labuser/collector/*_pb2*.py /home/labuser/gnmi_client/gnmi_sub.py
version : 0.49.0
commit : ce0d4173
date : 2026-09-16T19:25:59Z
…(省略)3.3 CSR1 の有効化と、gNMI の行の拒否
CSR1 の NETCONF の有効化は、7-1 §4.2 と同じ 6 行です。CSR1(csr1000v 17.03.08a)の投入のエコーは以下のとおりです。
configure terminal
Enter configuration commands, one per line. End with CNTL/Z.
CSR1(config)#aaa new-model
CSR1(config)#aaa authentication login default local
CSR1(config)#aaa authorization exec default local
CSR1(config)#netconf-yang
CSR1(config)#ip http secure-server
CSR1(config)#restconf
CSR1(config)#end
CSR1#投入の後の待ち方も 7-1 §4.3 と同じで、show netconf-yang datastores を show clock で挟んで繰り返し撮りました。1 回目(15:13:09.601)から 5 回目までは % Error: Currently unable to process request で、6 回目に running のデータストアが返りました。CSR1(csr1000v 17.03.08a)の 6 回目の表示は以下のとおりです。
CSR1# show clock
*15:14:32.894 UTC Sun Oct 11 2026
CSR1# show netconf-yang datastores
Datastore Name : running
CSR1# show clock
*15:14:37.300 UTC Sun Oct 11 2026datastores が running を返した後の CSR1 の syslog には、NETCONF にかかわる次の行がありました。後始末の確認(Phase Z)で撮った CSR1(csr1000v 17.03.08a)の show logging の抜粋は以下のとおりです。
CSR1# show logging
…(省略)
*Oct 11 15:15:09.363: %DMI-5-NACM_INIT: R0/0: dmiauthd: NACM configuration has been set to its initial configuration.
*Oct 11 15:15:15.302: %DMI-5-AUTH_PASSED: R0/0: dmiauthd: User 'netops' authenticated successfully from 192.168.1.50:59870 and was authorized for netconf over ssh. External groups: PRIV15
*Oct 11 15:15:23.004: %DMI-5-SYNC_COMPLETE: R0/0: dmiauthd: The running configuration has been synchronized to the NETCONF running data store.
*Oct 11 15:15:36.795: %DMI-5-AUTH_PASSED: R0/0: dmiauthd: User 'netops' authenticated successfully from 192.168.1.50:59884 and was authorized for netconf over ssh. External groups: PRIV15
…(省略)時刻の順に並べると、以下のとおりです(どれも機器の時計)。
| 機器の時刻 | 出来事 | 出どころ |
|---|---|---|
| 15:14:32.894〜15:14:37.300 | datastores の 6 回目で running が返った | show clock(上) |
| 15:15:09.363 | %DMI-5-NACM_INIT | syslog |
| 15:15:12.808 | Phase A(§4)の最初の show clock | show clock |
| 15:15:15.302 | 192.168.1.50:59870 の netconf over ssh の認証 | syslog |
| 15:15:23 | netconf-start-time(秒まで) | Phase Z の show netconf-yang statistics |
| 15:15:23.004 | %DMI-5-SYNC_COMPLETE | syslog |
| 15:15:36.795 | 192.168.1.50:59884 の netconf over ssh の認証 | syslog |
表の netconf-start-time は Phase Z で撮った値で、秒までの表示です。1 本目の認証(15:15:15.302)と 2 本目(15:15:36.795)の間の時刻ですが、NETCONF の受け付けの開始を測ったものとしては扱いません。
〔ツール側〕取得スクリプトの判定メモには、Phase A の hello の 1 回目の試行はチャネルが閉じて(受信 0 bytes)失敗し、2 回目の試行で hello を受けた、とあります(§4.1 の session-id 30 のセッション)。根拠はこの判定メモだけで、機器の出力ではありません。2 本の認証の行と 2 回の試行の対応は、記録していません。本ラボでは、datastores が running を返した後の最初の NETCONF の試行で hello を受け取れませんでした(1 回の観測で、理由は確かめていません。§10)。
同じ CSR1 に、gNMI の有効化の行を入れました。CSR1(csr1000v 17.03.08a)は、gnxi と gnxi server の 2 行を % Invalid input で拒みました。
configure terminal
Enter configuration commands, one per line. End with CNTL/Z.
CSR1(config)#gnxi
^
% Invalid input detected at '^' marker.
CSR1(config)#gnxi server
^
% Invalid input detected at '^' marker.
CSR1(config)#end
CSR1#CSR1(csr1000v 17.03.08a)は、gnmi-yang と gnmi-yang server の 2 行も同じく拒みました。
configure terminal
Enter configuration commands, one per line. End with CNTL/Z.
CSR1(config)#gnmi-yang
^
% Invalid input detected at '^' marker.
CSR1(config)#gnmi-yang server
^
% Invalid input detected at '^' marker.
CSR1(config)#end
CSR1#CSR1 の yang-management のプロセス一覧は 8 行で、8 行とも Running でした。C9K の一覧(§9.1)にある gnmib の行は、CSR1(csr1000v 17.03.08a)の一覧にはありません。
CSR1# show platform software yang-management process
confd : Running
nesd : Running
syncfd : Running
ncsshd : Running
dmiauthd : Running
nginx : Running
ndbmand : Running
pubd : Runningここから言えるのは、この版の csr1000v が、投入した 4 行を % Invalid input で拒み、プロセス一覧に gnmib が無かったことまでです。他の版・他の機種で gNMI が使えるかどうかは、この出力からは言えません。
購読を始める前の CSR1 の購読一覧は空でした。show telemetry ietf subscription all の出力に文字のある行は無く、購読が 1 本あった時の一覧(§5.7 の close の前)に在った Telemetry subscription brief の行も出ていません。本節で購読一覧が「空」と書く時は、この形を指します。
3.4 撮影の段階
撮影は段階(Phase)に分け、1 本の取得スクリプトで続けて撮りました。CSR1 の段階の後に C9K の段階を置いています。
| Phase | 機器 | 内容 | 本文 | 時刻の拠り所 |
|---|---|---|---|---|
| 0 | CSR1 | 版・有効化・準備完了の関門・gNMI の行の拒否・購読の一覧(0 件) | §3 | 有効化の投入の時刻は撮っていない。show clock は準備完了の関門の最初の値(15:13:04.401)から |
| A | CSR1 | hello(取得スクリプトの 2 回目の試行で受けた。§3.3)と、購読まわりのモジュールの get-schema | §4 | show clock |
| B | CSR1 | NETCONF の動的購読・periodic(B1〜B4) | §5 | show clock |
| C | CSR1 | NETCONF の動的購読・on-change(候補 C1〜C7) | §6 | show clock |
| D | CSR1 + COL | CLI で設定した購読と dial-out(D1 = 101〜104・D2 = 105) | §7 | show clock(CSR1 の最後の値は 15:25:59.524) |
| G の前半 | C9K + COL | gNMI の有効化・準備完了の関門(§9.1)・Capabilities・Get・Set・Subscribe の ONCE と POLL | §9.1〜§9.6 | show clock なし(syslog の行頭だけ) |
| G の後半 | C9K + COL | Subscribe の TARGET_DEFINED・SAMPLE・ON_CHANGE | §9.6 | show clock(15:28:45.696〜15:32:37.935) |
| S | COL | COL の環境 | §3.2 | — |
| Z | CSR1・C9K | 後始末の確認(最後の show logging・running-config・購読の一覧) | 逐語の引用は §3.3・§5.3・§6.4・§9.6、照合の補いは §3・§6.2・§7.4・§9.1・§10・§11.10 | show clock なし(両機器) |
Phase Z は専用の節を持たず、各節の syslog の行と running-config の行の出所として使います。show clock の値は、どれも 2026 年 10 月 11 日の UTC です。show clock を撮っていない段の時刻は、syslog の行頭の値で書きます。
4. 機器が名乗る購読(csr1000v 17.03.08a)
4.1 hello の capability
CSR1 の NETCONF の hello には、購読にかかわる capability とモジュールの名前が並んでいました。CSR1(csr1000v 17.03.08a)の hello の抜粋は以下のとおりです(Phase A で hello を受けたセッション。取得スクリプトの 2 回目の試行で、session-id は 30。§3.3)。
<?xml version="1.0" encoding="UTF-8"?>
<hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<capabilities>
<capability>urn:ietf:params:netconf:base:1.0</capability>
<capability>urn:ietf:params:netconf:base:1.1</capability>
<capability>urn:ietf:params:netconf:capability:writable-running:1.0</capability>
<capability>urn:ietf:params:netconf:capability:rollback-on-error:1.0</capability>
<capability>urn:ietf:params:netconf:capability:validate:1.0</capability>
<capability>urn:ietf:params:netconf:capability:validate:1.1</capability>
<capability>urn:ietf:params:netconf:capability:xpath:1.0</capability>
<capability>urn:ietf:params:netconf:capability:notification:1.0</capability>
<capability>urn:ietf:params:netconf:capability:interleave:1.0</capability>
…(省略)
<capability>http://cisco.com/ns/yang/Cisco-IOS-XE-mdt-cfg?module=Cisco-IOS-XE-mdt-cfg&revision=2020-03-01</capability>
<capability>http://cisco.com/ns/yang/Cisco-IOS-XE-mdt-common-defs?module=Cisco-IOS-XE-mdt-common-defs&revision=2020-07-01</capability>
<capability>http://cisco.com/ns/yang/Cisco-IOS-XE-mdt-oper?module=Cisco-IOS-XE-mdt-oper&revision=2020-07-01</capability>
<capability>http://cisco.com/ns/yang/Cisco-IOS-XE-mdt-oper-v2?module=Cisco-IOS-XE-mdt-oper-v2&revision=2020-07-01</capability>
…(省略)
<capability>http://cisco.com/ns/yang/cisco-xe-ietf-event-notifications-deviation?module=cisco-xe-ietf-event-notifications-deviation&revision=2018-12-03</capability>
<capability>http://cisco.com/ns/yang/cisco-xe-ietf-yang-push-deviation?module=cisco-xe-ietf-yang-push-deviation&revision=2018-12-03</capability>
…(省略)
<capability>urn:ietf:params:xml:ns:yang:ietf-event-notifications?module=ietf-event-notifications&revision=2016-10-27&features=json,configured-subscriptions&deviations=cisco-xe-ietf-event-notifications-deviation,cisco-xe-ietf-yang-push-deviation</capability>
…(省略)
<capability>urn:ietf:params:xml:ns:yang:ietf-yang-push?module=ietf-yang-push&revision=2016-10-28&features=on-change&deviations=cisco-xe-ietf-yang-push-deviation</capability>
…(省略)
<capability>
urn:ietf:params:netconf:capability:notification:1.1
</capability>
</capabilities>
<session-id>30</session-id></hello>]]>]]>hello の <capability> は 7-2 と同じ 520 本で、購読にかかわるものは以下のとおりです(本機の hello の表示。名乗っていることは、その機能が使える証拠にはなりません)。
| capability・モジュール | 本機の hello の表示 | 定めている資料 |
|---|---|---|
notification:1.0 | あり(hello の 11 行目) | RFC 5277 |
interleave:1.0 | あり(hello の 12 行目) | RFC 5277 |
notification:1.1 | あり(520 本目 = 最後の要素) | draft-ietf-netconf-rfc5277bis-01 §9 |
| ietf-event-notifications | revision 2016-10-27・features json と configured-subscriptions・deviation 2 本 | 本文は §4.2 |
| ietf-yang-push | revision 2016-10-28・features on-change・deviation 1 本 | 本文は §4.2 |
| cisco-xe-ietf-event-notifications-deviation・cisco-xe-ietf-yang-push-deviation | revision 2018-12-03 | 本文は §4.2 |
| Cisco-IOS-XE-mdt-cfg・-mdt-common-defs・-mdt-oper・-mdt-oper-v2 | Cisco の MDT のモジュール | — |
| ietf-subscribed-notifications | 無い(0 件) | draft-ietf-netconf-subscribed-notifications-03 の module |
RFC 5277 は、通知を扱う能力を capability の交換で名乗ると書いています。
The ability to process and send event notifications is advertised during the capability exchange between the NETCONF client and server.
交換のもう一方の、WSL のクライアントが送った hello は以下のとおりです(〔ツール側〕クライアントが送ったもの。Phase B・C の 3 本のセッションでも、同じ中身の hello を送りました)。
<?xml version="1.0" encoding="UTF-8"?>
<hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<capabilities>
<capability>urn:ietf:params:netconf:base:1.0</capability>
<capability>urn:ietf:params:netconf:base:1.1</capability>
</capabilities>
</hello>
]]>]]>クライアントが名乗ったのは base:1.0 と base:1.1 の 2 本だけで、notification:1.0・interleave:1.0・notification:1.1 は名乗っていません。
interleave:1.0 は、購読中のセッションで他の NETCONF の操作を受け付けることを示します。interleave は notification の capability に依存します。
The :interleave capability indicates that the NETCONF peer supports the ability to interleave other NETCONF operations within a notification subscription.
This capability is dependent on the notification capability being supported.
RFC 5277 の本文に notification:1.1 の文字列は 1 度も現れません(取得した RFC 5277 のテキストで数えて 0 件)。notification:1.1 を定めているのは、CSR1 の ietf-event-notifications の reference 文と同じ draft-ietf-netconf-rfc5277bis-01 で、この draft の機能を持つ機器は 1.0 と 1.1 の両方を名乗ると書いています。
Publishers supporting the features in this document must advertise both capabilities “urn:ietf:params:netconf:capability:notification:1.0” and “urn:ietf:params:netconf:capability:notification:1.1”.
Subscribers that only support [RFC5277] recognize capability “urn:ietf:params:netconf:capability:notification:1.0” and ignore capability “urn:ietf:params:netconf:capability:notification:1.1”. This allows them interacting with the publisher as per [RFC5277].
17.3 の MDT 章は、前提条件の節で、hello に notification:1.1 が載っていることを求め、この capability は IETF のテレメトリに対応する機器だけが名乗ると書いています。
The urn:ietf:params:netconf:capability:notification:1.1 capability must be listed in hello messages. This capability is advertised only on devices that support IETF telemetry.
CSR1(csr1000v 17.03.08a)の hello では、520 本目(最後の要素)がこの capability でした。購読を機器が受け付けたかどうかは、hello ではなく §5 以降の応答で見ます。
4.2 ietf-event-notifications と ietf-yang-push の本文
購読の RPC と通知を定めるモジュールの本文を、get-schema で取り出しました(get-schema は 7-2 §5)。CSR1(csr1000v 17.03.08a)が get-schema で返した本文(ietf-event-notifications@2016-10-27)の冒頭と revision は以下のとおりです。
module ietf-event-notifications {
namespace
"urn:ietf:params:xml:ns:yang:ietf-event-notifications";
prefix notif-bis;
import ietf-yang-types {
prefix yang;
…(省略)
revision 2016-10-27 {
description
"Tweaks to remove two notifications,
RPC for create subscription refined with stream default,
new grouping to eliminate some dymanically modifiable
parameters in modifiy subscription RPC";
reference
"draft-ietf-netconf-rfc5277bis-01";
}
…(省略)reference 文は draft-ietf-netconf-rfc5277bis-01 でした。この本文の rpc 文は 5 本(establish-subscription・create-subscription・modify-subscription・delete-subscription・kill-subscription)で、yang-version 文は 0 件です。NETCONF の動的購読を作る establish-subscription の定義は、同じ本文の以下の部分です(CSR1 17.03.08a が返した本文)。
…(省略)
rpc establish-subscription {
description
"This RPC allows a subscriber to create
(and possibly negotiate) a subscription on its own behalf.
If successful, the subscription
remains in effect for the duration of the subscriber's
association with the publisher, or until the subscription
is terminated by virtue of a delete-subscription request.
In case an error (as indicated by subscription-result)
is returned, the subscription is
not created. In that case, the RPC output
MAY include suggested parameter settings
that would have a high likelihood of succeeding in a
subsequent establish-subscription request.";
input {
uses subscription-info;
}
output {
uses subscription-response;
}
}
…(省略)もう 1 本の ietf-yang-push の本文は、冒頭に注釈 (/* … */) があり、その中に yang-version 1.1; の行が「Not Supported」の文と一緒に置かれていました。CSR1(csr1000v 17.03.08a)が返した本文(ietf-yang-push@2016-10-28)の冒頭と revision は以下のとおりです。
module ietf-yang-push {
/*
* ---------------------------------------------------
* Not Supported
yang-version 1.1;
* ---------------------------------------------------
*/
namespace "urn:ietf:params:xml:ns:yang:ietf-yang-push";
prefix yp;
import ietf-inet-types {
prefix inet;
}
import ietf-yang-types {
prefix yang;
}
import ietf-event-notifications {
prefix notif-bis;
}
…(省略)
revision 2016-10-28 {
description
"Updates to simplify modify-subscription, add anchor-time";
reference "YANG Datastore Push, draft-ietf-netconf-yang-push-04";
}
feature on-change {
description
"This feature indicates that on-change updates are
supported.";
}
…(省略)注釈を取り除くと、この本文の yang-version 文は 0 件です。RFC 7950 §7.1.2 は、yang-version 文を持たないモジュールを YANG version 1 のものとしています。したがって、CSR1 が返した ietf-yang-push は YANG 1.0 のモジュールです(draft-ietf-netconf-yang-push-04 の module と同じ本文かどうかは、本ラボでは比べていません)。
A module or submodule that doesn’t contain the “yang-version” statement, or one that contains the value “1”, is developed for YANG version 1, defined in [RFC6020].
同じ本文の notification 文は 2 本(push-update と push-change-update)です。push-update の中身を入れる anydata datastore-contents は注釈の中にあり、注釈の外の中身の leaf は文字列型の datastore-contents-string でした。CSR1(csr1000v 17.03.08a)が返した本文の push-update の部分は以下のとおりです。
…(省略)
notification push-update {
description
"This notification contains a push update, containing
data subscribed to via a subscription.
This notification is sent for periodic updates, for a
periodic subscription. It can also be used for
synchronization updates of an on-change subscription.
This notification shall only be sent to receivers
of a subscription; it does not constitute a general-purpose
notification.";
leaf subscription-id {
type notif-bis:subscription-id;
mandatory true;
description
"This references the subscription because of which the
notification is sent.";
}
leaf time-of-update {
type yang:date-and-time;
description
"This leaf contains the time of the update.";
}
leaf updates-not-sent {
type empty;
description
"This is a flag which indicates that not all data nodes
subscribed to are included included with this
update. In other words, the publisher has failed to
fulfill its full subscription obligations.
This may lead to intermittent loss of synchronization
of data at the client. Synchronization at the client
can occur when the next push-update is received.";
}
/*
* --------------------------------------------------------------------
* datastore-contents not currently supported.
* Will replace datastore-contents-string in a future release.
anydata datastore-contents {
description
"This contains the updated data. It constitutes a snapshot
at the time-of-update of the set of data that has been
subscribed to. The format and syntax of the data
corresponds to the format and syntax of data that would be
returned in a corresponding get operation with the same
filter parameters applied.";
}
* --------------------------------------------------------------------
*/
leaf datastore-contents-string {
type string;
…(省略)push-change-update も同じ形で、if-feature "on-change"; を持ち、anydata datastore-changes は注釈の中、注釈の外の中身の leaf は datastore-changes-string です。§5〜§6 で実際に届いた通知の中身の要素は datastore-contents-xml と datastore-changes-xml で、この 2 つの名前は get-schema で取り出した 9 本の本文のどれにも現れません(grep で 0 件)。本文を取り出していない Cisco の拡張のモジュール(cisco-xe-ietf-yang-push-ext など)にこの名前があるかは確かめていません。
資料の側では、この 2 つの名前が例や文に出てきます。要素名だけを比べると、以下のとおりです。
| どこ | datastore-contents-xml | datastore-changes-xml | module の本文の中身の名前 |
|---|---|---|---|
| CSR1(17.03.08a)が返した ietf-yang-push の本文 | 無い | 無い | datastore-contents-string・datastore-changes-string(anydata は注釈の中) |
| 17.3 の MDT 章 | 本文の文と例 | 無い | — |
| draft-ietf-netconf-yang-push-04 の例 | Figure 1 | Figure 2 と Figure 4 | anydata の datastore-contents・datastore-changes |
| draft-ietf-netconf-yang-push-07 の例 | 無い(Figure 1 は datastore-contents) | Figure 4 だけ(Figure 2 と Figure 3 は datastore-changes) | anydata の datastore-contents・datastore-changes |
17.3 の MDT 章の本文の文は以下のとおりです。
The subscribed information element or tree is returned within the datastore-contents-xml tag.
比べたのは要素名だけです。-04 と -07 の例には <time-of-update> と、:1.0 の付いた ietf-yang-push の名前空間がありますが、本機の通知にはどちらもありません(§5.2・§6.2)。この比較から、本機の要素名がどの文書に基づくかは言えません。
4.3 deviation が外しているもの
hello の deviations= に挙がった 2 本の deviation のモジュールも取り出しました。cisco-xe-ietf-yang-push-deviation は、ietf-event-notifications の modify-subscription の全体を not-supported にし、establish-subscription の dampening-period(on-change の dampening period。§2.3)の範囲を “0” に置き換えています。CSR1(csr1000v 17.03.08a)が返した本文(cisco-xe-ietf-yang-push-deviation@2018-12-03)の該当部分は以下のとおりです。
…(省略)
revision 2018-12-03 {
description
"Added deviations for dampening-period to only accept 0 and
no-synch-on-start to be unsupported.";
}
…(省略)
deviation "/notif-bis:modify-subscription" {
deviate not-supported;
description "Currently not supported.";
}
…(省略)
deviation "/notif-bis:establish-subscription/notif-bis:input" +
"/yp:update-trigger/yp:periodic/yp:anchor-time" {
deviate not-supported;
description "Currently not supported.";
}
deviation "/notif-bis:establish-subscription/notif-bis:input" +
"/yp:update-trigger/yp:on-change/yp:dampening-period" {
deviate replace {
type yang:timeticks {
range "0";
}
}
description "Currently only accepts 0.";
}
deviation "/notif-bis:establish-subscription/notif-bis:input" +
"/yp:update-trigger/yp:on-change/yp:no-synch-on-start" {
deviate not-supported;
description "Currently not supported.";
}
…(省略)2 本の deviation の本文が外しているものを数えると、以下のとおりです(注釈の外の deviation 文だけを数えた値)。
| deviation のモジュール | 注釈の外の deviation 文 | 主な対象 |
|---|---|---|
| cisco-xe-ietf-event-notifications-deviation | 17 本(not-supported 13・replace 4) | establish-subscription の filter の by-reference・startTime・stopTime、設定購読の interface-originated |
| cisco-xe-ietf-yang-push-deviation | 22 本(not-supported 19・replace 3) | modify-subscription の全体、periodic の anchor-time、on-change の no-synch-on-start・excluded-change、dscp・subscription-priority・subscription-dependency、dampening-period(range “0”) |
2 本とも、push-update と push-change-update を対象にした deviation は 0 件でした。dampening-period の “0” は §6.5 の拒否と、no-synch-on-start の not-supported は §6.2 の Synch on start: Yes と並べます。
4.4 17.3 の章が挙げる draft の版と、RFC 8639・RFC 8641
CSR1 のモジュールの reference 文は draft-ietf-netconf-rfc5277bis-01 と draft-ietf-netconf-yang-push-04 でした。一方、17.3 の章は本文で、NETCONF の動的購読の RPC が別の版の draft で定められていると書いています。
RPCs that are used to create and delete dynamic subscriptions using NETCONF are defined in Custom Subscription to Event Notifications draft-ietf-netconf-subscribed-notifications-03 and Subscribing to YANG datastore push updates draft-ietf-netconf-yang-push-07.
subscribed-notifications の draft は、rfc5277bis の draft を改名したものです。-03 の改版の履歴(「v01 5277bis - v00 subscribed notifications」の項)は、次のように書いています。
Renamed from 5277bis to Subscribed Notifications.
同じ章の「IETF Draft Compliance」の節も、yang-push のストリームの準拠先に同じ 2 本(Version 03 と Version 07)を挙げます。
Custom Subscription to Event Notifications, Version 03
Subscribing to YANG datastore push updates, Version 07
ところが、同じ章の参考文献の表(Standards and RFCs)は、CSR1 のモジュールの reference 文と同じ 2 本の名前も並べています。
draft-ietf-netconf-rfc5277bis-01
draft-ietf-netconf-yang-push-04
資料と機器の版の関係を並べると、以下のとおりです。
| どこ | 購読の draft | yang-push の draft | 本ラボでの扱い |
|---|---|---|---|
| CSR1 のモジュールの reference 文(17.03.08a が返した本文) | rfc5277bis-01(ietf-event-notifications 2016-10-27) | yang-push-04(ietf-yang-push 2016-10-28) | 機器の振る舞いの説明に使う |
| 17.3 の章の本文・IETF Draft Compliance | subscribed-notifications-03 | yang-push-07 | 章が挙げる版として並べる |
| 17.3 の章の参考文献の表 | rfc5277bis-01(と上の版) | yang-push-04(と上の版) | 機器の reference 文と同じ名前がある |
draft-ietf-netconf-subscribed-notifications-03 の module は ietf-subscribed-notifications で、CSR1 の hello にこの名前は無く、章の購読の RPC の例が使う名前空間は ietf-event-notifications です(章の例の実物は §6.1。落とし穴としての整理は §11.1)。
RFC 8639 と RFC 8641 は、これらの draft と同じ名前のモジュール(ietf-subscribed-notifications・ietf-yang-push)を定める RFC です。どの draft がどの RFC になったかを書いた文は、本節が取得した資料にはありません。2 本の RFC の位置付けは、次の 1 文ずつです。RFC 8639 は、RFC 5277 の <create-subscription> を置き換える RPC を定めています。
The RPC operations in this document replace the operation <create-subscription> as defined in [RFC5277], Section 4.
RFC 8641 は、データストアの更新の購読(YANG-Push)を RFC 8639 の上に組み立てています。
This document defines a corresponding solution that is built on top of [RFC8639].
本ラボの 2 台は、どちらも ietf-subscribed-notifications(-03 と RFC 8639 の module の名前)を名乗っていません(CSR1 は hello、C9K は gnmic が描いた Capabilities の一覧で 0 件)。本節の NETCONF の購読は、すべて CSR1 の ietf-event-notifications と ietf-yang-push(draft の版)の RPC と通知です。
5. NETCONF の動的購読(periodic)
本節の NETCONF の購読は、すべて CSR1(csr1000v 17.03.08a)で、WSL のクライアントが張った NETCONF のセッションの上で撮りました。購読先は 7-2 で読んだ ietf-interfaces の状態の木(interfaces-state)の Loopback0 の統計です。
| 購読 | xpath | period | 結果 |
|---|---|---|---|
| B1 | /if:interfaces-state/interface[name="Loopback0"]/statistics | 1000 | 受理(id 2147483648)・push-update 5 本・delete-subscription で削除 |
| B2(章の例・対照) | /memory-ios-xe-oper:memory-statistics/memory-statistic | 1000 | 受理(id 2147483649)・push-update 5 本・削除 |
| B3 | B1 と同じ | 50 | 拒否(notif-bis:error-insufficient-resources) |
| B4 | B1 と同じ(別のセッション) | 1000 | 受理(id 2147483650)・購読中に close-session |
5.1 establish-subscription — 要求と応答
draft-ietf-netconf-rfc5277bis-01 は、establish-subscription を RPC として呼ぶと、購読の条件を交渉できると書いています。
When invoking the RPC, establish-subscription permits negotiating the subscription terms, changing them dynamically.
応答の形は、CSR1 のモジュールの reference 文が挙げるもう 1 本の draft、draft-ietf-netconf-yang-push-04 が §4.7.1(establish-subscription の RPC の節)で書いています。要求には受理か拒否かを明示して応え、受理の応答には受理した購読の subscription-id を含めます。
The publisher must respond explicitly positively (i.e., subscription accepted) or negatively (i.e., subscription rejected) to the request. Positive responses include the subscription-id of the accepted subscription.
subscription-result の値の意味は、2 か所に書かれています。1 か所は機器が返した ietf-event-notifications の本文の identity の description で、CSR1(csr1000v 17.03.08a)が get-schema で返した本文の該当部分は以下のとおりです(本節で出てくる 4 つの値)。
…(省略)
identity ok {
base subscription-result;
description
"OK - RPC was successful and was performed as requested.";
}
…(省略)
identity error-no-such-option {
base error;
description
"A requested parameter setting is not supported.";
}
identity error-insufficient-resources {
base error;
description
"The publisher has insufficient resources to support the
subscription as requested.";
}
…(省略)
identity error-other {
base error;
description
"An unspecified error has occurred (catch all).";
}
…(省略)もう 1 か所は 17.3 の MDT 章の表で、establish-subscription の応答の値(Result String)ごとに原因(Cause)を書いています(出典層)。
| subscription-result の値 | 17.3 の MDT 章の表の Cause |
|---|---|
ok | Success |
error-no-such-option | The requested subscription is not supported. |
error-insufficient-resources | A subscription cannot be created because of the following reasons:(以下の 3 つ)There are too many subscriptions.・The amount of data requested is too large.・The interval for a periodic subscription is too small. |
error-other | Some other error. |
機器の本文と章の表は、同じ値に違う文言を当てています(たとえば error-no-such-option は、本文が「A requested parameter setting」、章が「The requested subscription」)。本節が観測したのは機器が返した値までで、ある応答がどの原因に当たるかは、応答の値からは分かりません(§5.6・§6.4)。
〔ツール側〕WSL のクライアントが CSR1(csr1000v 17.03.08a)へ送った B1 の要求(wire)は以下のとおりです。
#442
<?xml version="1.0" encoding="UTF-8"?>
<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="101">
<establish-subscription xmlns="urn:ietf:params:xml:ns:yang:ietf-event-notifications" xmlns:yp="urn:ietf:params:xml:ns:yang:ietf-yang-push">
<stream>yp:yang-push</stream>
<yp:xpath-filter>/if:interfaces-state/interface[name="Loopback0"]/statistics</yp:xpath-filter>
<yp:period>1000</yp:period>
</establish-subscription>
</rpc>
##要求の子は stream・xpath-filter・period の 3 つだけで、符号化を指定する要素はありません。period の値に単位の表記はありません。CSR1(csr1000v 17.03.08a)の応答は以下のとおりです。
<?xml version="1.0" encoding="UTF-8"?>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="101"><subscription-result xmlns='urn:ietf:params:xml:ns:yang:ietf-event-notifications' xmlns:notif-bis="urn:ietf:params:xml:ns:yang:ietf-event-notifications">notif-bis:ok</subscription-result>
<subscription-id xmlns='urn:ietf:params:xml:ns:yang:ietf-event-notifications'>2147483648</subscription-id>
</rpc-reply>subscription-result は notif-bis:ok、subscription-id は 2147483648 でした。ここまでが要求と応答で、この後の通知は要求なしで届きます。
5.2 push-update — 要求なしで届く通知
購読の後、同じ NETCONF のセッションに push-update が届きました。CSR1(csr1000v 17.03.08a)が送った 1 本目の通知は以下のとおりです(1 本の通知が 1 行の XML で届きます)。
<?xml version="1.0" encoding="UTF-8"?>
<notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>2026-10-11T15:15:49.19Z</eventTime><push-update xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push"><subscription-id>2147483648</subscription-id><datastore-contents-xml><interfaces-state xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>Loopback0</name><statistics><discontinuity-time>2026-10-11T15:08:35+00:00</discontinuity-time><in-octets>0</in-octets><in-unicast-pkts>0</in-unicast-pkts><in-broadcast-pkts>0</in-broadcast-pkts><in-multicast-pkts>0</in-multicast-pkts><in-discards>0</in-discards><in-errors>0</in-errors><in-unknown-protos>0</in-unknown-protos><out-octets>0</out-octets><out-unicast-pkts>0</out-unicast-pkts><out-broadcast-pkts>0</out-broadcast-pkts><out-multicast-pkts>0</out-multicast-pkts><out-discards>0</out-discards><out-errors>0</out-errors></statistics></interface></interfaces-state></datastore-contents-xml></push-update></notification>通知の外側は RFC 5277 の <notification>(名前空間 urn:ietf:params:xml:ns:netconf:notification:1.0)で、RPC の応答ではありません。
Note that <notification> is not a Remote Procedure Call (RPC) method but rather the top-level element identifying the one- way message as a notification.
中は <eventTime>・<push-update>・subscription-id・<datastore-contents-xml> の順で、<datastore-contents-xml> の中は 7-2 で読んだ ietf-interfaces の状態の木そのもの(Loopback0 の statistics の葉 14 個)です。13 個の計数器は 5 本ともすべて 0 でした(Loopback0 に通信は流しておらず、この 13 個の値が変わる通知は撮っていません)。
B1 の購読 2147483648 の通知は 5 本です。eventTime と、隣の通知との差は以下のとおりです。
| 通知 | eventTime | 前の通知との差 |
|---|---|---|
| 1 本目 | 2026-10-11T15:15:49.19Z | — |
| 2 本目 | 2026-10-11T15:15:59.03Z | 9.84 秒 |
| 3 本目 | 2026-10-11T15:16:09.02Z | 9.99 秒 |
| 4 本目 | 2026-10-11T15:16:19.04Z | 10.02 秒 |
5 本目(§5.3 の <get> の応答を待つ間に保存) | 2026-10-11T15:16:29.07Z | 10.03 秒 |
17.3 の章は、period の単位を 1/100 秒とし、1000 なら 10 秒ごと、最小値は 100 と書いています。
The period is time, in centiseconds (1/100 of a second), between periodic push updates. A period of 1000 will result in getting updates to the subscribed information every 10 seconds. The minimum period that can be configured is 100, or one second. There is no default value.
本機の出力(要求・応答・show・syslog)には period の単位の表記が無く、機器の yang-push の本文は period の型を yang:timeticks と書くだけです。本ラボで言えるのは、period 1000 の購読で eventTime の差が 9.84〜10.03 秒だったことまでです。
章は、最初の push-update は直ちに送られ、その後は周期のタイマーの満了ごとに送られると書いています。
With periodic subscriptions, the first push-update with the subscribed information is sent immediately; but it can be delayed if the device is busy or due to network congestion. Updates are then sent at the expiry of the configured periodic timer.
本ラボの時刻を並べると、要求の直前の show clock が 15:15:46.718、§5.3 の <get> で読んだ購読の last-state-change-time が 15:15:48.96532、最初の eventTime が 15:15:49.19 でした。クライアントが要求を送った時刻と応答を受けた時刻は記録していないので、区間の長さとしては扱いません。
5.3 購読中の CLI と <get>
購読中の CSR1 では、CLI の telemetry の表示に購読が現れました。CSR1(csr1000v 17.03.08a)の detail は以下のとおりです。
CSR1# show telemetry ietf subscription 2147483648 detail
Telemetry subscription detail:
Subscription ID: 2147483648
Type: Dynamic
State: Valid
Stream: yang-push
Filter:
Filter type: xpath
XPath: /if:interfaces-state/interface[name="Loopback0"]/statistics
Update policy:
Update Trigger: periodic
Period: 1000
Encoding: encode-xml
Source VRF:
Source Address:
Notes:
Receivers:
Address Port Protocol Protocol Profile
-----------------------------------------------------------------------------------------
192.168.1.50 59878 netconf Type: Dynamic が動的購読、Encoding: encode-xml は要求で指定しなかった符号化の表示です。Receivers の行は Address 192.168.1.50・Port 59878・Protocol netconf でした。CSR1(csr1000v 17.03.08a)の receiver の表示は以下のとおりです。
CSR1# show telemetry ietf subscription 2147483648 receiver
Telemetry subscription receivers detail:
Subscription ID: 2147483648
Address: 192.168.1.50
Port: 59878
Protocol: netconf
Profile:
Connection: 0
State: Connected
Explanation: 同じ 192.168.1.50 と 59878 の組は、CSR1 の syslog の NETCONF の認証の行にも出ていました。%DMI-5-AUTH_PASSED の行は、192.168.1.50:59878 からの利用者の認証の成功と、netconf over ssh への許可を記録しています。行の時刻 15:15:46.252 は、Phase B(§5)の最初の show clock(15:15:43.912)と、B1 の要求の直前の show clock(15:15:46.718)の間です。機器の出力から言えるのはここまでで、クライアントの側でこの port が何だったかは記録していません(192.168.1.50 が何かは §10)。後始末の確認(Phase Z)で撮った CSR1(csr1000v 17.03.08a)の show logging の該当の行は以下のとおりです。
CSR1# show logging
…(省略)
*Oct 11 15:15:46.252: %DMI-5-AUTH_PASSED: R0/0: dmiauthd: User 'netops' authenticated successfully from 192.168.1.50:59878 and was authorized for netconf over ssh. External groups: PRIV15
…(省略)購読を残したまま、同じセッションで <get> を送り、Cisco-IOS-XE-mdt-oper の購読の一覧を読みました。〔ツール側〕WSL のクライアントが CSR1(csr1000v 17.03.08a)へ送った要求は以下のとおりです。
#267
<?xml version="1.0" encoding="UTF-8"?>
<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="102">
<get><filter type="subtree"><mdt-oper-data xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-mdt-oper"><mdt-subscriptions/></mdt-oper-data></filter></get>
</rpc>
##CSR1(csr1000v 17.03.08a)は、同じ message-id 102 で rpc-reply を返しました。
<?xml version="1.0" encoding="UTF-8"?>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="102"><data><mdt-oper-data xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-mdt-oper"><mdt-subscriptions><subscription-id>2147483648</subscription-id><base><stream>yang-push</stream><encoding>encode-xml</encoding><source-vrf></source-vrf><period>1000</period><xpath>/if:interfaces-state/interface[name="Loopback0"]/statistics</xpath></base><type>sub-type-dynamic</type><state>sub-state-valid</state><comments></comments><mdt-receivers><address>192.168.1.50</address><port>59878</port><protocol>netconf</protocol><state>rcvr-state-connected</state><comments></comments><profile></profile><last-state-change-time>2026-10-11T15:15:48.969462+00:00</last-state-change-time></mdt-receivers><last-state-change-time>2026-10-11T15:15:48.96532+00:00</last-state-change-time></mdt-subscriptions></mdt-oper-data></data></rpc-reply>購読の一覧は 1 件で、CLI の detail と同じ値(stream・encoding・period・xpath・dynamic・valid・receiver)をモデルの形で返しています。〔ツール側〕クライアントが受けた順に振った保存の番号(購読の後も同じチャネルを読み続け、届いた XML を最上位の要素の notification と rpc-reply で分けて保存)では、要求 → 通知(5 本目の push-update)→ rpc-reply の順でした。機器の hello が interleave:1.0 を名乗っていたこと(クライアントの hello は名乗っていない。§4.1)と、この観測との関係は確かめていません(§10)。
5.4 delete-subscription — 購読の削除
draft-ietf-netconf-yang-push-04 は、establish-subscription で作った購読は delete-subscription で消し、その入力は subscription-id だけだと書いています。
To stop receiving updates from a subscription and effectively delete a subscription that had previously been established using an establish-subscription RPC, a subscriber can send a delete- subscription RPC, which takes as only input the subscription-id.
〔ツール側〕WSL のクライアントが CSR1(csr1000v 17.03.08a)へ送った削除の要求は以下のとおりです。
#271
<?xml version="1.0" encoding="UTF-8"?>
<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="103">
<delete-subscription xmlns="urn:ietf:params:xml:ns:yang:ietf-event-notifications">
<subscription-id>2147483648</subscription-id>
</delete-subscription>
</rpc>
##CSR1(csr1000v 17.03.08a)の応答は notif-bis:ok で、subscription-id の要素はありません。
<?xml version="1.0" encoding="UTF-8"?>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="103"><subscription-result xmlns='urn:ietf:params:xml:ns:yang:ietf-event-notifications' xmlns:notif-bis="urn:ietf:params:xml:ns:yang:ietf-event-notifications">notif-bis:ok</subscription-result>
</rpc-reply>削除の後(show clock 15:16:34.800)の show telemetry ietf subscription all は空で(§3.3 と同じ形)、購読の行も Telemetry subscription brief の行もありませんでした。〔ツール側〕削除の応答の後、次の B2 の要求までの間に、保存された通知は 0 本です。
5.5 章の例の memory(B2・対照)
B2 は、17.3 の章が設定購読の CLI の例に使う memory の xpath を、同じ period 1000 で購読したものです(章の例・対照。7-2 では読んでいないパス)。結果は以下のとおりです。
| 項目 | B1(ietf の統計) | B2(memory・章の例) |
|---|---|---|
| subscription-id | 2147483648 | 2147483649 |
| 通知の本数 | 5 本 | 5 本 |
| eventTime の差 | 9.84・9.99・10.02・10.03 秒 | 9.95・10.00・10.01・9.99 秒 |
| 1 本の通知の中の行 | Loopback0 の statistics 1 つ | <memory-statistic> 3 個(Processor・reserve Processor・lsmpi_io) |
| receiver の Connection | 0 | 1 |
| receiver の Address・Port | 192.168.1.50・59878 | 同じ |
B2 の 5 本は、eventTime の値を除いて同じ中身でした。receiver の Connection の値が B1 で 0・B2 で 1 だった意味は確かめていません。
5.6 period 50 — 下限より小さい period(B3)
B3 は、B1 と同じ xpath で period を 50 にした要求です。CSR1(csr1000v 17.03.08a)の応答は notif-bis:error-insufficient-resources で、subscription-id の要素はありません。
<?xml version="1.0" encoding="UTF-8"?>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="106"><subscription-result xmlns='urn:ietf:params:xml:ns:yang:ietf-event-notifications' xmlns:notif-bis="urn:ietf:params:xml:ns:yang:ietf-event-notifications">notif-bis:error-insufficient-resources</subscription-result>
</rpc-reply>同じ時間帯の syslog には、period の下限の文言を持つ行が 1 行ありました。CSR1(csr1000v 17.03.08a)の show logging | include MDT は以下のとおりです。
CSR1# show logging | include MDT
*Oct 11 15:17:31.611: %MDT_SUBSCRIPTION-4-OUTSIDE_LIMIT: R0/0: pubd: Subscription creation failed (stream yang-push, id none, client 192.168.1.50:59878): Value '50' below limit for parameter 'period' (must be greater than or equal to 100).syslog の行の下限(100 以上)は、§5.2 の章の最小値 100 と同じ数です。17.3 の章の表は、error-insufficient-resources の原因に 3 つを挙げ、その 1 つが periodic の間隔が小さすぎる場合です(§5.1)。ただし応答の値は、どの原因に当たるかを示しません。syslog の行は id none で、購読の id では B3 と結べません。行の client の組(192.168.1.50:59878)は、§5.3 の B1 の receiver の Address・Port と、同じ組の認証の行(AUTH_PASSED)と同じで、同じクライアントの端点からの要求だったことまでは言えます(B3 の前後には show clock を撮っていません)。
5.7 購読中の close-session(B4)
B4 は、別の NETCONF のセッション(session-id 37)で B1 と同じ購読を作り、購読を消さずに <close-session> でセッションを閉じたものです。17.3 の章は、親の NETCONF のセッションが切れると購読も消えると書いています。
A subscription is also deleted when the parent NETCONF session is torn down or disconnected.
RFC 5277 も、購読をセッションの寿命に結び付けています。
Subscription: An agreement and method to receive event notifications over a NETCONF session. A concept related to the delivery of notifications (if there are any to send) involving destination and selection of notifications. It is bound to the lifetime of a session.
B4 の購読 2147483650 の応答は notif-bis:ok で、このセッションで受けた通知は 1 本(eventTime 15:17:32.65Z)でした。close-session の応答は <ok/> です。CSR1(csr1000v 17.03.08a)の close の前後の時刻と購読一覧を並べると、以下のとおりです。
| 段 | show clock | show telemetry ietf subscription all |
|---|---|---|
| close の前 | 15:17:37.856 | 2147483650 の行(Dynamic・Valid・xpath) |
| close の後 1 | 15:17:45.076 | 空(Telemetry subscription brief の行も無い) |
| close の後 2 | 15:17:54.499 | 空(Telemetry subscription brief の行も無い) |
| close の後 3 | 15:18:03.911 | 空(Telemetry subscription brief の行も無い) |
close の後の 3 回とも、2147483650 の行はありませんでした。購読が一覧から消えた時刻そのものは撮っていません(一覧の表示に時刻は無い)。close-session の前の一覧(CSR1 17.03.08a)は以下のとおりです。
CSR1# show telemetry ietf subscription all
Telemetry subscription brief
ID Type State Filter type
--------------------------------------------------------
2147483650 Dynamic Valid xpath 6. NETCONF の動的購読(on-change)
6.1 候補 7 本と応答
on-change の購読を、CSR1(csr1000v 17.03.08a)の 1 本の NETCONF のセッション(session-id 39)で、候補を 1 本ずつ送って試しました。dampening-period(§2.3 の dampening period)は C7 だけ 100 で、他は 0 です。結果は以下のとおりです。
| 候補 | xpath | 何の木か | dampening-period | 応答 |
|---|---|---|---|---|
| C1 | /if:interfaces/interface[name="Loopback0"] | ietf-interfaces の設定(7-2 で読んだパス) | 0 | notif-bis:error-other |
| C2 | /ios:native/interface/Loopback[name="0"] | Cisco native の設定(7-2 で読んだパス) | 0 | notif-bis:ok(2147483651) |
| C3 | /if:interfaces-state/interface[name="Loopback0"] | ietf-interfaces の状態(7-2 で読んだパス) | 0 | notif-bis:error-other |
| C4 | /interfaces-ios-xe-oper:interfaces/interface[name="Loopback0"] | Cisco の状態のモデル(対照) | 0 | notif-bis:error-no-such-option |
| C5 | /cdp-ios-xe-oper:cdp-neighbor-details/cdp-neighbor-detail | CDP(章の例) | 0 | notif-bis:ok(2147483652) |
| C6 | /memory-ios-xe-oper:memory-statistics/memory-statistic | memory(章の例) | 0 | notif-bis:error-no-such-option |
| C7 | C2 と同じ | Cisco native の設定 | 100 | rpc-error(invalid-value) |
受理されたのは C2 と C5 の 2 本でした。7-2 で読んだパスのうち候補にした 3 つ(C1〜C3)では、受理は native の設定(C2)だけで、ietf-interfaces の設定(C1)と状態(C3)は拒否です。7-2 で読んだ OpenConfig の interfaces のパスは、CSR1 の on-change の候補(C1〜C7)に入れていません(§10)。17.3 の章は、on-change で購読できるデータかどうかはモデルに示されておらず、購読できないデータへの要求は、動的購読なら失敗になると書いています。
Currently, there is no indication within YANG models about the type of data that can be subscribed to, by using an on-change subscription. Attempts to subscribe to data that cannot be subscribed to by using on-change subscription results in a failure (dynamic) or an invalid subscription (configured).
同じ章は、設定購読の管理の節で、on-change の購読に対応する YANG モデルの一覧を表示するコマンドを挙げています。本ラボでは、このコマンドを CSR1 で打っていません(§10)。
Use the show platform software ndbman switch {switch-number | active | standby} models command to display the list of YANG models that support on-change subscription.
C5 は 17.3 の章の on-change の動的購読の例と同じ xpath です。章の例は以下のとおりです(17.3 の MDT 章の本文。出典層)。
…(省略)
<establish-subscription xmlns="urn:ietf:params:xml:ns:yang:ietf-event-notifications"
xmlns:yp="urn:ietf:params:xml:ns:yang:ietf-yang-push">
<stream>yp:yang-push</stream>
<yp:xpath-filter>/cdp-ios-xe-oper:cdp-neighbor-details/cdp-neighbor-detail</yp:xpath-filter>
<yp:dampening-period>0</yp:dampening-period>
</establish-subscription>
…(省略)6.2 C2 — 初回の同期と 3 つの変更
〔ツール側〕WSL のクライアントが CSR1(csr1000v 17.03.08a)へ送った C2 の要求は以下のとおりです。B1 と違い、period の代わりに dampening-period を置いています。
#440
<?xml version="1.0" encoding="UTF-8"?>
<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="102">
<establish-subscription xmlns="urn:ietf:params:xml:ns:yang:ietf-event-notifications" xmlns:yp="urn:ietf:params:xml:ns:yang:ietf-yang-push">
<stream>yp:yang-push</stream>
<yp:xpath-filter>/ios:native/interface/Loopback[name="0"]</yp:xpath-filter>
<yp:dampening-period>0</yp:dampening-period>
</establish-subscription>
</rpc>
##CSR1(csr1000v 17.03.08a)の応答は notif-bis:ok と subscription-id 2147483651 で、CLI の detail は以下のとおりでした。
CSR1# show telemetry ietf subscription 2147483651 detail
Telemetry subscription detail:
Subscription ID: 2147483651
Type: Dynamic
State: Valid
Stream: yang-push
Filter:
Filter type: xpath
XPath: /ios:native/interface/Loopback[name="0"]
Update policy:
Update Trigger: on-change
Synch on start: Yes
Dampening period: 0
Encoding: encode-xml
Source VRF:
Source Address:
Notes:
Receivers:
Address Port Protocol Protocol Profile
-----------------------------------------------------------------------------------------
192.168.1.50 59874 netconf Receivers の 192.168.1.50 と 59874 の組は、後始末の確認(Phase Z)で撮った CSR1 の syslog の %DMI-5-AUTH_PASSED の行(15:18:12.882・netconf over ssh の認証。§5.3 と同じ形)の接続元と同じです。detail には Synch on start: Yes の表示がありました。draft-ietf-netconf-yang-push-04 は、on-change の購読の開始時にも push-update を送り、受信側の同期に使うと書いています(no-synch-on-start は、§4.3 のとおり本機の deviation で not-supported です)。
The notification can also be used in an on-change subscription for the purposes of allowing a receiver to “synch”. Specifically, it is used at the start of an on-change subscription, unless no-synch-on- start is specified for the subscription.
17.3 の章は、on-change の最初の push update は購読したデータの全体で、以後は変わったデータだけが送られ、変化の最小の単位は行 (row) だと書いています。
With on-change subscriptions, the first push update is the entire set of subscribed to data (the initial sychronization as defined in the IETF documents). This is not controllable. Subsequent updates are sent when the data changes, and consist of only the changed data. However, the minimum data resolution for a change is a row. So, if an on-change subscription is to a leaf within a row, if any item in that row changes, an update notification is sent.
C2 の受理の後、要求を送らずに届いた最初の通知は push-update でした。CSR1(csr1000v 17.03.08a)が送った初回の通知は以下のとおりです。
<?xml version="1.0" encoding="UTF-8"?>
<notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>2026-10-11T15:18:18.09Z</eventTime><push-update xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push"><subscription-id>2147483651</subscription-id><datastore-contents-xml><native xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-native"><interface><Loopback><name>0</name><description>initial</description><ip><address><primary><address>10.7.3.1</address><mask>255.255.255.255</mask></primary></address></ip></Loopback></interface></native></datastore-contents-xml></push-update></notification>中身は購読した Loopback 0 の全体(description initial と IP 10.7.3.1/32)で、<shutdown/> はありません。この後、CLI で Loopback0 に 3 つの変更を 1 つずつ入れました。1 つ目の CSR1(csr1000v 17.03.08a)の投入のエコーは以下のとおりです(2 つ目と 3 つ目は shutdown と no shutdown の行が違うだけです)。
configure terminal
Enter configuration commands, one per line. End with CNTL/Z.
CSR1(config)#interface Loopback0
CSR1(config-if)#description onchange-c2-1
CSR1(config-if)#end
CSR1#変更ごとに、push-change-update が 1 本ずつ届きました。1 つ目の変更(description)の後に CSR1(csr1000v 17.03.08a)が送った通知は以下のとおりです。
<?xml version="1.0" encoding="UTF-8"?>
<notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>2026-10-11T15:18:36.22Z</eventTime><push-change-update xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push"><subscription-id>2147483651</subscription-id><datastore-changes-xml><yang-patch xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-patch"><patch-id>null</patch-id><edit><edit-id>edit1</edit-id><operation>merge</operation><target>/native/interface/Loopback=0</target><value><Loopback xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-native"><description>onchange-c2-1</description></Loopback></value></edit></yang-patch></datastore-changes-xml></push-change-update></notification>2 つ目の変更(shutdown)の後に CSR1(csr1000v 17.03.08a)が送った通知は以下のとおりです。
<?xml version="1.0" encoding="UTF-8"?>
<notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>2026-10-11T15:18:57.25Z</eventTime><push-change-update xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push"><subscription-id>2147483651</subscription-id><datastore-changes-xml><yang-patch xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-patch"><patch-id>null</patch-id><edit><edit-id>edit1</edit-id><operation>merge</operation><target>/native/interface/Loopback=0</target><value><Loopback xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-native"><shutdown/></Loopback></value></edit></yang-patch></datastore-changes-xml></push-change-update></notification>3 つ目の変更(no shutdown)の後に CSR1(csr1000v 17.03.08a)が送った通知は以下のとおりです。
<?xml version="1.0" encoding="UTF-8"?>
<notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>2026-10-11T15:19:18.30Z</eventTime><push-change-update xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push"><subscription-id>2147483651</subscription-id><datastore-changes-xml><yang-patch xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-patch"><patch-id>null</patch-id><edit><edit-id>edit1</edit-id><operation>delete</operation><target>/native/interface/Loopback=0</target><value><Loopback xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-native"><shutdown/></Loopback></value></edit></yang-patch></datastore-changes-xml></push-change-update></notification>3 本の push-change-update を並べると、以下のとおりです。
| 変更 | edit の operation | value の中身 | eventTime |
|---|---|---|---|
| description onchange-c2-1 | merge | <description>onchange-c2-1</description> | 15:18:36.22Z |
| shutdown | merge | <shutdown/> | 15:18:57.25Z |
| no shutdown | delete | <shutdown/>(delete の edit にも value がある) | 15:19:18.30Z |
3 本とも、patch-id は null、edit は 1 個で、edit-id は edit1、target は /native/interface/Loopback=0 でした。中身は変わった部分だけで、description の変更の通知に IP は入っておらず、shutdown の通知に description は入っていません。no shutdown の通知は、operation が delete で value に <shutdown/> を持つ edit でした。
draft-ietf-netconf-yang-push-04 は、push-change-update のデータの断片の形を YANG-patch に従うものとしています。
The format of the data snippet follows YANG-patch [I-D.ietf-netconf-yang-patch], i.e. the same format that would be used with a YANG-patch operation to apply changes to a data tree, indicating the creates, deletes, and modifications of data nodes.
YANG Patch を定める RFC 8072 は、YANG Patch を edit の順序付きのリストと定義し、操作を 7 種としています。各 edit は edit-id で識別され、操作を 1 つ持ちます。
A “YANG Patch” is an ordered list of edits that are applied to the target datastore by the RESTCONF server.
There are seven operations supported (“create”, “delete”, “insert”, “merge”, “move”, “replace”, and “remove”).
Each edit is identified by an “edit-id”, and it has an edit operation (“create”, “delete”, “insert”, “merge”, “move”, “replace”, or “remove”) that is applied to the target resource.
同じ RFC の ietf-yang-patch の module は、delete の操作と、edit の value の欄を次のように定めています(RFC 8072 の module の本文。出典層)。
…(省略)
enum delete {
description
"Delete the target node, only if the data resource
currently exists; otherwise, return an error.";
}
…(省略)
anydata value {
when "../operation = 'create' "
+ "or ../operation = 'merge' "
+ "or ../operation = 'replace' "
+ "or ../operation = 'insert'" {
description
"The anydata 'value' is only used for 'create',
'merge', 'replace', and 'insert' operations.";
}
…(省略)RFC 8072 は YANG Patch 全体を一意の patch-id で識別すると書いています。
A YANG Patch is identified by a unique “patch-id”, and it may have an optional comment.
本機の 3 本の edit と、RFC 8072 の定めを並べると、次のとおりです。
- 本機の 3 本の patch-id は、どれも
nullでした - 本機の 3 本目の edit(no shutdown の後)は、operation が delete・target が
/native/interface/Loopback=0・value が<shutdown/>でした - RFC 8072 の module は、delete を target の節点を消す操作とし、value を create・merge・replace・insert の時だけ使う欄としています
- 3 つの変更の後の CSR1 の Loopback0 には、description と IP が残り、
shutdownの行はありませんでした(下の出力)
RFC 8072 は RESTCONF を対象とする定義で、draft が参照するのは YANG-patch の Internet-Draft です。本ラボは、本機の通知の形(patch-id の null と、value を持つ delete の edit)を RFC 8072 で検証しておらず、本機が no shutdown の edit をどの意味で送ったかも確かめていません(§10)。Phase C の最後に撮った CSR1(csr1000v 17.03.08a)の Loopback0 は以下のとおりです。
CSR1# show running-config interface Loopback0
Building configuration...
Current configuration : 91 bytes
!
interface Loopback0
description onchange-c2-1
ip address 10.7.3.1 255.255.255.255
endCLI の時刻と通知の時刻を並べると、以下のとおりです(どれも機器の時計。差を遅れとは扱いません)。
| 変更 | 投入の前の show clock | 通知の eventTime | syslog の %SYS-5-CONFIG_I |
|---|---|---|---|
| description | 15:18:28.245 | 15:18:36.22 | 15:18:39.065 |
| shutdown | 15:18:49.285 | 15:18:57.25 | 15:19:00.100 |
| no shutdown | 15:19:10.318 | 15:19:18.30 | 15:19:21.133 |
3 組とも、通知の eventTime は同じ組の CONFIG_I の行の時刻より前でした。show clock は投入の前に撮った時刻で、変更が機器に入った時刻そのものは撮っていません。
機器の ietf-yang-push の本文は push-change-update に time-of-update の leaf を持ちますが、届いた 3 本に time-of-update と updates-not-sent の要素はありませんでした。C2 は最後に delete-subscription で消し、応答は notif-bis:ok でした。
6.3 C5 — 章の例の CDP
C5(章の例の CDP)も受理され、Synch on start: Yes・Dampening period: 0 でした。CSR1(csr1000v 17.03.08a)が送った初回の push-update は、中身が空の <datastore-contents-xml/> でした。
<?xml version="1.0" encoding="UTF-8"?>
<notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>2026-10-11T15:19:45.18Z</eventTime><push-update xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push"><subscription-id>2147483652</subscription-id><datastore-contents-xml/></push-update></notification>17.3 の章は、同じ on-change の節で、現在存在しないデータへの購読も受け付けられ、その初回の同期の通知は空で、データが現れるまで以後の更新は無いと書いています。
Subscriptions for data that does not currently exist are permitted and run as normal subscriptions. The initial synchronization update notification is empty and there are no further updates until data is available.
ただし、CSR1 に CDP の隣接があったかは撮っておらず、章の条件(データが現在存在しない)に C5 が当たるかは確かめていません。この引用は、C5 の初回が空だった理由の説明には使いません。C5 には変更を入れず、delete-subscription で消したので、「以後の更新は無い」の側も試していません。
6.4 拒否 — error-other と error-no-such-option
拒否の応答は 2 種でした(値の定義は §5.1)。ietf-interfaces の設定(C1)と状態(C3)は notif-bis:error-other で、Cisco の状態のモデル(C4)と memory(C6)は notif-bis:error-no-such-option です。C1 の応答(CSR1 17.03.08a)は以下のとおりです。
<?xml version="1.0" encoding="UTF-8"?>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="101"><subscription-result xmlns='urn:ietf:params:xml:ns:yang:ietf-event-notifications' xmlns:notif-bis="urn:ietf:params:xml:ns:yang:ietf-event-notifications">notif-bis:error-other</subscription-result>
</rpc-reply>C4 の応答(CSR1 17.03.08a)は以下のとおりです。
<?xml version="1.0" encoding="UTF-8"?>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="105"><subscription-result xmlns='urn:ietf:params:xml:ns:yang:ietf-event-notifications' xmlns:notif-bis="urn:ietf:params:xml:ns:yang:ietf-event-notifications">notif-bis:error-no-such-option</subscription-result>
</rpc-reply>同じ時間帯の syslog には、on-change の拒否の文言を持つ %MDT_SUBSCRIPTION-4-NOT_SUPPORTED の行が 2 行ありました。CSR1(csr1000v 17.03.08a)の show logging | include MDT|CONFIG_I は以下のとおりです(6〜8 行目の CONFIG_I は §6.2 の 3 つの変更の投入の時間帯の行)。
CSR1# show logging | include MDT|CONFIG_I
*Oct 11 15:12:44.981: %SYS-5-CONFIG_I: Configured from console by netops on vty0 (192.168.1.50)
*Oct 11 15:14:55.144: %SYS-5-CONFIG_I: Configured from console by netops on vty0 (192.168.1.50)
*Oct 11 15:15:05.972: %SYS-5-CONFIG_I: Configured from console by netops on vty0 (192.168.1.50)
*Oct 11 15:17:31.611: %MDT_SUBSCRIPTION-4-OUTSIDE_LIMIT: R0/0: pubd: Subscription creation failed (stream yang-push, id none, client 192.168.1.50:59878): Value '50' below limit for parameter 'period' (must be greater than or equal to 100).
*Oct 11 15:18:39.065: %SYS-5-CONFIG_I: Configured from console by netops on vty0 (192.168.1.50)
*Oct 11 15:19:00.100: %SYS-5-CONFIG_I: Configured from console by netops on vty0 (192.168.1.50)
*Oct 11 15:19:21.133: %SYS-5-CONFIG_I: Configured from console by netops on vty0 (192.168.1.50)
*Oct 11 15:19:42.898: %MDT_SUBSCRIPTION-4-NOT_SUPPORTED: R0/0: pubd: Subscription creation failed (stream yang-push, id none, client 192.168.1.50:59874): Value 'on-change' for parameter 'update-trigger' is not supported by the specified filter (supported values include 'periodic').
*Oct 11 15:20:10.791: %MDT_SUBSCRIPTION-4-NOT_SUPPORTED: R0/0: pubd: Subscription creation failed (stream yang-push, id none, client 192.168.1.50:59874): Value 'on-change' for parameter 'update-trigger' is not supported by the specified filter (supported values include 'periodic').syslog の行には購読の識別子が無い(id none)ので、候補ごとの show clock の窓に時刻で当てはめました。
| 候補 | 窓(その候補の前の show clock から次の候補の前まで) | 窓の中の %MDT_SUBSCRIPTION の行 | 応答 |
|---|---|---|---|
| C1 | 15:18:13.483〜15:18:15.738 | 無し | error-other |
| C2 | 15:18:15.738〜15:19:38.440 | 無し(CONFIG_I の 3 行だけ) | ok |
| C3 | 15:19:38.440〜15:19:40.690 | 無し | error-other |
| C4 | 15:19:40.690〜15:19:42.942 | NOT_SUPPORTED 15:19:42.898 | error-no-such-option |
| C5 | 15:19:42.942〜15:20:08.572 | 無し | ok |
| C6 | 15:20:08.572〜15:20:10.828 | NOT_SUPPORTED 15:20:10.791 | error-no-such-option |
| C7 | 15:20:10.828〜 | 無し | rpc-error |
窓の中に NOT_SUPPORTED の行があったのは、error-no-such-option を返した C4 と C6 でした。2 行の文言は「指定したフィルタでは update-trigger の値 on-change が対応しておらず、対応する値に periodic がある」という内容で、client の port 59874 は C2・C5 の detail の Receivers の Port と同じ数字です。error-other を返した C1・C3 の窓には、この絞り込み(MDT|CONFIG_I)で見える行がありません。応答の値が 2 種に分かれた理由は撮っていません。
表の「無し」と、上の段落の「見える行がありません」は、上の show logging | include MDT|CONFIG_I に出たバッファの行についての観測です。後始末の確認(Phase Z)で撮った CSR1(csr1000v 17.03.08a)の show logging の冒頭と、バッファの設定の行は以下のとおりです。rate-limited の 3 件がいつのどの行で、バッファに入ったかどうかは、出力からは分かりません。バッファの level は informational で、大きさは 512000 でした(起動時の %SYS-5-LOG_CONFIG_CHANGE の行)。
CSR1# show logging
Syslog logging: enabled (0 messages dropped, 3 messages rate-limited, 0 flushes, 0 overruns, xml disabled, filtering disabled)
…(省略)
Buffer logging: level informational, 103 messages logged, xml disabled,
…(省略)
*Oct 11 15:08:54.485: %SYS-5-LOG_CONFIG_CHANGE: Buffer logging: level informational, xml disabled, filtering disabled, size (512000)
…(省略)6.5 dampening-period 100 — rpc-error(C7)
17.3 の章は、on-change の dampening period は 0 だけで、他の値は使えないと書いています。
When creating an on-change subscription, the dampening period must be set to 0 to indicate that there is no dampening period; no other value is supported.
C7 は、C2 と同じ xpath で dampening-period を 100 にした要求です。CSR1(csr1000v 17.03.08a)の応答は、subscription-result ではなく rpc-error でした。
<?xml version="1.0" encoding="UTF-8"?>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="109"><rpc-error>
<error-type>protocol</error-type>
<error-tag>invalid-value</error-tag>
<error-severity>error</error-severity>
<error-path xmlns:yp="urn:ietf:params:xml:ns:yang:ietf-yang-push" xmlns:notif-bis="urn:ietf:params:xml:ns:yang:ietf-event-notifications">
/rpc/notif-bis:establish-subscription/yp:dampening-period
</error-path><error-message xml:lang="en">"100" is out of range.</error-message><error-info><bad-element>dampening-period</bad-element>
</error-info>
</rpc-error>
</rpc-reply>error-tag は invalid-value、bad-element は dampening-period でした(0 と 100 以外の値は試していません。dampening period の定義は §2.3)。§4.3 の deviation は、establish-subscription の dampening-period の範囲を “0” に置き換えています。§6.4 の show logging | include MDT|CONFIG_I に、C7 の窓の時刻の行はありませんでした(rate-limited の件数は §6.4 の表の後)。
7. configured の購読と dial-out(gRPC・kvGPB)
7.1 gRPC の送り出しと受信器
17.3 の章は、gRPC を設定購読の送り出しだけに使え、gRPC の符号化は kvGPB だけと書いています。
The gRPC protocol is available only for the transport of configured subscriptions, and can be used with yang-push and yang-notif-native streams. Only kvGPB encoding is supported with gRPC transport protocol.
同じ制限の節は、TLS の認証について 2 行を並べています。1 行目は非対応、2 行目は Amsterdam 17.1.1 以降で対応と書いていて、2 行は 17.1.1 より前と後の対で読みます。本ラボの設定購読の receiver は grpc-tcp(§7.2)で、TLS は使っていません。
Transport Layer Security-based (TLS-based) authentication between a device and a receiver is not supported.
TLS-based authentication is supported in Cisco IOS XE Amsterdam 17.1.1 and later releases.
受け手には、kvGPB(key-value Google Protocol Buffers)を解釈できる gRPC のコレクタが要ります。メッセージの定義は 2 本の proto です。
Set up a gRPC collector that understands key-value Google Protocol Buffers (GPB) encoding.
For telemetry messages defined in .proto files, see: mdt_grpc_dialout.proto and telemetry.proto.
章のリンク先は cisco-ie/cisco-proto の proto/xe/ で、本ラボの受信器 mdt_receiver.py はこの版(commit 9cc3967c)の proto で復号しました。gRPC のサービスの定義は以下のとおりです(mdt_grpc_dialout.proto。出典層)。
syntax = "proto3";
// Package implements gRPC Model Driven Telemetry service
package mdt_dialout;
// gRPCMdtDialout defines service used for client-side streaming pushing MdtDialoutArgs.
service gRPCMdtDialout {
rpc MdtDialout(stream MdtDialoutArgs) returns(stream MdtDialoutArgs) {};
}
// MdtDialoutArgs is the content pushed to the server
message MdtDialoutArgs {
int64 ReqId = 1;
// data carries the payload content.
bytes data = 2;
string errors = 3;
}このコードは proto3 の形式です(1 行目の syntax = "proto3";)。service の中の rpc の行は、RPC の名前(MdtDialout)と、要求と応答のメッセージの型を並べています。message は欄の並びで、欄ごとに型・名前・番号を持ちます。stream については、同じファイルの注釈が、MdtDialoutArgs をクライアントの側から送り続けるサービスと書いています(gRPCMdtDialout の上の行)。§9.2 の gnmi.proto と §9.6 の SubscriptionList も、同じ読み方です。
受信器は、CSR1 から受けた MdtDialoutArgs の data のバイト列をそのまま 1 本ずつ .bin に残し、telemetry.proto(XE の版)の Telemetry のメッセージとして復号した形を .txt に書きました。受信器の stub は、この 2 本の proto から作りました。上の rpc の行の双方向のストリームの上で、受信器からは何も返していません。〔ツール側〕残したバイト列は、IOS XR の版の telemetry.proto(ios-xr/model-driven-telemetry の commit 11f88d8f の protos/24_2_2/telemetry.proto。照合だけに使った資料で、本文では引いていません)でも復号し、129 本すべてで両方の復号の結果が一致し、XE の版で未知のフィールドは 0 本でした(WSL の照合の道具 crosscheck_xr.py の出力「対象 129 本・一致 129 本・不一致か失敗 0 本」)。
〔ツール側〕D1 の設定の前に、COL の shell で受信器の待ち受け(57500)を確かめた出力は以下のとおりです。57599 の待ち受けの行はありません(57599 は 104 の receiver の port で、待ち受けを置いていません)。
LISTEN 0 4096 *:57500 *:* users:(("python3",pid=1212,fd=8))
{"kind": "listen", "recv_utc": "2026-10-11T15:20:19.920620Z", "listen": "0.0.0.0:57500", "grpcio": "1.84.0"}7.2 CLI で 101〜104 を設定する
設定購読は 4 本(101〜104)を 1 回の configure で入れました。CSR1(csr1000v 17.03.08a)の投入のエコーは以下のとおりです。
configure terminal
Enter configuration commands, one per line. End with CNTL/Z.
CSR1(config)#telemetry ietf subscription 101
CSR1(config-mdt-subs)# encoding encode-kvgpb
CSR1(config-mdt-subs)# filter xpath /if:interfaces-state/interface[name="Loopback0"]/statistics
CSR1(config-mdt-subs)# source-vrf Mgmt-vrf
CSR1(config-mdt-subs)# stream yang-push
CSR1(config-mdt-subs)# update-policy periodic 1000
CSR1(config-mdt-subs)# receiver ip address 172.16.1.242 57500 protocol grpc-tcp
CSR1(config-mdt-subs)#exit
CSR1(config)#telemetry ietf subscription 102
CSR1(config-mdt-subs)# encoding encode-kvgpb
CSR1(config-mdt-subs)# filter xpath /memory-ios-xe-oper:memory-statistics/memory-statistic
CSR1(config-mdt-subs)# source-vrf Mgmt-vrf
CSR1(config-mdt-subs)# stream yang-push
CSR1(config-mdt-subs)# update-policy periodic 1000
CSR1(config-mdt-subs)# receiver ip address 172.16.1.242 57500 protocol grpc-tcp
CSR1(config-mdt-subs)#exit
CSR1(config)#telemetry ietf subscription 103
CSR1(config-mdt-subs)# encoding encode-kvgpb
CSR1(config-mdt-subs)# filter xpath /ios:native/interface/Loopback[name="0"]
CSR1(config-mdt-subs)# stream yang-push
CSR1(config-mdt-subs)# update-policy on-change
CSR1(config-mdt-subs)# receiver ip address 10.7.31.2 57500 protocol grpc-tcp
CSR1(config-mdt-subs)#exit
CSR1(config)#telemetry ietf subscription 104
CSR1(config-mdt-subs)# encoding encode-kvgpb
CSR1(config-mdt-subs)# filter xpath /if:interfaces-state/interface[name="Loopback0"]/statistics
CSR1(config-mdt-subs)# source-vrf Mgmt-vrf
CSR1(config-mdt-subs)# stream yang-push
CSR1(config-mdt-subs)# update-policy periodic 1000
CSR1(config-mdt-subs)# receiver ip address 172.16.1.242 57599 protocol grpc-tcp
CSR1(config-mdt-subs)#exit
CSR1(config)#end
CSR1#4 本の違いは以下のとおりです。
| 購読 | xpath | 契機 | receiver | source-vrf | 確かめること |
|---|---|---|---|---|---|
| 101 | ietf の統計(B1 と同じ) | periodic 1000 | 172.16.1.242 57500 | Mgmt-vrf | Mgmt-vrf の経路での送り出し |
| 102 | memory(章の例・対照) | periodic 1000 | 172.16.1.242 57500 | Mgmt-vrf | 同じ受信器への 2 本目・表の行ごとのメッセージ |
| 103 | native の Loopback 0(C2 と同じ) | on-change | 10.7.31.2 57500 | 行なし(global) | on-change の送り出し・VRF の無い経路 |
| 104 | ietf の統計 | periodic 1000 | 172.16.1.242 57599 | Mgmt-vrf | 受信器が待ち受けていない port |
投入のエコーに % の行はありません。17.3 の章の設定購読の例は以下のとおりで、本ラボの 102 は、この例の xpath を使っています(17.3 の MDT 章の本文。出典層)。
…(省略)
telemetry ietf subscription 101
encoding encode-kvgpb
filter xpath /memory-ios-xe-oper:memory-statistics/memory-statistic
stream yang-push
update-policy periodic 6000
source-vrf Mgmt-intf
receiver ip address 10.28.35.45 57555 protocol grpc-tcp
…(省略)CSR1(csr1000v 17.03.08a)の running-config には 4 本がそのまま載り、xpath の中の二重引用符の前に \ が付いていました。
CSR1# show running-config | section telemetry
telemetry ietf subscription 101
encoding encode-kvgpb
filter xpath /if:interfaces-state/interface[name=\"Loopback0\"]/statistics
source-vrf Mgmt-vrf
stream yang-push
update-policy periodic 1000
receiver ip address 172.16.1.242 57500 protocol grpc-tcp
telemetry ietf subscription 102
encoding encode-kvgpb
filter xpath /memory-ios-xe-oper:memory-statistics/memory-statistic
source-vrf Mgmt-vrf
stream yang-push
update-policy periodic 1000
receiver ip address 172.16.1.242 57500 protocol grpc-tcp
telemetry ietf subscription 103
encoding encode-kvgpb
filter xpath /ios:native/interface/Loopback[name=\"0\"]
stream yang-push
update-policy on-change
receiver ip address 10.7.31.2 57500 protocol grpc-tcp
telemetry ietf subscription 104
encoding encode-kvgpb
filter xpath /if:interfaces-state/interface[name=\"Loopback0\"]/statistics
source-vrf Mgmt-vrf
stream yang-push
update-policy periodic 1000
receiver ip address 172.16.1.242 57599 protocol grpc-tcp7.3 購読一覧・detail・receiver
設定の前の show clock(15:20:22.788)から 138.469 秒後(15:22:41.257)の一覧では、4 本とも Configured・Valid でした。CSR1(csr1000v 17.03.08a)の一覧は以下のとおりです。
CSR1# show telemetry ietf subscription all
Telemetry subscription brief
ID Type State Filter type
--------------------------------------------------------
101 Configured Valid xpath
102 Configured Valid xpath
103 Configured Valid xpath
104 Configured Valid xpath 101 の detail は、§5.3 の動的購読と比べて Type: Configured・Encoding: encode-kvgpb・Source VRF: Mgmt-vrf・Receivers の Protocol grpc-tcp が違います。CSR1(csr1000v 17.03.08a)の 101 の detail は以下のとおりです。
CSR1# show telemetry ietf subscription 101 detail
Telemetry subscription detail:
Subscription ID: 101
Type: Configured
State: Valid
Stream: yang-push
Filter:
Filter type: xpath
XPath: /if:interfaces-state/interface[name="Loopback0"]/statistics
Update policy:
Update Trigger: periodic
Period: 1000
Encoding: encode-kvgpb
Source VRF: Mgmt-vrf
Source Address:
Notes:
Receivers:
Address Port Protocol Protocol Profile
-----------------------------------------------------------------------------------------
172.16.1.242 57500 grpc-tcp receiver の表示は以下のとおりです(CSR1 17.03.08a の 101)。
CSR1# show telemetry ietf subscription 101 receiver
Telemetry subscription receivers detail:
Subscription ID: 101
Address: 172.16.1.242
Port: 57500
Protocol: grpc-tcp
Profile:
Connection: 5
State: Connected
Explanation: 4 本の receiver を並べると、以下のとおりです。
| 購読 | Address | Port | Connection | State |
|---|---|---|---|---|
| 101 | 172.16.1.242 | 57500 | 5 | Connected |
| 102 | 172.16.1.242 | 57500 | 5 | Connected |
| 103 | 10.7.31.2 | 57500 | 6 | Connected |
| 104 | 172.16.1.242 | 57599 | 65535 | Connecting |
State: Connecting は 104 の 1 本だけでした。
7.4 機器が接続を張る — internal connection と受信器の open
show telemetry internal connection は、機器から受信器への接続の表です。CSR1(csr1000v 17.03.08a)の表示は以下のとおりです。
CSR1# show telemetry internal connection
Telemetry connections
Index Peer Address Port VRF Source Address State
----- -------------------------- ----- --- -------------------------- ----------
5 172.16.1.242 57500 1 172.16.1.241 Active
6 10.7.31.2 57500 0 10.7.31.1 Active
7 172.16.1.242 57599 1 172.16.1.241 ConnectingIndex 5 は Peer 172.16.1.242・Source 172.16.1.241(Gi1・vrf Mgmt-vrf)、Index 6 は Peer 10.7.31.2・Source 10.7.31.1(Gi2・後始末の確認(Phase Z)の running-config に vrf の行が無い IF)でした。receiver の Connection の値は、101 と 102 がどちらも 5、103 が 6 で、表の Index と同じ番号です。Peer 172.16.1.242・Port 57500 の行は Index 5 の 1 行だけでした。
〔ツール側〕受信器の記録(events.jsonl)では、接続の相手(peer)は CSR1 の側のアドレスでした。open の行は 3 行で、172.16.1.241 が 2 回、10.7.31.1 が 1 回です。冒頭の 4 行は以下のとおりです(受信器の記録。ツール側)。
{"kind": "listen", "recv_utc": "2026-10-11T15:20:19.920620Z", "listen": "0.0.0.0:57500", "grpcio": "1.84.0"}
{"kind": "open", "recv_utc": "2026-10-11T15:20:47.670350Z", "peer": "ipv4:172.16.1.241:59377", "metadata": [["user-agent", "grpc-c++/1.14.1 grpc-c/6.0.0 (linux; chttp2; gladiolus)"], ["accept-encoding", "identity,gzip"]]}
{"kind": "msg", "seq": 1, "recv_utc": "2026-10-11T15:20:47.764189Z", "peer": "ipv4:172.16.1.241:59377", "req_id": 0, "data_len": 437, "data_sha256": "2249c04524cd0385ba7a5e9f53cc310c81de492590ae01bfb0308d3ccebe933e", "errors": "", "unknown_fields": false, "node_id_str": "CSR1", "subscription_id_str": "101", "encoding_path": "ietf-interfaces:interfaces-state/interface/statistics", "collection_id": 1, "msg_timestamp": 1791732047868, "collection_start_time": 1791732047868, "collection_end_time": 0, "kvgpb_top_fields": 1, "gpb_rows": 0}
{"kind": "msg", "seq": 2, "recv_utc": "2026-10-11T15:20:47.766217Z", "peer": "ipv4:172.16.1.241:59377", "req_id": 1, "data_len": 89, "data_sha256": "c000641148f5d081c43a3787d9baa1741b4ee9398233c1e8b713deca9eba4f2d", "errors": "", "unknown_fields": false, "node_id_str": "CSR1", "subscription_id_str": "101", "encoding_path": "ietf-interfaces:interfaces-state/interface/statistics", "collection_id": 1, "msg_timestamp": 1791732047898, "collection_start_time": 1791732047868, "collection_end_time": 1791732047898, "kvgpb_top_fields": 0, "gpb_rows": 0}
…(省略)〔ツール側〕open の 3 回の peer と、各購読の msg の peer は以下のとおりです。
| open の recv_utc(COL の時計) | peer | その peer の msg |
|---|---|---|
| 15:20:47.670350Z | ipv4:172.16.1.241:59377 | 101 の 44 本と 102 の 80 本は、どれもこの peer |
| 15:21:12.035251Z | ipv4:172.16.1.241:59377(1 回目と同じ文字列) | (同上) |
| 15:21:35.538607Z | ipv4:10.7.31.1:55151 | 103 の 5 本 |
101 と 102 について言えるのは、CLI の Connection: 5 が両方に出て Index 5 の行が 1 行であることと、受信器の 2 回の open の peer の文字列(port 59377 まで)が同じことまでです。2 本が 1 本の TCP の接続を使っているかは、パケットを撮っていないので確かめていません(§10)。受信器の記録の msg の行には、どの open(gRPC の呼び出し)に属するかの識別子もありません。
7.5 kvGPB のメッセージの形 — periodic
〔ツール側〕受信器が復号した 101 の 1 本目(collection_id 1 のデータ)は以下のとおりです。CSR1(csr1000v 17.03.08a)が送った kvGPB を、受信器が text_format で書いたものです。
node_id_str: "CSR1"
subscription_id_str: "101"
encoding_path: "ietf-interfaces:interfaces-state/interface/statistics"
collection_id: 1
collection_start_time: 1791732047868
msg_timestamp: 1791732047868
data_gpbkv {
timestamp: 1791732047868
fields {
name: "keys"
fields {
name: "name"
string_value: "Loopback0"
}
}
fields {
name: "content"
fields {
name: "discontinuity-time"
string_value: "2026-10-11T15:08:34+00:00"
}
fields {
name: "in-octets"
uint64_value: 0
}
…(省略)kvGPB は、YANG の節点の名前(name)と値の組を入れ子にした形で、list の key は keys、それ以外の葉は content の下に入っていました。encoding_path は ietf-interfaces:interfaces-state/interface/statistics で、モジュールの名前を接頭辞にしたパスです。〔ツール側〕同じ collection_id 1 の次の msg は、データを持たず、collection_end_time だけを持っていました(CSR1 17.03.08a が送ったもの・受信器の復号)。以下、この形の msg を「collection_end_time だけの msg」と呼びます。
node_id_str: "CSR1"
subscription_id_str: "101"
encoding_path: "ietf-interfaces:interfaces-state/interface/statistics"
collection_id: 1
collection_start_time: 1791732047868
msg_timestamp: 1791732047898
collection_end_time: 1791732047898telemetry.proto は、collection_id を 1 回の収集の印とし、collection_end_time を収集の最後のメッセージにだけ入れると書いています。時刻は epoch からのミリ秒です(telemetry.proto の注釈。出典層)。
…(省略)
// collection_id identifies messages belonging to a collection round.
// Multiple message may be generated from a collection round.
uint64 collection_id = 8;
//
// collection_start_time is the time when the collection identified by
// the collection_id begins - encoded as milliseconds since the epoch.
// If a single collection is spread over multiple Telemetry Messages,
// collection_start_time may be encoded in the first Telemetry Message
// for the collection only.
uint64 collection_start_time = 9;
//
// msg_timestamp is the time when the data encoded in the Telemetry
// message is generated - encoded as milliseconds since the epoch.
uint64 msg_timestamp = 10;
…(省略)
// collection_end_time is the timestamp when the last Telemetry message
// for a collection has been encoded - encoded as milliseconds since the
// epoch. If a single collection is spread over multiple Telemetry
// messages, collection_end_time is encoded in the last Telemetry Message
// for the collection only.
uint64 collection_end_time = 13;
…(省略)〔ツール側〕受信器の記録を購読ごとに数えると、以下のとおりです(129 本とも errors は空・unknown_fields は false)。
| 購読 | msg の本数 | collection_id | 1 回の収集の形 |
|---|---|---|---|
| 101(periodic・ietf の統計) | 44 | 1〜22 | データ 1 本 + collection_end_time だけの 1 本 |
| 102(periodic・memory) | 80 | 1〜20 | データ 3 本(keys が Processor・reserve Processor・lsmpi_io)+ collection_end_time だけの 1 本 |
| 103(on-change・native) | 5 | 1〜4 | 初回(1)= データ 1 本 + collection_end_time だけの 1 本 / 変更(2〜4)= collection_end_time を持つデータ 1 本 |
| 104 | 0 | — | — |
102 は、NETCONF の B2(§5.5)で 1 本の通知に 3 行が入っていたのと違い、kvGPB では表の行ごとに 1 本の msg に分かれていました。101 の collection_start_time の隣どうしの差は 9623〜10394(ミリ秒とみなすと 21 個とも四捨五入で 10 秒)、102 は 9988〜10018 でした。101 の数値の値は、どれも 0 です。
7.6 on-change の送り出し(103)
103 は §6 の C2 と同じ native の Loopback 0 を、on-change で 10.7.31.2 へ送り出す設定購読です。〔ツール側〕初回(collection_id 1)のデータには、§6.2 で入れた description onchange-c2-1 と IP 10.7.3.1 が入っていました。
この後、CLI で Loopback0 に description・shutdown・no shutdown を 1 つずつ入れました。1 つ目の CSR1(csr1000v 17.03.08a)の投入のエコーは以下のとおりです。
configure terminal
Enter configuration commands, one per line. End with CNTL/Z.
CSR1(config)#interface Loopback0
CSR1(config-if)#description onchange-dialout
CSR1(config-if)#end
CSR1#〔ツール側〕description の変更の後に受信器が受けた msg(collection_id 2)は以下のとおりです。CSR1(csr1000v 17.03.08a)が送った kvGPB で、collection_end_time を持つデータ 1 本でした。
node_id_str: "CSR1"
subscription_id_str: "103"
encoding_path: "Cisco-IOS-XE-native:native/interface/Loopback"
collection_id: 2
collection_start_time: 1791732194625
msg_timestamp: 1791732194625
data_gpbkv {
timestamp: 1791732194625
fields {
name: "keys"
fields {
name: "name"
uint32_value: 0
}
}
fields {
name: "content"
fields {
name: "description"
string_value: "onchange-dialout"
}
}
}
collection_end_time: 1791732194625中身は変わった description だけで、IP の field はありません。string_value: "onchange-dialout" を持つ msg は、129 本のうちこの 1 本だけでした。〔ツール側〕shutdown の後の msg(collection_id 3・CSR1 17.03.08a が送ったもの)は以下のとおりです。
node_id_str: "CSR1"
subscription_id_str: "103"
encoding_path: "Cisco-IOS-XE-native:native/interface/Loopback"
collection_id: 3
collection_start_time: 1791732215801
msg_timestamp: 1791732215801
data_gpbkv {
timestamp: 1791732215801
fields {
name: "keys"
fields {
name: "name"
uint32_value: 0
}
}
fields {
name: "content"
fields {
name: "shutdown"
}
}
}
collection_end_time: 1791732215801shutdown の field は値の行を持ちません。no shutdown の後の msg(collection_id 4)も、collection_id と時刻の行を除いて同じ形でした(data の長さはどちらも 131 バイト)。NETCONF の C2 では no shutdown が yang-patch の delete で区別されていましたが(§6.2)、kvGPB の 2 本の content は同じ形で、何で区別するのかは確かめていません。
msg_timestamp を telemetry.proto の注釈どおりにミリ秒の UNIX 時刻とみなして UTC に直すと、CLI の show clock との順は以下のとおりです(出力に単位の表示は無く、ミリ秒は proto の注釈に基づく仮定です)。
| 段 | 投入の前の show clock | 〔ツール側〕msg_timestamp を UTC に直した値 |
|---|---|---|
| description | 15:23:06.181 | 15:23:14.625(collection 2) |
| shutdown | 15:23:27.212 | 15:23:35.801(collection 3) |
| no shutdown | 15:23:48.256 | 15:23:56.234(collection 4) |
| 3 段の後 | 15:24:11.286 | — |
どの msg_timestamp も、その段の show clock と次の段の show clock の間に入りました。
7.7 受信器が待ち受けていない port(104)
104 は、受信器が待ち受けていない 57599 を receiver にした購読です。CSR1(csr1000v 17.03.08a)の 104 の receiver は以下のとおりです。
CSR1# show telemetry ietf subscription 104 receiver
Telemetry subscription receivers detail:
Subscription ID: 104
Address: 172.16.1.242
Port: 57599
Protocol: grpc-tcp
Profile:
Connection: 65535
State: Connecting
Explanation: detail の State は Valid のままで、receiver だけが Connecting でした。internal connection の Index 7(57599)も Connecting です。17.3 の章は、受信器への接続を gRPC の指数バックオフで再試行すると書いています。
Receiver connection retries based on gRPC protocol (exponential back-off) are supported.
本ラボは、104 の接続の試行の間隔と回数は撮っていません(§10)。
7.8 encode-xml の 105(D2)
17.3 の章の「gRPC は kvGPB だけ」に対して、本機が encode-xml の設定購読をどう扱うかを、101〜104 を消した後に 105 だけで撮りました(受信器は別の port 57501)。CSR1(csr1000v 17.03.08a)は、encoding encode-xml の行を % Invalid input で拒みました。
configure terminal
Enter configuration commands, one per line. End with CNTL/Z.
CSR1(config)#telemetry ietf subscription 105
CSR1(config-mdt-subs)# encoding encode-xml
^
% Invalid input detected at '^' marker.
CSR1(config-mdt-subs)# filter xpath /if:interfaces-state/interface[name="Loopback0"]/statistics
CSR1(config-mdt-subs)# source-vrf Mgmt-vrf
CSR1(config-mdt-subs)# stream yang-push
CSR1(config-mdt-subs)# update-policy periodic 1000
CSR1(config-mdt-subs)# receiver ip address 172.16.1.242 57501 protocol grpc-tcp
CSR1(config-mdt-subs)#exit
CSR1(config)#end
CSR1#残りの行は入り、running-config の 105 に encoding の行はありません。CSR1(csr1000v 17.03.08a)の running-config は以下のとおりです。
CSR1# show running-config | section telemetry
telemetry ietf subscription 105
filter xpath /if:interfaces-state/interface[name=\"Loopback0\"]/statistics
source-vrf Mgmt-vrf
stream yang-push
update-policy periodic 1000
receiver ip address 172.16.1.242 57501 protocol grpc-tcp設定の前の show clock(15:24:54.861)から 64.663 秒後(15:25:59.524)の detail は、State: Invalid・Encoding: encode-xml で、Notes に理由の文言がありました。CSR1(csr1000v 17.03.08a)の detail は以下のとおりです。
CSR1# show telemetry ietf subscription 105 detail
Telemetry subscription detail:
Subscription ID: 105
Type: Configured
State: Invalid
Stream: yang-push
Filter:
Filter type: xpath
XPath: /if:interfaces-state/interface[name="Loopback0"]/statistics
Update policy:
Update Trigger: periodic
Period: 1000
Encoding: encode-xml
Source VRF: Mgmt-vrf
Source Address:
Notes: Value 'encode-xml' not supported for parameter 'encoding' (supported values include 'encode-kvgpb').
Receivers:
Address Port Protocol Protocol Profile
-----------------------------------------------------------------------------------------
172.16.1.242 57501 grpc-tcp receiver は State: Disconnected・Explanation: Subscription invalid で、internal connection の表は空でした。〔ツール側〕57501 の受信器の記録には、待ち受けの開始(listen)と停止(stopped)の 2 行だけで、open と msg の行はありません。detail の Encoding: encode-xml が、拒まれた投入の行から来たのか、running-config に無い encoding の既定の表示なのかは確かめていません。
7.9 設定購読の削除
設定購読は、設定を消すと消えます。D1 の 4 本は no telemetry ietf subscription で消しました。CSR1(csr1000v 17.03.08a)の投入のエコーは以下のとおりです。
configure terminal
Enter configuration commands, one per line. End with CNTL/Z.
CSR1(config)#no telemetry ietf subscription 101
CSR1(config)#no telemetry ietf subscription 102
CSR1(config)#no telemetry ietf subscription 103
CSR1(config)#no telemetry ietf subscription 104
CSR1(config)#end
CSR1#削除の後の一覧は空でした。〔ツール側〕受信器の記録の close の行は 3 行で、messages の値(44・80・5)は購読ごとの msg の本数と同じ数です。draft-ietf-netconf-rfc5277bis-01 は、設定購読を RPC で変えることも消すこともできないと書いています。引用の後半が設定の操作(configuration operations)と対にしているとおり、ここでの RPC は動的購読を作り・変え・消す側の RPC の話です(本ラボは RPC での削除を試していません)。
Note that there is no mixing-and-matching of dynamic and configured subscriptions. Specifically, a configured subscription cannot be modified or deleted using RPC. Similarly, a subscription created via RPC cannot be modified through configuration operations.
8. dial-in と dial-out を並べる
§5 の B1(動的購読)と §7 の 101(設定購読)は、同じ CSR1(csr1000v 17.03.08a)の同じ xpath・同じ period 1000 の購読です。2 本を並べると、以下のとおりです。
| 項目 | B1(NETCONF の動的購読・dial-in) | 101(CLI の設定購読・dial-out) |
|---|---|---|
| 作り方 | WSL のクライアントが <establish-subscription> を送る | CLI で telemetry ietf subscription 101 を設定する |
| 接続を張る側 | クライアントが機器の NETCONF(SSH の TCP 830)へ | 機器(Source 172.16.1.241)が受信器(172.16.1.242:57500)へ |
| データが流れる経路 | 購読を作った NETCONF のセッションの上 | 機器が張った gRPC の接続の上 |
Type | Dynamic | Configured |
| receiver の Protocol | netconf(Address は 192.168.1.50) | grpc-tcp(Address は設定した受信器) |
Encoding | encode-xml(要求で指定せず) | encode-kvgpb(設定で指定) |
| 届く形 | <notification> の push-update(XML)1 本 | kvGPB のデータの msg 1 本 + collection_end_time だけの msg 1 本 |
| subscription-id | 2147483648(機器が付けた) | 101(設定で付けた) |
| 消え方 | delete-subscription・セッションの終了(B4) | 設定の削除 |
| VRF | — | source-vrf で選ぶ(103 は行なし = global の経路) |
どちらの購読も、成立した後は機器が要求を待たずに送り出しました。違いは、接続を張る側と、購読の寿命が何に結び付くかです。dial-in はクライアントが張った接続の上で通知が流れ、そのセッションが閉じると購読も消えました(§5.7)。dial-out は機器が受信器へ接続を張り、受信器が待ち受けていない間は Connecting のまま設定として残りました(§7.7)。
subscription-id の範囲も違いました。17.3 の章は、設定購読の id は 0〜2147483647 の範囲に収めるよう書いています。本ラボで機器が付けた動的購読の id は 2147483648〜2147483652 で、この範囲の外でした。
Controllers must limit the values they use for configured subscriptions in the range 0 to 2147483647 to avoid collisions with the dynamic subscriptions created on the publisher.
17.3 の章は、再起動とスイッチオーバーの後の扱いも 2 つで違うと書いています。dial-in は再起動の後に張り直しが要り(下の 1 文目)、dial-out は stateful switchover の後に自動で受信器へ接続し直します(2 文目)。
Dial-in subscriptions need to be reinitiated after a reload, because established connections or sessions are killed during stateful switchover.
Dial-out subscriptions are created as part of the device configuration, and they automatically reconnect to the receiver after a stateful switchover.
再起動(reload)の後の dial-out については、同じ章の注が条件を書いています。購読の設定を startup-config へ同期しておけば、再起動の後も購読の設定が機器に残る、という条件です。
In the event of a device reload, subscription configurations must be synchronized to the start-up configuration of a device. This ensures that after the device reboots, subscription configurations remain intact on the device.
本ラボは、再起動・スイッチオーバー・startup-config への保存のどれも試していません(§10)。
§9 の gNMI の Subscribe は、COL のクライアントが C9K へ接続を張る dial-in で、C9K の CLI でも Type: Dynamic と表示されました。
9. gNMI(cat9000v-uadp 17.15.03)
§9 の機器の出力は、すべて C9K(cat9000v-uadp 17.15.03)のものです。クライアントは COL の gnmic 0.49.0 と gnmi_sub.py で、宛先は 172.16.1.244:50052(--insecure)でした。gnmic の共通の指定は -a 172.16.1.244:50052 --insecure -u netops --timeout 30s で、出力の形(--format)と符号化(--encoding)を RPC ごとに付けました。gnmic の標準出力のブロックの 1 行目の COL $ の行が、取得の記録の見出しのコマンドです(標準エラーの側のブロックと gnmi_sub.py の記録には付けていません。その指定は §9.3 と §9.6 の表)。出典の Cisco のガイドは 17.15.x の版を当てます。
9.1 有効化 — gnxi と gnmib
17.15 の gNMI 章は、gnxi のコマンドを gNMI と gNOI の両方のサービスにかかわるものとし、gNxI をその道具の集まりと書いています。
The gnxi commands apply to both gNMI and gRPC Network Operations Interface (gNOI) services. gNxI tools are a collection of tools for Network Management that use the gNMI and gNOI protocols.
同じ章は、gnxi が gNxI のプロセスを起動し、gnxi server が insecure のモードのサーバを有効にし、その既定の port は 50052 と書いています。
Starts the gNxI process.
Enables the gNxI server in insecure mode.
The default insecure gNxI port is 50052.
同じ章の、insecure のモードで gNMI を有効にする節(ここまでの 4 つの引用も、この節の文です)は、Day Zero のセットアップでは、まず機器を insecure のモードで有効にし、それを無効にしてから secure のモードを有効にするよう書いています。insecure のモードの gNxI を止めるコマンドには no gnxi server を挙げています。
In a Day Zero setup, first enable the device in insecure mode, then disable it, and enable the secure mode. To stop gNxI in insecure mode, use the no gnxi server command.
同じ節の注は、insecure と secure のサーバを 1 台で同時に動かせるとも書いています。
gNxI insecure and secure servers can run simultaneously on a device.
本ラボは insecure のモードだけで撮りました(試していないことは §10.3)。§3 の day0 は本ラボの起動時の設定を指す呼び名で、上の引用の Day Zero とは別に使っています。
C9K の yang-management のプロセス一覧は、gnxi を入れる前は nginx だけが Running で、gnmib は Not Running でした。C9K(cat9000v-uadp 17.15.03)の表示は以下のとおりです。
C9K# show platform software yang-management process
confd : Not Running
nesd : Not Running
syncfd : Not Running
ncsshd : Not Running
dmiauthd : Not Running
nginx : Running
ndbmand : Not Running
pubd : Not Running
gnmib : Not Runningaaa の 3 行と gnxi・gnxi server を入れました。C9K(cat9000v-uadp 17.15.03)の投入のエコーに、拒否の行はありません。
configure terminal
Enter configuration commands, one per line. End with CNTL/Z.
C9K(config)#aaa new-model
C9K(config)#aaa authentication login default local
C9K(config)#aaa authorization exec default local
C9K(config)#gnxi
C9K(config)#gnxi server
C9K(config)#end
C9K#C9K には netconf-yang を入れていません(後始末の確認(Phase Z)の running-config に netconf-yang の行は 0 行。17.15 の章の注は NETCONF-YANG と gNXI のどちらかの設定を求めています。§2.1)。入れた後の C9K(cat9000v-uadp 17.15.03)の show gnxi state detail の冒頭と末尾は以下のとおりです。
C9K# show gnxi state detail
Settings
========
Server: Enabled
Server port: 50052
Secure server: Disabled
Secure server port: 9339
Secure client authentication: Disabled
Secure trustpoint:
Secure client trustpoint:
Secure password authentication: Disabled
GNMI
====
Admin state: Enabled
Oper status: Up
State: Provisioned
…(省略)
gRPC Tunnel
===========
Admin state: Enabled
Oper status: Upinsecure のモードのサーバ(50052)が有効で、secure のモードのサーバ(9339)は無効です。末尾は gRPC Tunnel の見出しと、その下の Admin state: Enabled・Oper status: Up の 2 行です。本ラボは gRPC Tunnel を撮っておらず、この 2 行が何を指すかは確かめていません(§10.3)。プロセス一覧は 9 行のうち 8 行が Running になり、gnmib も Running でした(Not Running は ncsshd の 1 行)。C9K(cat9000v-uadp 17.15.03)の gnxi の後の一覧は以下のとおりです。
C9K# show platform software yang-management process
confd : Running
nesd : Running
syncfd : Running
ncsshd : Not Running
dmiauthd : Running
nginx : Running
ndbmand : Running
pubd : Running
gnmib : Running syslog では、gnmi::broker の administrative state が 15:26:59.199 に DISABLED、CLI の投入(15:27:00.009)の後の 15:27:01.658 に ENABLED になり、operational status が UP になったのは 15:28:26.958 でした。その間の 15:28:22〜15:28:25 には、dmiauthd が running の設定を「NETCONF running data store」へ同期する行が出ています(netconf-yang を入れていない機器でこの行が出る理由は確かめていません)。17.15 の gNMI 章は、gNMI broker(GNMIB)の operational の状態を、障害の時に up から down へ変わるものとして書いています。
When a gNMI service failure occurs, the gNMI broker (GNMIB) will indicate an operational change of state from up to down, and all RPCs will return a service unavailable message until the database is up and running.
〔ツール側〕取得スクリプトは、投入の後、gnmib のプロセス・COL から 50052 への TCP・OpenConfig(以下 OC)の config の Get を繰り返し確かめてから、Capabilities に進みました(この確認の Get の応答は保存していません)。同じ時間帯の C9K(cat9000v-uadp 17.15.03)の syslog の抜粋は以下のとおりです。
C9K# show logging | include GNMIB|DMI|MDT|CONFIG_I
…(省略)
*Oct 11 15:27:01.658: %GNMIB-5-SRV_ADMIN_SCN: Switch 1 R0/0: gnmib: Component [ gnmi::broker ] administrative state: ENABLED
*Oct 11 15:27:06.977: %GNMIB-6-GRPC_CON_STATE: Switch 1 R0/0: gnmib: Received gRPC Connection from ipv4:172.16.1.242:56402 for RPC gNMI/Get
*Oct 11 15:27:06.978: %GNMIB-6-GRPC_CON_STATE: Switch 1 R0/0: gnmib: Received gRPC Disconnection from ipv4:172.16.1.242:56402 for RPC gNMI/Get
…(省略)
*Oct 11 15:28:26.958: %GNMIB-5-SRV_OPER_SCN: Switch 1 R0/0: gnmib: Component [ gnmi::broker ] operational status: UP
*Oct 11 15:28:33.589: %GNMIB-6-GRPC_CON_STATE: Switch 1 R0/0: gnmib: Received gRPC Connection from ipv4:172.16.1.242:50702 for RPC gNMI/Get
*Oct 11 15:28:33.639: %GNMIB-6-GRPC_CON_STATE: Switch 1 R0/0: gnmib: Received gRPC Disconnection from ipv4:172.16.1.242:50702 for RPC gNMI/Get
*Oct 11 15:28:38.133: %GNMIB-6-GRPC_CON_STATE: Switch 1 R0/0: gnmib: Received gRPC Connection from ipv4:172.16.1.242:50704 for RPC gNMI/Capabilities
…(省略)ENABLED の後、Capabilities の接続(15:28:38.133)の前に、COL からの Get の接続と切断の行が 8 対ありました。UP の行より前の 7 対は、どれも接続から 0.001〜0.002 秒で切断の行があり、UP の後の 1 対(15:28:33.589 と 15:28:33.639)の差は 0.050 秒でした。Get が通るようになった時刻と、UP の前の Get の応答の中身は確かめていません(§10)。
9.2 Capabilities — 0.7.0 を名乗る
Capabilities は、機器が対応するモデルと符号化と gNMI の版を返す RPC です。〔ツール側〕COL の gnmic 0.49.0 が描いた C9K(cat9000v-uadp 17.15.03)の応答の抜粋は以下のとおりです。
COL $ /home/labuser/bin/gnmic -a 172.16.1.244:50052 --insecure -u netops --timeout 30s --format prototext --log capabilities
…(省略)
supported_models: {
name: "Cisco-IOS-XE-mdt-capabilities-oper"
organization: "Cisco Systems, Inc."
version: "2022-11-01"
}
…(省略)
supported_models: {
name: "openconfig-interfaces"
organization: "OpenConfig working group"
version: "2.3.0"
}
…(省略)
supported_encodings: JSON
supported_encodings: JSON_IETF
supported_encodings: PROTO
gNMI_version: "0.7.0"〔ツール側〕supported_models は 304 件(名前の重複 0)で、Cisco-IOS-XE- 161・cisco-xe- 40・openconfig- 88・ietf- 14・iana-if-type 1 でした。一覧に名前があることは、そのモデルが使える証拠にはしません(使えたことは §9.3〜§9.6 の応答で示します)。C9K の syslog には、この RPC の接続と切断の行(for RPC gNMI/Capabilities)が 1 対ありました。
C9K は gNMI の版を 0.7.0 と名乗りました。一方、17.3 と 17.15 の gNMI 章は、どちらも 0.4.0 と書いています(17.15 の章の文は以下のとおり)。
The gNMI Protocol feature describes the model-driven configuration and retrieval of operational data using the gRPC Network Management Interface (gNMI) capabilities, and the Get, Set, and Subscribe remote procedure calls (RPCs). gNMI Version 0.4.0 is supported.
gNMI のサービスを定める gnmi.proto は、版の値を gnmi_service の option に持ち、Capabilities で返すと書いています。openconfig/gnmi の commit 00369d9 の gnmi.proto の該当部分は以下のとおりです(出典層)。
…(省略)
// gNMI_service is the current version of the gNMI service, returned through
// the Capabilities RPC.
option (gnmi_service) = "0.7.0";
…(省略)C9K の 0.7.0 は、この値と一致します。章が書く 0.4.0 は、commit 8a14ac0 の gnmi.proto の値と一致します(出典層)。
…(省略)
// gNMI_service is the current version of the gNMI service, returned through
// the Capabilities RPC.
option (gnmi_service) = "0.4.0";
…(省略)2 つの版の gnmi.proto は、どちらも同じ 4 つの RPC(Capabilities・Get・Set・Subscribe)を持ちます。0.7.0 の版の定義は以下のとおりです(出典層)。
…(省略)
service gNMI {
// Capabilities allows the client to retrieve the set of capabilities that
// is supported by the target. This allows the target to validate the
// service version that is implemented and retrieve the set of models that
// the target supports. The models can then be specified in subsequent RPCs
// to restrict the set of data that is utilized.
// Reference: gNMI Specification Section 3.2
rpc Capabilities(CapabilityRequest) returns (CapabilityResponse);
// Retrieve a snapshot of data from the target. A Get RPC requests that the
// target snapshots a subset of the data tree as specified by the paths
// included in the message and serializes this to be returned to the
// client using the specified encoding.
// Reference: gNMI Specification Section 3.3
rpc Get(GetRequest) returns (GetResponse);
// Set allows the client to modify the state of data on the target. The
// paths to modified along with the new values that the client wishes
// to set the value to.
// Reference: gNMI Specification Section 3.4
rpc Set(SetRequest) returns (SetResponse);
// Subscribe allows a client to request the target to send it values
// of particular paths within the data tree. These values may be streamed
// at a particular cadence (STREAM), sent one off on a long-lived channel
// (POLL), or sent as a one-off retrieval (ONCE).
// Reference: gNMI Specification Section 3.5
rpc Subscribe(stream SubscribeRequest) returns (stream SubscribeResponse);
}
…(省略)以下の仕様の文の引用は、gNMI の仕様の文書の Version 0.4.0 のものです(C9K が名乗る版は 0.7.0 で、版が違います)。
9.3 Get — パスの接頭辞と origin
Get は、データの木の一部の写しを返す RPC です(仕様の文書 0.4.0)。
In some cases, a client may require a snapshot of the state that exists on the target. In such cases, a client desires some subtree of the data tree to be serialized by the target and transmitted to it. It is expected that the values that are retrieved (whether writeable by the client or not) are collected immediately and provided to the client.
gNMI のパスの書き方は、Path の origin の欄(§2.5)の値ごとに違います。17.15 の gNMI 章の「gNMI Namespace」は、origin ごとの接頭辞の付け方を次のように定めています。
A namespace specifies the path prefixing to be used in the origin field of a message.
RFC 7951-specified namespaces: Path prefixes use the YANG module name as defined in RFC 7951.
Openconfig: No path prefixes are used. These can only be used with a path to an openconfig model.
Blank: Same as the openconfig prefix. This is the default.
Here, path prefixing uses the YANG module prefix as defined in the YANG module definition.
最後の文は、16.10.1 より前のリリースの書き方(legacy)の節の文です。
This section describes the path prefixing used in releases prior to Cisco IOS XE Gibraltar 16.10.1.
まず、7-2 で読んだ OpenConfig の Loopback0 の config を、origin を付けないパス(上の Blank)で読みました(gnmic の指定は --encoding json_ietf)。〔ツール側〕gnmic が描いた C9K(cat9000v-uadp 17.15.03)の応答は以下のとおりです。
COL $ /home/labuser/bin/gnmic -a 172.16.1.244:50052 --insecure -u netops --timeout 30s --format prototext --encoding json_ietf get --path '/interfaces/interface[name=Loopback0]/config'
notification: {
timestamp: 1791732518264107350
update: {
path: {
elem: {
name: "interfaces"
}
elem: {
name: "interface"
key: {
key: "name"
value: "Loopback0"
}
}
elem: {
name: "config"
}
}
val: {
json_ietf_val: "{\"name\":\"Loopback0\",\"type\":\"iana-if-type:softwareLoopback\",\"description\":\"initial\",\"enabled\":true}"
}
}
}値は json_ietf_val の中の JSON で、7-2 §8 で RESTCONF が返した OpenConfig の config と同じ項目(name・type・description・enabled)でした。type の値は iana-if-type:softwareLoopback で、7-2 §7 の RESTCONF の JSON と同じく、モジュールの名前(iana-if-type)が接頭辞に付いていました。17.15 の gNMI 章は、JSON_IETF のデータを RFC 7951 の規則に従わせると書いています。
JSON_IETF-encoded data must conform to the rules for JSON serialisation described in RFC 7951.
上で引いた 17.15 の gNMI 章の「gNMI Namespace」の節は、rfc7951 の namespace の文(origin の規則の 2 本目の引用)の直後に、値の中の接頭辞(value prefixing)の 2 文を置いています。
The RFC 7951-specified value prefixing uses the YANG module name.
Value prefixing is not affected by the selected path prefix namespace.
この 2 文の直後の例は、json_ietf_val の中のメンバー名(openconfig-interfaces:config・openconfig-interfaces:description)にモジュールの名前が付いた形で、identity の値は例にありません。RFC 7951 §4 は、JSON のメンバー名(データノードの識別子)を名前空間で修飾する形を定め、identityref と instance-identifier の値に名前空間の識別子が要る時も同じ形を使うと書いています。
namespace-qualified - the data node identifier is prefixed with the name of the module in which the data node is defined, separated from the data node identifier by the colon character (":").
Explicit namespace identifiers are sometimes needed when encoding values of the “identityref” and “instance-identifier” types. The same form of namespace-qualified name as defined above is then used. See Sections 6.8 and 6.11 for details.
7-2 §7 は、CSR1(csr1000v 17.03.08a)の ietf-interfaces の type(identityref の葉。7-2 §6)の値を、RFC 7951 §6.8 で読みました。C9K(cat9000v-uadp 17.15.03)の type の葉の型は、本ラボで取り出していません(§10)。
上の Namespace の規則(origin なし・rfc7951・legacy)と符号化の指定を、次の 11 本の Get で試しました(〔ツール側〕exit は gnmic の終了コード。どの Get も、§9 の冒頭の共通の指定に --format prototext と、表の --encoding と get --path を付けたもの)。
--path の値(origin・接頭辞) | --encoding | exit | 応答 |
|---|---|---|---|
/interfaces/interface[name=Loopback0]/config(origin なし) | json_ietf | 0 | OC の config(上のとおり) |
/interfaces/interface[name=Loopback0]/state(origin なし) | json_ietf | 0 | admin-status・oper-status は UP・ifindex 36・counters |
/ietf-interfaces:interfaces/interface[name=Loopback0](origin なし・モジュール名の接頭辞) | json_ietf | 1 | InvalidArgument・unexpected prefix[ ietf-interfaces ] |
/Cisco-IOS-XE-native:native/interface/Loopback[name=0](origin なし・モジュール名の接頭辞) | json_ietf | 1 | InvalidArgument・unexpected prefix[ Cisco-IOS-XE-native ] |
rfc7951:/openconfig-interfaces:interfaces/interface[name=Loopback0]/config | json_ietf | 0 | OC の config と同じ値 |
rfc7951:/ietf-interfaces:interfaces/interface[name=Loopback0] | json_ietf | 0 | ietf-ip の ipv4 10.7.3.2 と空の ipv6 |
rfc7951:/Cisco-IOS-XE-native:native/interface/Loopback[name=0] | json_ietf | 0 | key の name は数値の 0・primary の address 10.7.3.2 |
legacy:/oc-if:interfaces/interface[name=Loopback0]/config(YANG の prefix) | json_ietf | 0 | type が ianaift:softwareLoopback |
/interfaces/no-such-node(存在しない節点) | json_ietf | 1 | InvalidArgument・Invalid path: "/oc-if:interfaces/no-such-node" |
/interfaces/interface[name=Loopback0]/config | json | 0 | 値は json_val |
/interfaces/interface[name=Loopback0]/config | ascii | 1 | Unimplemented・Requested encoding "ASCII" not supported |
origin を付けないパスにモジュール名の接頭辞を付けると拒まれ、rfc7951: を付けると同じ接頭辞のパスが通りました。〔ツール側〕origin なしで ietf-interfaces の接頭辞を付けた Get の応答は以下のとおりです(gnmic の標準エラーの側の出力。C9K 17.15.03 の status)。
target "172.16.1.244:50052" Get request failed: "172.16.1.244:50052" GetRequest failed: rpc error: code = InvalidArgument desc = Invalid element name [ ietf-interfaces:interfaces ] : unexpected prefix[ ietf-interfaces ]
Error: one or more requests failed〔ツール側〕rfc7951: を付けた OC の Get では、gnmic が描いた応答の path にも origin とモジュール名の接頭辞が付いていました(C9K 17.15.03 の応答)。
COL $ /home/labuser/bin/gnmic -a 172.16.1.244:50052 --insecure -u netops --timeout 30s --format prototext --encoding json_ietf get --path 'rfc7951:/openconfig-interfaces:interfaces/interface[name=Loopback0]/config'
notification: {
timestamp: 1791732518840311801
update: {
path: {
origin: "rfc7951"
elem: {
name: "openconfig-interfaces:interfaces"
}
…(省略)〔ツール側〕legacy: と YANG の prefix(oc-if)で書いたパスも通り、値の type は ianaift:(iana-if-type の prefix 文の値。7-2 §6)の形で返りました(C9K 17.15.03 の応答)。
COL $ /home/labuser/bin/gnmic -a 172.16.1.244:50052 --insecure -u netops --timeout 30s --format prototext --encoding json_ietf get --path 'legacy:/oc-if:interfaces/interface[name=Loopback0]/config'
notification: {
timestamp: 1791732519236847650
update: {
path: {
origin: "legacy"
elem: {
name: "oc-if:interfaces"
}
elem: {
name: "interface"
key: {
key: "name"
value: "Loopback0"
}
}
elem: {
name: "config"
}
}
val: {
json_ietf_val: "{\"name\":\"Loopback0\",\"type\":\"ianaift:softwareLoopback\",\"description\":\"initial\",\"enabled\":true}"
}
}
}〔ツール側〕--encoding json_ietf の OC の config の 3 本の Get で gnmic が描いた type の値の接頭辞は、origin なしと rfc7951: では iana-if-type:、legacy: と oc-if で書いたパスでは ianaift: でした(C9K 17.15.03 の応答)。
上で引いた章の値の接頭辞(value prefixing)の 2 文目は、値の接頭辞は選んだパスの接頭辞の namespace に左右されないと書いています。この 2 文は、章が 16.10.1 以降のリリースの namespace として書いた部分にあり、16.10.1 より前の legacy の節には値の接頭辞の文がありません。2 文が legacy の origin と type の値に当てはまるかは、本ラボでは確かめていません(§10)。
存在しない節点への Get の status は、要求に無い oc-if: の接頭辞を付けたパスを返しました。
符号化は、仕様の文書(0.4.0)では JSON が既定で、対応しない符号化には Unimplemented を返すとされています。
If the encoding is not specified, JSON MUST be used.
If the target does not support the specified encoding, the target MUST return an error of
Unimplemented.
C9K は、--encoding json の Get には値を json_val で返し、--encoding ascii の Get には Unimplemented を返しました。〔ツール側〕ascii の Get の status は以下のとおりです(C9K 17.15.03 の応答)。
target "172.16.1.244:50052" Get request failed: "172.16.1.244:50052" GetRequest failed: rpc error: code = Unimplemented desc = Requested encoding "ASCII" not supported
Error: one or more requests failed17.15 の gNMI 章は、BYTES と ASCII を対応しない符号化に挙げています。
BYTES and ASCII encoding options are not supported.
同じ章の Proto Encoding の節は、PROTO を Subscribe だけで使えるとし、Get と Set には対応しないと書いています。§9.2 の Capabilities の supported_encodings に並んだ PROTO と、この章の文は別々に読みます。本ラボは PROTO の Get も Subscribe も撮っていません。
PROTO encoding is supported for all the paths that are supported by gNMI. PROTO encoding supports subscribe RPC, but not GET and SET RPCs.
9.4 on-change の申告 — capabilities model
17.15 の MDT 章は、gNMI の ON_CHANGE に対応するパスが限られていて、対応は capabilities model(Cisco-IOS-XE-mdt-capabilities-oper)で問い合わせると書いています。
ON_CHANGE support is limited to certain model paths. To check whether a path supports ON_CHANGE, query the path in the Cisco-IOS-XE-MDT-capabilities-oper model.
From Cisco IOS XE 17.6.1, Cisco IOS XE software supports the capabilities model, Cisco-IOS-XE-mdt-capabilities-oper.yang that can be queried to determine the paths that support on-change subscriptions and their transports.
capabilities model は、すべての節点ではなく、親と対応が変わる節点(inflection point)だけを並べます。トランスポートごとの表(mdt-transport-per-node)、節点ごとの表(mdt-per-node)、システム全体の順に調べます。
Instead of listing every individual leaf and container node that supports on-change, the Cisco-IOS-XE-mdt-capabilities-oper.yang model essentially lists only the inflection points, that is, the paths to the nodes whose support differs from that of their parent node.
To determine the capabilities of a node for a particular transport, first check the mdt-transport-per-node list for that transport. If no match is found, check the mdt-per-node list. If again no match is found, then fall back to the system capabilities.
対応はビットで示し、mdt-cap-notif-config が設定の節点、mdt-cap-notif-state が状態の節点の対応です。どちらのビットも立っていなければ非対応です。
The bit field indicates the actual support. There are two bit values, mdt-cap-notif-config and mdt-cap-notif-state, which indicate that the capability is supported for config or operational nodes, respectively.
This sample capability specification indicates that on-change is not supported, because neither of the bits is set.
同じ節は、is-valid の欄を、在ること自体がその entry に能力の指定が当てはまることを示す empty の葉としています。節点ごとの表では、その節点を選ぶ最初の entry が能力を決めます。システム全体の能力は、periodic だけで on-change は非対応と書いています。
The is-valid field is an empty leaf node. The presence of the is-valid field indicates that the capability applies to that entry.
The first entry that selects a given node is what determines the capabilities of that node.
The system-level capabilities for Cisco IOS XE support only periodic subscriptions; on-change subscriptions are not supported.
JSON_IETF は RFC 7951 に従い(§9.3)、RFC 7951 §6.9 は empty の型の値を [null] と書きます。
An “empty” value is represented as “[null]”, i.e., an array with the “null” literal being its only element.
C9K の capabilities model は、gNMI の Get(rfc7951: の origin)で読みました(C9K に NETCONF のセッションは張っていません)。最上位の container の名前(mdt-capabilities-oper-data)は、要求のパスの側では道具の入力で、機器からは取り出していません。応答の Path と values のキーには、同じ名前が返っています。〔ツール側〕gnmic が JSON で描いた C9K(cat9000v-uadp 17.15.03)の応答の抜粋は以下のとおりです。
COL $ /home/labuser/bin/gnmic -a 172.16.1.244:50052 --insecure -u netops --timeout 30s --format json --encoding json_ietf get --path rfc7951:/Cisco-IOS-XE-mdt-capabilities-oper:mdt-capabilities-oper-data
[
{
…(省略)
"Path": "rfc7951:/Cisco-IOS-XE-mdt-capabilities-oper:mdt-capabilities-oper-data",
"values": {
"Cisco-IOS-XE-mdt-capabilities-oper:mdt-capabilities-oper-data": {
…(省略)
{
"index": 84,
"sub-caps": {
"on-change-is-valid": [
null
],
"on-change-supported": [
null
]
},
"xpath": "/interfaces-ios-xe-oper:interfaces/interface/lag-aggregate-state"
},
…(省略)
{
"index": 86,
"sub-caps": {
"on-change-is-valid": [
null
],
"on-change-supported": "mdt-cap-notif-config mdt-cap-notif-state"
},
"xpath": "/interfaces-ios-xe-oper:interfaces/interface"
},
…(省略)
{
"transport": "mdt-cap-transport-gnmi"
},
{
"transport": "mdt-cap-transport-grpc"
}
]
}
],
"sub-caps": {
"on-change-is-valid": [
null
],
"on-change-supported": [
null
],
"periodic-is-valid": [
null
],
"periodic-supported": "mdt-cap-notif-config mdt-cap-notif-state"
}
…(省略)〔ツール側〕応答の中身を数えると、以下のとおりです(数えたのは道具の側の読みです)。
| 表 | 中身 |
|---|---|
| mdt-per-node | 26 件。23 件の on-change-supported が mdt-cap-notif-config mdt-cap-notif-state、3 件(index 84・85・97)が空([null]) |
| on-change-is-valid | mdt-per-node の 26 件と system の sub-caps のすべてで [null] |
| index 86 | xpath /interfaces-ios-xe-oper:interfaces/interface(Cisco の状態のモデル)で、on-change-supported は 2 つのビット |
| OpenConfig の interfaces の xpath | 0 件(OC の xpath は platform の 1 種だけ) |
| mdt-transport | netconf・gnmi・grpc の 3 件。gnmi と grpc は mdt-transport-per-node を持たない |
| system の sub-caps | on-change-supported は空([null])・periodic-supported は 2 つのビット |
17.15 の章の調べ方の順に当てはめると、gnmi の表は空なので節点ごとの表を見ます。7-2 で読んだ OpenConfig の interfaces のパスは節点ごとの表に無く、システム全体の on-change は空です。Cisco の状態のモデルの interface(index 86)は、2 つのビットが立っています。on-change-is-valid の [null] は、RFC 7951 の empty の値の形で、章の is-valid の欄が「在る」と読めます。index 84・85 は index 86 より前に並びますが、選ぶのは interface の下の節点(lag-aggregate-state・diffserv-info)で、interface 自身の読みには掛かりません。
一方、on-change-supported は、章の例(上の「neither of the bits is set」の文が説明する例)ではビットの無い空の要素 <on-change-supported/> として書かれている欄です。本ラボはこの葉の型を機器から取り出していないので、この欄の [null] を「ビットが無い」の形と読むのは道具の側の読みです。機器が調べ方の順で実際にどの entry を選ぶかも、出力からは言えません。§9.6 の ON_CHANGE は、この申告に在るパス(index 86)と、申告に無い OC のパスの両方を試しました。
9.5 Set — 書いて CLI で読む
仕様の文書(0.4.0)は、Set の変更を全部適用するか、全部戻すかのどちらかとしています。
That is, either all modifications within the request are applied, or the target MUST rollback the state changes to reflect its state before any changes were applied. The state of the target MUST NOT appear to be changed until such time as all changes have been accepted successfully.
OC の config の description に set-by-gnmi を書きました。〔ツール側〕gnmic が描いた C9K(cat9000v-uadp 17.15.03)の Set の応答は以下のとおりです。
COL $ /home/labuser/bin/gnmic -a 172.16.1.244:50052 --insecure -u netops --timeout 30s --format prototext --encoding json_ietf set --update-path '/interfaces/interface[name=Loopback0]/config/description' --update-value set-by-gnmi
response: {
path: {
elem: {
name: "interfaces"
}
elem: {
name: "interface"
key: {
key: "name"
value: "Loopback0"
}
}
elem: {
name: "config"
}
elem: {
name: "description"
}
}
op: UPDATE
}
timestamp: 1791732519893142872Set の後の C9K(cat9000v-uadp 17.15.03)の CLI には、gNMI で書いた description がありました。
C9K# show running-config interface Loopback0
Building configuration...
Current configuration : 89 bytes
!
interface Loopback0
description set-by-gnmi
ip address 10.7.3.2 255.255.255.255
end同じ時間帯の C9K(cat9000v-uadp 17.15.03)の syslog では、Set の接続と切断の間に、dmiauthd の「Configured from gNMI」の行がありました。
…(省略)
*Oct 11 15:28:39.892: %GNMIB-6-GRPC_CON_STATE: Switch 1 R0/0: gnmib: Received gRPC Connection from ipv4:172.16.1.242:40846 for RPC gNMI/Set
*Oct 11 15:28:40.397: %DMI-5-CONFIG_I: Switch 1 R0/0: dmiauthd: Configured from gNMI by gnmib_pid_16067, transaction-id 40
*Oct 11 15:28:40.505: %GNMIB-6-GRPC_CON_STATE: Switch 1 R0/0: gnmib: Received gRPC Disconnection from ipv4:172.16.1.242:40846 for RPC gNMI/SetSet の後の gnmic の Get も、description に set-by-gnmi を返しました。
9.6 Subscribe — モードごとの応答
仕様の文書(0.4.0)は、購読のモードを 3 つ(ONCE・POLL・STREAM)に分け、STREAM の中をさらに 3 つ(SAMPLE・ON_CHANGE・TARGET_DEFINED)に分けています。
The target creates the relevant update messages, transmits them, and subsequently closes the channel.
Polling subscriptions are used for on-demand retrieval of data items via long-lived channels.
Stream subscriptions are long-lived subscriptions which continue to transmit updates relating to the set of paths that are covered within the subscription indefinitely.
Target Defined
(TARGET_DEFINED)- when a client creates a subscription specifying the target defined mode, the target MUST determine the best type of subscription to be created on a per-leaf basis.
1 つ目の文は ONCE の節の文です。gnmi.proto(0.7.0)では、mode の欄が 2 つのメッセージに別々に在ります。SubscriptionList の mode(列挙 Mode = STREAM・ONCE・POLL)と、SubscriptionList が subscription の欄に入れる Subscription の mode(列挙 SubscriptionMode = TARGET_DEFINED・ON_CHANGE・SAMPLE)です(出典層)。
…(省略)
message SubscriptionList {
Path prefix = 1; // Prefix used for paths.
repeated Subscription subscription = 2; // Set of subscriptions to create.
…(省略)
enum Mode {
STREAM = 0; // Values streamed by the target (Sec. 3.5.1.5.2).
ONCE = 1; // Values sent once-off by the target (Sec. 3.5.1.5.1).
POLL = 2; // Values sent in response to a poll request (Sec. 3.5.1.5.3).
}
Mode mode = 5;
…(省略)
Encoding encoding = 8;
…(省略)
message Subscription {
Path path = 1; // The data tree path.
SubscriptionMode mode = 2; // Subscription mode to be used.
…(省略)
enum SubscriptionMode {
TARGET_DEFINED = 0; // The target selects the relevant mode for each element.
ON_CHANGE = 1; // The target sends an update on element value change.
SAMPLE = 2; // The target samples values according to the interval.
}
…(省略)一方、17.15 の MDT 章は、gNMI の Subscribe で対応するものを STREAM、SAMPLE と ON_CHANGE に絞って書いています。
Path prefix (only explicit element names), Subscription subscription, Mode mode STREAM, and Encoding encoding IETF_JSON are supported.
Only SAMPLE and ON_CHANGE (from Cisco IOS XE Bengaluru 17.6.1) are supported.
同じ章の Prefix と Path の注は、origin の値を空と openconfig に、elem を接頭辞の無い名前に絞っています。
Origin (supported values are “” and “openconfig”), elem (supported element name is prefix-free), and target are supported.
ただし、同じ章の gNMI Dial-In Subscription の例の 2 つ目は、origin に legacy、elem に接頭辞の付いた名前を使っています(出典層)。
…(省略)
path: <
origin: "legacy"
elem: <name: "oc-platform:components">
…(省略)17.15 の gNMI 章の「gNMI Namespace」も、origin の欄で使う接頭辞の決め方として、RFC 7951 の名前空間(モジュール名の接頭辞)を挙げています(§9.3)。
〔ツール側〕本ラボの要求のうち、SAMPLE と申告に無い OC の ON_CHANGE は origin なし・接頭辞なしのパスでした。申告に在る ON_CHANGE は、origin が rfc7951、最初の elem が接頭辞の付いた Cisco-IOS-XE-interfaces-oper:interfaces で、注の値に無い形です。C9K(cat9000v-uadp 17.15.03)は、この要求に update を 3 本返しました(下の STREAM・ON_CHANGE の段)。
本ラボは 5 つのモードを試しました。道具ごとの status の書き方は次のとおりです。〔ツール側〕gnmic は gRPC の status の名前を InvalidArgument と表示し、gnmi_sub.py は INVALID_ARGUMENT と、番号の code_num 3 で記録しました。仕様の文書(0.4.0)は、この code を InvalidArgument (3) と書いています(出典層。たとえば SAMPLE の sample_interval を拒む時の文)。
If the target is unable to support the desired
sample_intervalit MUST reject the subscription by closing theSubscribeRPC specifying anInvalidArgument (3)error code.
結果は以下のとおりです(〔ツール側〕道具が記録した応答と status。C9K の CLI と syslog は右の列。指定の列は道具の引数で、どれも --encoding json_ietf を付けました)。
| モード | 道具 | 指定 | パス | 〔ツール側〕応答・status | C9K の CLI・syslog |
|---|---|---|---|---|---|
| ONCE | gnmic | --mode once | /interfaces/interface[name=Loopback0]/state/counters | InvalidArgument・Unsupported subscription list mode selection [ ONCE ] | — |
| POLL | gnmi_sub.py | --mode poll --poll-after 5 --polls 1 --duration 40 | 同じ | INVALID_ARGUMENT・… [ POLL ] | — |
| STREAM・TARGET_DEFINED | gnmi_sub.py | --mode stream --stream-mode target_defined --duration 15 | 同じ | INVALID_ARGUMENT・Unsupported subscription mode selection [ \u0000 on sub index [ 0 ]] | 一覧は空・Subscribe の接続と切断が 0.001 秒差 |
| STREAM・SAMPLE 10 秒 | gnmic | --mode stream --stream-mode sample --sample-interval 10s | 同じ | update 4 本(中身あり 3 本)と sync_response 1 本 | Dynamic・Update Trigger: periodic |
| STREAM・ON_CHANGE | gnmi_sub.py | --mode stream --stream-mode on_change --duration 110 | rfc7951:/Cisco-IOS-XE-interfaces-oper:interfaces/interface[name=Loopback0](Cisco の状態のモデルの interface。申告に在る) | update 3 本(sync_response 0 本) | Dynamic・Update Trigger: on-change |
| STREAM・ON_CHANGE | gnmi_sub.py | 同じ | /interfaces/interface[name=Loopback0]/config/description(OC。申告に無い) | INTERNAL(下のとおり) | 接続と切断が 0.004 秒差 |
17.15 の章が挙げないモード(ONCE・POLL・TARGET_DEFINED)は、3 つとも拒まれました。拒まれた理由は、status の文言の範囲でしか分かりません。
ONCE・POLL・TARGET_DEFINED。 〔ツール側〕gnmic の ONCE の status は以下のとおりです(標準エラーの側の出力。C9K 17.15.03 の応答)。
rpc error: code = InvalidArgument desc = Unsupported subscription list mode selection [ ONCE ]
Error: one or more requests failed〔ツール側〕gnmi_sub.py の POLL の記録(events.jsonl)は以下のとおりです(C9K 17.15.03 の応答の status。1 行目は開始の行で、道具の版と呼び出しの指定を記録しています)。
{"kind": "start", "t_utc": "2026-10-11T15:28:45.411507Z", "label": "PG_61_gnmisub-poll", "target": "172.16.1.244:50052", "user": "netops", "mode": "poll", "stream_mode": null, "paths": ["/interfaces/interface[name=Loopback0]/state/counters"], "encoding": "json_ietf", "sample_interval_ns": null, "duration_s": 40.0, "poll_after_s": 5.0, "polls": 1, "python": "3.12.3", "grpcio": "1.84.0", "protobuf": "7.36.2"}
{"kind": "request", "t_utc": "2026-10-11T15:28:45.438197Z", "seq": 1, "file": "request-0001.txt", "request_type": "subscribe"}
{"kind": "rpc_error", "t_utc": "2026-10-11T15:28:45.448718Z", "code": "INVALID_ARGUMENT", "code_num": 3, "details": "Unsupported subscription list mode selection [ POLL ]", "trailing_metadata": []}〔ツール側〕TARGET_DEFINED の記録は以下のとおりです(C9K 17.15.03 の応答の status)。
{"kind": "start", "t_utc": "2026-10-11T15:28:47.910888Z", "label": "PG_62_gnmisub-target-defined", "target": "172.16.1.244:50052", "user": "netops", "mode": "stream", "stream_mode": "target_defined", "paths": ["/interfaces/interface[name=Loopback0]/state/counters"], "encoding": "json_ietf", "sample_interval_ns": null, "duration_s": 15.0, "poll_after_s": 1.0, "polls": 1, "python": "3.12.3", "grpcio": "1.84.0", "protobuf": "7.36.2"}
{"kind": "request", "t_utc": "2026-10-11T15:28:47.914737Z", "seq": 1, "file": "request-0001.txt", "request_type": "subscribe"}
{"kind": "rpc_error", "t_utc": "2026-10-11T15:28:47.928155Z", "code": "INVALID_ARGUMENT", "code_num": 3, "details": "Unsupported subscription mode selection [ \u0000 on sub index [ 0 ]]", "trailing_metadata": []}〔ツール側〕開始の行(上の 1 行目)の指定は "mode": "stream", "stream_mode": "target_defined" です。gnmi_sub.py が記録した TARGET_DEFINED の要求は以下のとおりで、mode の行は subscription の括弧の中にも外にもありません。
subscribe {
subscription {
path {
elem {
name: "interfaces"
}
elem {
name: "interface"
key {
key: "name"
value: "Loopback0"
}
}
elem {
name: "state"
}
elem {
name: "counters"
}
}
}
encoding: JSON_IETF
}〔ツール側〕POLL の要求の mode: POLL の行は、subscription の括弧の外(encoding と同じ段)に在ります。上の gnmi.proto の SubscriptionList の mode で、TARGET_DEFINED を指定する Subscription の mode とは別の欄です。同じ gnmi_sub.py の ON_CHANGE の要求(開始の行の指定は "mode": "stream", "stream_mode": "on_change")の記録では、mode の行は subscription の括弧の中の mode: ON_CHANGE の 1 本だけで、括弧の外に STREAM の行はありません。gnmi.proto では、STREAM も TARGET_DEFINED も 0 です。この 3 本の記録では、値が 0 の列挙(list の STREAM・Subscription の TARGET_DEFINED)の行が無く、0 でない値(list の POLL = 2・Subscription の ON_CHANGE = 1)の行だけが在りました。記録に mode の行が無いことと、機器に届いた要求の中身との関係は、パケットを撮っておらず確かめていません(§10)。
STREAM・SAMPLE。 SAMPLE は、sample_interval(ナノ秒)ごとに値を送るモードです(仕様の文書 0.4.0)。
Sampled (
SAMPLE) - a subscription that is defined to be sampled MUST be specified along with asample_intervalencoded as an unsigned 64-bit integer representing nanoseconds between samples.
gnmic の --sample-interval 10s を 26 秒で止めました(SIGINT)。〔ツール側〕gnmic の --log の標準エラーの行では、C9K(17.15.03)へ送った SubscribeRequest の sample_interval は 10000000000 でした。
…(省略)
time=2026-10-11T15:29:04.866Z level=INFO msg="sending gNMI SubscribeRequest" target=172.16.1.244:50052 subscribe="subscribe:{subscription:{path:{elem:{name:\"interfaces\"} elem:{name:\"interface\" key:{key:\"name\" value:\"Loopback0\"}} elem:{name:\"state\"} elem:{name:\"counters\"}} mode:SAMPLE sample_interval:10000000000} encoding:JSON_IETF}" mode=STREAM encoding=JSON_IETF〔ツール側〕gnmic が描いた C9K(cat9000v-uadp 17.15.03)の応答の先頭は以下のとおりです。
COL $ /home/labuser/bin/gnmic -a 172.16.1.244:50052 --insecure -u netops --timeout 30s --format prototext --log --encoding json_ietf subscribe --mode stream --stream-mode sample --sample-interval 10s --path '/interfaces/interface[name=Loopback0]/state/counters'
update: {
timestamp: 1791732545051934000
update: {
path: {
elem: {
name: "interfaces"
}
elem: {
name: "interface"
key: {
key: "name"
value: "Loopback0"
}
}
elem: {
name: "state"
}
elem: {
name: "counters"
}
}
val: {
json_ietf_val: "{\"in-octets\":\"0\",\"in-unicast-pkts\":\"0\",\"in-broadcast-pkts\":\"0\",\"in-multicast-pkts\":\"0\",\"in-discards\":\"0\",\"in-errors\":\"0\",\"in-unknown-protos\":\"0\",\"in-fcs-errors\":\"0\",\"out-octets\":\"0\",\"out-unicast-pkts\":\"0\",\"out-broadcast-pkts\":\"0\",\"out-multicast-pkts\":\"0\",\"out-discards\":\"0\",\"out-errors\":\"0\",\"last-clear\":\"1791731279743000000\"}"
}
}
}
update: {
timestamp: 1791732545055328000
}
sync_response: true
…(省略)〔ツール側〕最上位の update は 4 本で、中身のある 3 本の timestamp を UTC に直すと 15:29:05.051934・15:29:15.044224・15:29:25.046469 です(差は 9.99229 秒と 10.002245 秒)。1 本目の次に timestamp だけの空の update があり、その次に sync_response を true にした応答が 1 本ありました。値は counters の 15 個で、last-clear 以外はどれも "0" です。
gNMI の仕様の文書(0.4.0)は、購読のパスすべての最初の update を送り終えたら、sync_response を true にした SubscribeResponse を送る(MUST)と書き、その応答を、購読の既存のデータがすべて少なくとも 1 回送られたことの印としています(C9K が名乗る版は 0.7.0。§11.4)。
When the target has transmitted the initial updates for all paths specified within the subscription, a
SubscribeResponsemessage with thesync_responsefield set totrueMUST be transmitted to the client to indicate that the initial transmission of updates has concluded.
This provides an indication to the client that all of the existing data for the subscription has been sent at least once.
17.15 の MDT 章は、sync_response を、SubscriptionList のパスの値がすべて少なくとも 1 回送られたことを示すフィールドとし、最初の update の後に送られると書いています。同じ章は、このフィールドが gNMI の on-change と periodic の両方で有効とも書いています。
The sync_response is a boolean field that is part of the SubscribeResponse response message, which indicates that all data values that corresponds to the paths in the SubscriptionList has been transmitted at least once. The sync_response message is sent after the first update message.
This field is enabled for both gNMI on-change and periodic notifications.
同じ章の SubscribeResponse の定義(oneof response に update・sync_response・error)の後の注は、次の 1 文です。
Only Notification update is supported.
本ラボの記録では、gnmic の SAMPLE に sync_response が 1 本あり、gnmi_sub.py の ON_CHANGE には 0 本でした(この節の SAMPLE と ON_CHANGE の段)。注と記録の関係は確かめていません(§10)。
購読中の C9K の CLI には、gNMI の購読が Dynamic として現れました。C9K(cat9000v-uadp 17.15.03)の detail は以下のとおりです。
C9K# show telemetry ietf subscription 2147483648 detail
Telemetry subscription detail:
Subscription ID: 2147483648
Type: Dynamic
State: Valid
Stream: yang-push
Filter:
Filter type: xpath
XPath: /oc-if:interfaces/interface[name='Loopback0']/state/counters
Update policy:
Update Trigger: periodic
Period: 1000
Encoding: encode-kvgpb
Source VRF:
Source Address:
Notes: Subscription validated
Named Receivers:
Name Last State Change State Explanation
-------------------------------------------------------------------------------------------------------------------------------------------------------
gNMI://172.16.1.242:36372 10/11/26 15:29:05 Connected gNMI の購読は、MDT の購読の表に、stream yang-push・xpath の購読として現れました。XPath は oc-if: の接頭辞の形、受け手の名前は gNMI:// と COL のアドレスと port です。CLI の Encoding: encode-kvgpb は、gnmic の指定(JSON_IETF)と符号化の名前が違います。CLI の Period: 1000 は、17.15 の章の period の単位(1/100 秒)で読めば gnmic の指定(10 秒)と同じ長さですが、C9K の出力に単位の表記は無く、この表示がその単位かは確かめていません(§11.6)。同じ時間帯の C9K(cat9000v-uadp 17.15.03)の syslog では、Subscribe の接続の後に pubd の %MDT_CONNECTION の UP と DOWN の行があり、port 36372 は detail の受け手の port と同じでした。
…(省略)
*Oct 11 15:29:04.999: %GNMIB-6-GRPC_CON_STATE: Switch 1 R0/0: gnmib: Received gRPC Connection from ipv4:172.16.1.242:36372 for RPC gNMI/Subscribe
*Oct 11 15:29:05.022: %MDT_CONNECTION-6-STATE_CHANGED: Switch 1 R0/0: pubd: Connection state changed (id 0 - 172.16.1.242:36372:0:0.0.0.0): UP
*Oct 11 15:29:30.966: %MDT_CONNECTION-6-STATE_CHANGED: Switch 1 R0/0: pubd: Connection state changed (id 0 - 172.16.1.242:36372:0:0.0.0.0): DOWN
*Oct 11 15:29:30.967: %GNMIB-6-GRPC_CON_STATE: Switch 1 R0/0: gnmib: Received gRPC Disconnection from unknown for RPC gNMI/Subscribe
…(省略)STREAM・ON_CHANGE(申告に在るパス)。 仕様の文書(0.4.0)は、ON_CHANGE でも最初に購読のパスすべての update を送り(MUST)、その後は値が変わった時だけ送るべきとしています。
For all
ON_CHANGEsubscriptions, the target MUST first generate updates for all paths that match the subscription path(s), and transmit them.
Following this initial set of updates, updated values SHOULD only be transmitted when their value changes.
§9.4 の申告に在る Cisco の状態のモデルの interface(index 86)を、rfc7951: の origin で 110 秒購読しました(Cisco の状態のモデルは対照で、7-2 では読んでいないパスです)。購読中に C9K の CLI で Loopback0 に description・shutdown・no shutdown を 1 つずつ入れました。〔ツール側〕gnmi_sub.py の記録(events.jsonl)は以下のとおりです(C9K 17.15.03 の応答。1 行目は開始の行)。
{"kind": "start", "t_utc": "2026-10-11T15:29:35.420333Z", "label": "PG_64_0_gnmisub-onchange", "target": "172.16.1.244:50052", "user": "netops", "mode": "stream", "stream_mode": "on_change", "paths": ["rfc7951:/Cisco-IOS-XE-interfaces-oper:interfaces/interface[name=Loopback0]"], "encoding": "json_ietf", "sample_interval_ns": null, "duration_s": 110.0, "poll_after_s": 1.0, "polls": 1, "python": "3.12.3", "grpcio": "1.84.0", "protobuf": "7.36.2"}
{"kind": "request", "t_utc": "2026-10-11T15:29:35.424553Z", "seq": 1, "file": "request-0001.txt", "request_type": "subscribe"}
{"kind": "response", "t_utc": "2026-10-11T15:29:35.567881Z", "seq": 1, "file": "response-0001.txt", "which": "update", "sync_response": false, "n_update": 1, "has_content": 1}
{"kind": "response", "t_utc": "2026-10-11T15:30:16.369993Z", "seq": 2, "file": "response-0002.txt", "which": "update", "sync_response": false, "n_update": 1, "has_content": 1}
{"kind": "response", "t_utc": "2026-10-11T15:30:37.403981Z", "seq": 3, "file": "response-0003.txt", "which": "update", "sync_response": false, "n_update": 1, "has_content": 1}
{"kind": "cancelled", "t_utc": "2026-10-11T15:31:25.427420Z", "reason": "duration", "code": "CANCELLED", "code_num": 1, "details": "Locally cancelled by application!", "trailing_metadata": []}〔ツール側〕応答は update 3 本で、sync_response は 0 本でした(同じ C9K の SAMPLE の記録には 1 本)。最後は gnmi_sub.py の側の打ち切り(110 秒)です。仕様の文書(0.4.0)は購読のパスすべての最初の update を送り終えたら sync_response を送る(MUST)と書き、17.15 の MDT 章は sync_response を on-change でも有効としています。この記録に sync_response が無かった理由は確かめていません(§10)。〔ツール側〕SAMPLE は gnmic、ON_CHANGE は gnmi_sub.py で撮ったので、sync_response の有無の差に道具の差が混じっていないかは、同じ道具・同じパスで比べていません。gnmi_sub.py は応答ごとに、response の欄が update か sync_response かを events.jsonl の which と sync_response に書きます(上の 3 行)。
3 本の値は、どれも interface の entry の全体(最上位のキー 29 個)でした。C9K の CLI の時刻と並べると、以下のとおりです。
| 記録 | 〔ツール側〕timestamp を UTC に直した値 | admin-status・oper-status | description | 前後の C9K の時刻 |
|---|---|---|---|---|
| response-0001 | 15:29:35.691479 | if-state-up・if-oper-state-ready | set-by-gnmi | 購読の Connection 15:29:35.562 の後・description の投入の前の show clock 15:29:45.817 の前 |
| response-0002 | 15:30:16.4938 | if-state-down・if-oper-state-no-pass | onchange-gnmi-0 | shutdown の投入の前の show clock 15:30:06.867 の後・LINK の down の行 15:30:16.488 |
| response-0003 | 15:30:37.527948 | if-state-up・if-oper-state-ready | onchange-gnmi-0 | no shutdown の前の show clock 15:30:27.895 の後・LINK の up の行 15:30:37.523 |
description だけを変えた後(15:29:45.817 の show clock の後)から、shutdown の後の response-0002 までの間に、記録された応答はありません。response-0002 の値は、description と admin-status の両方の変化を含んでいました。description の変更が単独で update を出すかは、この窓の長さ(約 21 秒)では確かめていません。response-0001 を開始時の同期と呼ぶ根拠も、出力にはありません(時刻が購読の開始の直後というだけです)。
購読中の C9K(cat9000v-uadp 17.15.03)の detail は以下のとおりで、Update Trigger: on-change・Synch on start: Yes・Dampening period: 0 でした。
C9K# show telemetry ietf subscription 2147483649 detail
Telemetry subscription detail:
Subscription ID: 2147483649
Type: Dynamic
State: Valid
Stream: yang-push
Filter:
Filter type: xpath
XPath: /interfaces-ios-xe-oper:interfaces/interface[name='Loopback0']
Update policy:
Update Trigger: on-change
Synch on start: Yes
Dampening period: 0
Encoding: encode-kvgpb
Source VRF:
Source Address:
Notes: Subscription validated
Named Receivers:
Name Last State Change State Explanation
-------------------------------------------------------------------------------------------------------------------------------------------------------
gNMI://172.16.1.242:40258 10/11/26 15:29:35 Connected STREAM・ON_CHANGE(申告に無いパス)。 対照に、§9.4 の申告に無い OC の config/description へ ON_CHANGE の購読を送りました。〔ツール側〕gnmi_sub.py の記録は以下のとおりで、status は INTERNAL でした(C9K 17.15.03 の応答)。
…(省略)
{"kind": "request", "t_utc": "2026-10-11T15:31:34.619421Z", "seq": 1, "file": "request-0001.txt", "request_type": "subscribe"}
{"kind": "rpc_error", "t_utc": "2026-10-11T15:31:34.631091Z", "code": "INTERNAL", "code_num": 13, "details": "Value '/oc-if:interfaces/interface[name=\"Loopback0\"]/config/description' for parameter 'filter-type' is not supported by the specified filter.", "trailing_metadata": []}details の文言は、パラメータ filter-type の値として渡した OC の description のパスが、指定したフィルタでは対応していない、という内容です。C9K(cat9000v-uadp 17.15.03)の syslog では、この購読の接続と切断が 0.004 秒差で並び、その後の CLI の投入の行が続きました。
…(省略)
*Oct 11 15:31:34.752: %GNMIB-6-GRPC_CON_STATE: Switch 1 R0/0: gnmib: Received gRPC Connection from ipv4:172.16.1.242:56296 for RPC gNMI/Subscribe
*Oct 11 15:31:34.756: %GNMIB-6-GRPC_CON_STATE: Switch 1 R0/0: gnmib: Received gRPC Disconnection from ipv4:172.16.1.242:56296 for RPC gNMI/Subscribe
*Oct 11 15:31:53.581: %SYS-5-CONFIG_I: Configured from console by netops on vty1 (192.168.1.50)
…(省略)後始末の確認(Phase Z)で撮った C9K の show logging のバッファの全体に、%MDT_SUBSCRIPTION の行は 0 行で、CSR1 の NETCONF の拒否(§6.4)のような文言の行はありません。同じ C9K(cat9000v-uadp 17.15.03)の show logging の冒頭と、バッファの設定の行は以下のとおりです。rate-limited の 2 件がいつのどの行で、バッファに入ったかどうかは、出力からは分かりません。バッファの level は informational で、大きさは 512000 でした(起動時の %SYS-5-LOG_CONFIG_CHANGE の行。その前の行は利用者 netops の権限の行)。
C9K# show logging
Syslog logging: enabled (0 messages dropped, 2 messages rate-limited, 0 flushes, 0 overruns, xml disabled, filtering disabled)
…(省略)
Buffer logging: level informational, 220 messages logged, xml disabled,
…(省略)
*Oct 11 15:11:51.130: %AAA-6-USER_PRIVILEGE_UPDATE: username: netops privilege updated with priv-15
*Oct 11 15:11:51.246: %SYS-5-LOG_CONFIG_CHANGE: Buffer logging: level informational, xml disabled, filtering disabled, size (512000)
…(省略)INTERNAL の理由は、status の details の文言の範囲でしか分かりません。
C9K の syslog の %GNMIB-6-GRPC_CON_STATE の接続と切断の行は、RPC ごとに同じ数でした(Capabilities 1 対・Get 21 対・Set 1 対・Subscribe 6 対)。Get の 21 対は、Capabilities の前の 8 対(§9.1)と、本文で示した Get の 13 本(§9.3 の 11 本・§9.4 の 1 本・§9.5 の Set の後の 1 本)を足した数です。切断の行の接続元が unknown になったのは Subscribe の 2 行(SAMPLE と、申告に在るパスの ON_CHANGE の終わり)で、どちらも %MDT_CONNECTION の DOWN の行と 0.002 秒以内に並んでいます。
10. 本ラボで確かめていないこと
本節の実測は、同じ構成での 1 回の撮影です。以下は観測していません。機器と版ごとに分け、各項目の末尾に戻る先の § を書きます。
10.1 CSR1(csr1000v 17.03.08a)の NETCONF の購読
- 最初の NETCONF の試行で hello を受け取れなかった理由と、NETCONF が要求を受け付け始めた時刻。チャネルが閉じたのか、終了の状態を受けたのかも区別していません(§3.3)
- RFC 8639・RFC 8641 の版の実装。2 台とも ietf-subscribed-notifications の名前を名乗っておらず、RFC 8639・RFC 8641 の RPC は試していません(§4.4)
- interleave の意味。機器の hello に
interleave:1.0がありますが(クライアントの hello は名乗っていない)、何を許すかは試していません。購読中の<get>の観測を、interleave の実証とは扱いません(§5.3) - period の単位(CSR1)。CSR1 の出力に単位の表記は無く、機器の yang-push の本文の型
yang:timeticksを定めるモジュールの本文は取り出していません。言えるのは eventTime の差(9.84〜10.03 秒)までです(§5.2) - CSR1 の on-change に対応するモデルの一覧。17.3 の章が挙げる
show platform software ndbman switch {switch-number | active | standby} modelsは、CSR1 で打っていません。候補の応答と、この一覧を突き合わせてもいません(§6.1) - OpenConfig の interfaces のパスの on-change(CSR1)。7-2 で読んだ OpenConfig の interfaces のパスは on-change の候補(C1〜C7)に入れておらず、CSR1 が受理するかは試していません(§6.1)
- no shutdown の edit の意味。本機が delete の edit に value の
<shutdown/>を付けて何を表したかは確かめていません。draft が参照する YANG-patch の Internet-Draft の本文は取り出しておらず、RFC 8072 の module は delete に value を使いません(§6.2) - on-change の可否の理由(CSR1)。subscription-result の値の定義は機器の本文と章の表にありますが(§5.1)、候補ごとに error-other と error-no-such-option のどちらになったかの理由は、応答と syslog の文言の範囲だけです。xpath の接頭辞(
if:・ios:など)の xmlns の宣言を付けた要求も試していません(§6.4)
10.2 CSR1 の CLI の設定購読と dial-out
- 101 と 102 が 1 本の TCP の接続を使っているか。CLI の Connection の番号と受信器の peer の文字列が同じことまでで、パケットは撮っていません(§7.4)
- kvGPB の時刻の単位。msg_timestamp をミリ秒とみなしたのは telemetry.proto の注釈に基づく仮定で、出力に単位の表示はありません(§7.5)
- 103 の shutdown と no shutdown の 2 本の msg が同じ形になる理由(§7.6)
- 104 の接続の再試行(間隔・回数・バックオフ)。CLI の
Connectingだけを撮りました(§7.7) - 105 の
Encoding: encode-xmlの出どころ(拒まれた投入の行か、既定の表示か。§7.8) - RPC での設定購読の削除(§7.9)と modify-subscription(本機の deviation で not-supported。§4.3)
- 再起動・スイッチオーバーの後の購読と、startup-config への保存(§8)
- TLS の dial-out。CSR1 の設定購読の receiver の行は、投入のエコーと running-config の合計 10 行とも
protocol grpc-tcpで、grpc-tlsは使っていません。17.3 の章の TLS の 2 行は §7.1 - CSR1 の別の版・別の機種の gNMI。17.03.08a の csr1000v が gNMI の有効化の行を拒んだことだけを撮りました(§3.3)
10.3 C9K(cat9000v-uadp 17.15.03)の gNMI
- gNMI の TLS(secure のモード)。gNMI は insecure のモードのサーバ(50052・gnmic は
--insecure)だけで撮り、C9K のSecure serverは Disabled でした(secure の既定の port は 9339)。17.15 の章が Day Zero のセットアップに書く、insecure のモードを止めること(no gnxi server)と、その後に secure のモードを有効にすることも試していません。後始末の確認(Phase Z)の C9K の running-config の gnxi の行は、gnxiとgnxi serverの 2 行でした(§9.1) - gNMI の dial-out(gRPC Tunnel)。本ラボは gRPC Tunnel を撮っておらず、後始末の確認(Phase Z)の C9K の running-config に
grpcを含む行は 0 行でした。show gnxi state detailの末尾の gRPC Tunnel の見出しの下はAdmin state: Enabled・Oper status: Upの 2 行で、この 2 行が何を指すかは確かめていません(§9.1) - Get が通るようになった時刻と、UP の前の Get の応答の中身。取得スクリプトの確認の Get の応答は保存していません(§9.1)
- type の値の接頭辞と、章の値の接頭辞(value prefixing)の 2 文の関係。JSON_IETF の OC の config の Get の type の値は、origin なしと rfc7951 で
iana-if-type:softwareLoopback、legacy(oc-ifの接頭辞のパス)でianaift:softwareLoopbackでした。17.15 の gNMI 章の 2 文は 16.10.1 以降の namespace を書いた部分にあり、直後の例はメンバー名の接頭辞です。2 文が legacy の origin と type の値に当てはまるかは確かめていません。C9K の type の葉の型(identityref か)も、本ラボで取り出していません(§9.3) - PROTO の符号化の Get と Subscribe。撮っていません(§9.3)
- C9K の申告(capabilities model)の読み。on-change-supported の
[null]が章の例の空の要素と同じものか、機器が調べ方の順で実際にどの entry を選ぶかは、出力からは言えません(§9.4) - ONCE・POLL・TARGET_DEFINED が拒まれる理由と、TARGET_DEFINED の details の
\u0000が何を指すか。TARGET_DEFINED の要求の記録にmodeの行が無いことと、機器に届いた要求の中身との関係も、パケットを撮っておらず確かめていません(§9.6) - INTERNAL の理由。status の details の文言の範囲だけです(§9.6)
- ON_CHANGE で description だけの変更が単独で update を出すかと、sync_response が届かなかった理由(§9.6。SAMPLE は gnmic・ON_CHANGE は gnmi_sub.py で撮っていて、同じ道具で比べていない)。17.15 の MDT 章の SubscribeResponse の定義の後の注と、sync_response の記録の関係も確かめていません
- period の単位(C9K)。gNMI の購読の
Period: 1000も出力に単位の表記は無く、言えるのは update の timestamp の差(9.99229 秒と 10.002245 秒)までです(§9.6・§11.6) - C9K の NETCONF の購読と CLI の設定購読。C9K は gNMI だけで撮りました。C9K に netconf-yang を入れた時の振る舞いも撮っていません(§9.1)
10.4 2 台と環境に共通
- 通知の遅れ。測っていません。通知の時刻と CLI の時刻は並べただけです(§5.2・§6.2・§7.6・§9.6)
show clockを撮っていない段の時刻。C9K の Phase G の前半と、両機器の後始末の確認(Phase Z)は、show clockを撮っていません(§3.4)- gnmic の prototext の空白の数。本ラボの gnmic 0.49.0 の記録は名前の後のコロンに空白 2 個でしたが、ほかの版・ほかのビルドの gnmic でも同じかは確かめていません(§11.9)
- syslog の
rate-limitedの件数が指す行。後始末の確認(Phase Z)で撮ったshow loggingの出力の最初の行のrate-limitedは、CSR1 が 3 件、C9K が 2 件でした。いつのどの行か、その行がバッファに入ったかどうかは出力に無く、本節で syslog の行を数えた所と、行が「無し」「0 行」と書いた所は、バッファの行についての観測です(§6.4・§9.6) - 通信量の計数器(名前に octets・pkts を含む葉)が 0 以外の値をとる通知。Loopback0 に通信を流していません(§5.2・§7.5・§9.6)
- 192.168.1.50 が何か。機器の表示に接続元として出るだけで、出力からは言えません(§3・§5.3)
- COL の時計と機器の時計のずれ。両機器の running-config に
ntpの行は無く、時計の合わせ方は撮っていません(§1) - ライセンスと機能の関係。show version にライセンスの行はありますが、gNMI・MDT との関係は本文では扱っておらず、撮ってもいません
- 同じ手順を繰り返した時に同じ値になるか。1 回分の撮影からは言えません
11. 落とし穴・補足
11.1 章が挙げる draft の版と機器のモジュールの版の差
17.3 の章の本文は、NETCONF の購読の RPC を draft-ietf-netconf-subscribed-notifications-03 と draft-ietf-netconf-yang-push-07 の版で書いています。しかし CSR1(17.03.08a)が返したモジュールの reference 文は rfc5277bis-01 と yang-push-04 で、章の参考文献の表もこの 2 本を並べています(§4.4)。-03 の module は ietf-subscribed-notifications という別の名前で、章の購読の RPC の例が使う名前空間は ietf-event-notifications です(§6.1)。章の版の draft を読んで要求を組むと、機器が名乗っていないモジュールの名前空間を書くことになります。機器が名乗るモジュールとその本文は、hello と get-schema の応答で確かめられます(§4)。
章は、update の通知の形式も yang-push-07 に基づくと書いています。
These update notification formats are based on the draft-ietf-netconf-yang-push-07.
本ラボで届いた通知の中身の要素名(datastore-contents-xml・datastore-changes-xml)は、機器が返した ietf-yang-push の本文の notification 文の名前(注釈の外の datastore-contents-string・datastore-changes-string)と違い、章が基づくと書く -07 の Figure 1〜3 の名前(-xml の付かない datastore-contents・datastore-changes)とも違いました。同じ名前が出てくるのは、同じ章の本文の文と例、-04 の例の Figure 1・2・4 で、-07 の例では Figure 4 の datastore-changes-xml だけです(§4.2 の表)。-07 の例の -xml の付かない名前で通知を待つ道具を組むと、本ラボで届いた通知の要素名と合いません。
11.2 機器のモジュールの本文と draft の module の差
CSR1 の ietf-yang-push は、reference 文と revision が yang-push-04 と同じでも、yang-version 1.1; を「Not Supported」の注釈の中に置き、anydata の中身の節点も注釈の中に置いていました(§4.2)。注釈の中は YANG の文として読まれないので、この本文は YANG 1.0 のモジュールになります。draft の module の版と、機器の本文の版は取り違えやすい点です。
11.3 notification:1.1 と notification:2.0
hello の notification:1.1 は RFC 5277 ではなく、draft-ietf-netconf-rfc5277bis-01 の §9 が定める capability です(§4.1)。17.3 の章が本文で挙げる subscribed-notifications-03 は、別の capability(2.0)を名乗るよう書いています。
Publishers supporting the RPCs and Notifications in this document must advertise the capability “urn:ietf:params:netconf:capability:notification:2.0”.
CSR1 の機器の hello に 2.0 は無く、名乗っていたのは 1.0・1.1 と interleave 1.0 でした。capability の版の数字だけで、どの文書の購読に対応するかを決めることはできません。
11.4 章の gNMI 0.4.0 と機器の 0.7.0
17.3 と 17.15 の gNMI 章は gNMI の版を 0.4.0 と書き、C9K(17.15.03)は Capabilities で 0.7.0 を名乗りました(§9.2)。0.7.0 は gnmi.proto(commit 00369d9)の gnmi_service の値と一致します。本節が引いた仕様の文書は Version 0.4.0 のもので、0.7.0 の機器の振る舞いを 0.4.0 の文書の文で説明するときは、版が違うことを断っています。
11.5 17.3 のページの中の後の版の行
17.3 の gNMI 章のページの Feature Information の表には、17.8.1 や 17.11.1 の行も載っています。たとえば、17.11.1 の行は PROTO の符号化に対応したと書いています。
gNMI protocol supports PROTO encoding.
同じページの制限の節は、PROTO を含む 4 つの符号化を対応しないと書いていて、ページの中で版の時点が混ざっています。
JSON, BYTES, PROTO, and ASCI encoding options are not supported.
17.15 の gNMI 章は、PROTO を 17.11.1 からとし、JSON と JSON_IETF を「already supported」と書いています。
PROTO encoding is supported from Cisco IOS XE Dublin 17.11.1.
gNMI protocol supports PROTO encoding along with the already supported JSON and JSON_IETF formats.
C9K(17.15.03)は、Capabilities で JSON・JSON_IETF・PROTO を名乗り、JSON と JSON_IETF の Get に応答し、ASCII の Get を Unimplemented で拒みました(PROTO の Get は撮っていません。17.15 の章は PROTO を Subscribe だけとし、Get と Set には対応しないと書いています。§9.3)。
11.6 MDT の表に現れる gNMI の購読
C9K の gNMI の Subscribe は、CLI の show telemetry ietf subscription に Type: Dynamic・Stream: yang-push の購読として現れ、id も CSR1 の NETCONF の動的購読と同じく 2147483648 から振られていました。SAMPLE の購読の detail の Encoding と Period は、分けて読みます。
Encoding: encode-kvgpb。gnmic の指定は JSON_IETF で、届いた値はjson_ietf_valでした。CLI の表示と、要求と応答の符号化の名前が違いますPeriod: 1000。gnmic の指定は sample_interval 10000000000(ナノ秒の単位で 10 秒。§9.6 の--logの行)でした。17.15 の章は、yang-push の periodic の period を 1/100 秒の単位とし、1000 なら 10 秒ごとと書いています。この単位で読めば、1000 は gnmic の指定と同じ 10 秒です
The period is time, in centiseconds (1/100 of a second), between periodic push updates. A period of 1000 will result in getting updates to the subscribed information every 10 seconds.
C9K(17.15.03)の出力に period の単位の表記は無く、gNMI の購読の Period の表示がこの単位かは確かめていません(§10)。本ラボで言えるのは、Period: 1000 と表示された購読で、〔ツール側〕gnmic の記録の中身のある update の timestamp の差が 9.99229 秒と 10.002245 秒だったことまでです(§9.6)。
11.7 xpath ごとの on-change の可否
on-change は「機器が on-change に対応しているか」ではなく、「その xpath で受け付けるか」で結果が分かれました。CSR1(17.03.08a)は、同じ Loopback0 でも native の設定は受け付け、ietf-interfaces の設定と状態は拒みました(§6.1)。C9K(17.15.03)は、申告に在る(申告の照合は本ラボの道具の側の読み。§9.4)Cisco の状態のモデルの interface で update を返し、申告に無い OC の description を INTERNAL で拒みました(§9.6)。hello の features=on-change も、capabilities model の申告も、そのパスで on-change が届くことの証拠ではありません。届いたかどうかは、通知(update)が来たことで判断します。
17.3 の章は、on-change の購読は階層を辿らないとも書いています。
In addition, on-change subscriptions are not hierarchical. That is, when subscribing to a container that has child containers, changes in the child container are not seen by the subscription.
11.8 失敗の確認に使う status と syslog
本ラボは、終わり方の gRPC の status を逐語で残すために、POLL・TARGET_DEFINED・ON_CHANGE を gnmi_sub.py で撮りました(ONCE と SAMPLE は gnmic)。失敗は、道具が記録した status と、機器の syslog の %GNMIB-6-GRPC_CON_STATE の接続と切断の行を合わせて見ると、どこで終わったかが分かります。申告に無いパスの ON_CHANGE の status は INTERNAL でした。syslog のバッファで、この購読の前後の show clock の間にある Subscribe の行は、接続から 0.004 秒で切断された 1 対だけで、%MDT_SUBSCRIPTION の行は 0 行でした(§9.6)。
syslog に行が「無い」と書いた所は、どれも show logging のバッファに残った行についての観測です。出力の最初の行の rate-limited は CSR1 で 3 件・C9K で 2 件で、どの行のものかは出力にありません。バッファは両機器とも informational・512000 でした(§3・§6.4・§9.6)。
11.9 gnmic の prototext の数え方
本ラボの gnmic 0.49.0 の --format prototext の記録は、名前の後のコロンに空白 2 個が続く形でした(update と sync_response に限らず、timestamp などほかの名前の後も同じ)。〔ツール側〕gnmic が描いた C9K(17.15.03)の SAMPLE の応答の、該当の 2 行は以下のとおりです(§9.6 の出力)。
update: {
…(省略)
sync_response: true
…(省略)この記録を、コロンの無い update { や、コロンの後の空白を 1 個にした形で数えると 0 件になり、SAMPLE が届いていないと誤って読みます。空白の数が、ほかの版・ほかのビルドの gnmic でも同じかは確かめていません(§10)。gnmi_sub.py の記録(update {)とは、コロンの有無が違います。SAMPLE の記録には、中身の無い update(timestamp だけ)も 1 本混じっていました(§9.6)。
11.10 細かい表示の違い
- running-config の xpath の
\: CLI で入れた xpath の二重引用符は、running-config では\"の形で表示され、detail では\が付きません(§7.2) - syslog の並び: 後始末の確認(Phase Z)で撮った両機器の syslog のバッファは、時刻の順に並んでいません(最も早い時刻の行が先頭ではない)。syslog の行を時刻で窓に当てはめる時は、行の順ではなく時刻で並べ直します
- gRPC の status の名前の書き方: gnmic は status の名前を
InvalidArgumentと表示し、gnmi_sub.py はINVALID_ARGUMENTとcode_num3 で記録しました(仕様の文書の書き方はInvalidArgument (3)。§9.6) - discontinuity-time の 1 秒の違い: B1 の 5 本の通知のうち 1 本と B4 の 1 本は、discontinuity-time が他より 1 秒前の値でした(15:08:34 と 15:08:35)。理由は確かめていません
- CDP の空の初回: C5 の初回の push-update は中身が空でした。17.3 の章は、現在存在しないデータへの on-change の購読の初回の同期が空になると書いていますが、C5 がその条件に当たるかは確かめていません(§6.3)。受理と初回の通知があっても、中身が入るとは限りません
12. まとめ
MDT は、YANG のモデルで定めたデータを、購読に応じて機器が送り出す仕組みです。購読する側が RPC で作る動的購読(dial-in)と、機器の設定として作る設定購読(dial-out)があり、違いは誰が接続を張るかと、購読の寿命が何に結び付くかです。gNMI は、要求と応答の Capabilities・Get・Set と、購読の Subscribe を 1 つの gRPC のサービスに持ちます。本ラボで成立した購読(NETCONF の動的購読・CLI の設定購読・gNMI の STREAM)は、どれも要求か設定で始まり、その後は機器が要求を待たずに送り出しました(§1・§2・§8・§9.6)。
csr1000v 17.03.08a は、hello で notification:1.0・interleave:1.0・notification:1.1 を名乗り、購読のモジュールの reference 文は draft-ietf-netconf-rfc5277bis-01 と draft-ietf-netconf-yang-push-04 でした。17.3 の章が本文で挙げる版(-03・-07)とは違い、ietf-yang-push の本文は yang-version 1.1; を注釈の中に置く YANG 1.0 のモジュールでした(§4)。
NETCONF の periodic の購読(period 1000)では、push-update が eventTime で 9.84〜10.03 秒の差で届き、delete-subscription とセッションの終了で購読が消えました。period 50 は拒まれ、syslog に下限 100 の文言がありました(§5)。NETCONF の on-change の購読は、7 本の候補のうち native の設定と章の例の CDP だけが受理され、Loopback0 の 3 つの変更は yang-patch の edit(merge・merge・delete)で届きました。拒否は error-other と error-no-such-option の 2 種で、dampening-period 100 は rpc-error でした(§6)。
CLI の設定購読は、機器が受信器へ gRPC の接続を張り、Mgmt-vrf と global の 2 経路で送り出しました。kvGPB は、periodic ではデータと collection_end_time だけの 2 種の msg、on-change の変更ではデータ 1 本で届きました。待ち受けの無い port は Connecting、encode-xml は投入の行が拒まれ Invalid でした(§7)。
cat9000v-uadp 17.15.03 の gNMI は、netconf-yang を入れずに gnxi と gnxi server(insecure のモード・50052)で立ち、Capabilities で 0.7.0 を名乗りました(章は 0.4.0)。Get は origin(なし・rfc7951・legacy)でパスの接頭辞の規則が違い、Set は CLI に反映しました。Subscribe は ONCE・POLL・TARGET_DEFINED を拒み、SAMPLE は update と sync_response を、申告に在るパスの ON_CHANGE は update 3 本を返し、申告に無い OC のパスは INTERNAL でした(§9)。確かめていないことは §10 にまとめてあります。
13. 次節(7-4 Python on Box / Guest Shell)
本節の受信器(mdt_receiver.py)と gNMI のクライアント(gnmic・gnmi_sub.py)は、どれも機器の外の Ubuntu で動かしました。NETCONF のクライアントも、ラボの外の WSL です。
次節 7-4 は、Python on Box / Guest Shell を扱います。機器の外ではなく、機器の上のスクリプトの実行環境(Guest Shell と IOx)でプログラムを動かす仕組みを見ていきましょう。
14. 出典
本節が参照した資料です。21 件のうち 14 件を 2026 年 10 月 8 日に、cisco-proto の proto 2 件を 10 月 9 日に取得しました。17.3 の 2 章と RFC 6020・7950・7951 の 5 件は、7-2 のときに 2026 年 10 月 1 日に取得したものです。本文中の > の引用は、表の参照日の時点のページとテキストの逐語です。RFC と Internet-Draft の .txt は、ページの区切りや行末のハイフンで割れた語を、取得したテキストのまま引いています。
CSR1 は csr1000v 17.03.08a で Cisco の 17.3.x のガイドを、C9K は cat9000v-uadp 17.15.03 で 17.15.x のガイドを当てています。17.3 の gNMI 章のページは、17.3 より後の版(17.8.1・17.11.1 など)の行も含みます(§11.5)。gnmi.proto と IOS XE の MDT の proto は、本文のコードブロックの照合に使った資料で、> の引用の原典ではありません。IOS XR の telemetry.proto(ios-xr/model-driven-telemetry の commit 11f88d8f の protos/24_2_2/telemetry.proto)は、§7.1 の〔ツール側〕の照合だけに使った資料で、本文では引いていません(取得の URL を記録していないので、表には載せていません)。RFC 8640 は、RFC 8639・RFC 8641 との関係を確かめるために読んだ資料で、本文では引いていません。
| 資料 | 版・更新日(資料の表記) | 参照日 | URL |
|---|---|---|---|
| draft-ietf-netconf-rfc5277bis-01 — Subscribing to Event Notifications | October 27, 2016・Expires: April 30, 2017 | 2026-10-08 | https://www.ietf.org/archive/id/draft-ietf-netconf-rfc5277bis-01.txt |
| draft-ietf-netconf-subscribed-notifications-03 — Custom Subscription to Event Notifications | July 2, 2017・Expires: January 3, 2018 | 2026-10-08 | https://www.ietf.org/archive/id/draft-ietf-netconf-subscribed-notifications-03.txt |
| draft-ietf-netconf-yang-push-04 — Subscribing to YANG datastore push updates | October 28, 2016・Expires: May 1, 2017 | 2026-10-08 | https://www.ietf.org/archive/id/draft-ietf-netconf-yang-push-04.txt |
| draft-ietf-netconf-yang-push-07 — Subscribing to YANG datastore push updates | June 26, 2017・Expires: December 28, 2017 | 2026-10-08 | https://www.ietf.org/archive/id/draft-ietf-netconf-yang-push-07.txt |
| gRPC Network Management Interface (gNMI) — Specification(openconfig/reference の rpc/gnmi/gnmi-specification.md) | commit 2a4f98f4・Version: 0.4.0・Date: November 7th, 2016 | 2026-10-08 | https://raw.githubusercontent.com/openconfig/reference/2a4f98f49683fc0cfb87a2b9d7838a8e2cac9eb4/rpc/gnmi/gnmi-specification.md |
| gnmi.proto(openconfig/gnmi の proto/gnmi/gnmi.proto。gnmi_service 0.4.0) | commit 8a14ac0 | 2026-10-08 | https://raw.githubusercontent.com/openconfig/gnmi/8a14ac0e9ed67e08988f9913243d89f398454824/proto/gnmi/gnmi.proto |
| gnmi.proto(openconfig/gnmi の proto/gnmi/gnmi.proto。gnmi_service 0.7.0) | commit 00369d9 | 2026-10-08 | https://raw.githubusercontent.com/openconfig/gnmi/00369d9017340facae4507445311119c4eff4138/proto/gnmi/gnmi.proto |
| mdt_grpc_dialout.proto(cisco-ie/cisco-proto の proto/xe/。Cisco の MDT 章のリンク先) | commit 9cc3967c | 2026-10-09 | https://raw.githubusercontent.com/cisco-ie/cisco-proto/9cc3967cb1cabbb3e9f92f2c46ed96edf8a0a78b/proto/xe/mdt_grpc_dialout.proto |
| telemetry.proto(cisco-ie/cisco-proto の proto/xe/。Cisco の MDT 章のリンク先) | commit 9cc3967c | 2026-10-09 | https://raw.githubusercontent.com/cisco-ie/cisco-proto/9cc3967cb1cabbb3e9f92f2c46ed96edf8a0a78b/proto/xe/telemetry.proto |
| Programmability Configuration Guide, Cisco IOS XE 17.15.x — Chapter: gNMI Protocol | IOS XE 17.15.x・Updated: August 14, 2024 | 2026-10-08 | https://www.cisco.com/c/en/us/td/docs/ios-xml/ios/prog/configuration/1715/b_1715_programmability_cg/grpc-network-management-interface.html |
| Programmability Configuration Guide, Cisco IOS XE 17.15.x — Chapter: Model-Driven Telemetry | IOS XE 17.15.x・Updated: August 14, 2024 | 2026-10-08 | https://www.cisco.com/c/en/us/td/docs/ios-xml/ios/prog/configuration/1715/b_1715_programmability_cg/model-driven-telemetry.html |
| Programmability Configuration Guide, Cisco IOS XE Amsterdam 17.3.x — Chapter: gNMI Protocol | IOS XE Amsterdam 17.3.x・Updated: July 31, 2020 | 2026-10-01 | https://www.cisco.com/c/en/us/td/docs/ios-xml/ios/prog/configuration/173/b_173_programmability_cg/grpc_network_management_interface.html |
| Programmability Configuration Guide, Cisco IOS XE Amsterdam 17.3.x — Chapter: Model-Driven Telemetry | IOS XE Amsterdam 17.3.x・Updated: July 31, 2020 | 2026-10-01 | https://www.cisco.com/c/en/us/td/docs/ios-xml/ios/prog/configuration/173/b_173_programmability_cg/model_driven_telemetry.html |
| RFC 5277 — NETCONF Event Notifications | RFC 5277(July 2008) | 2026-10-08 | https://www.rfc-editor.org/rfc/rfc5277.txt |
| RFC 6020 — YANG - A Data Modeling Language for the Network Configuration Protocol (NETCONF) | RFC 6020(October 2010) | 2026-10-01 | https://www.rfc-editor.org/rfc/rfc6020.txt |
| RFC 7950 — The YANG 1.1 Data Modeling Language | RFC 7950(August 2016) | 2026-10-01 | https://www.rfc-editor.org/rfc/rfc7950.txt |
| RFC 7951 — JSON Encoding of Data Modeled with YANG | RFC 7951(August 2016) | 2026-10-01 | https://www.rfc-editor.org/rfc/rfc7951.txt |
| RFC 8072 — YANG Patch Media Type | RFC 8072(February 2017) | 2026-10-08 | https://www.rfc-editor.org/rfc/rfc8072.txt |
| RFC 8639 — Subscription to YANG Notifications | RFC 8639(September 2019) | 2026-10-08 | https://www.rfc-editor.org/rfc/rfc8639.txt |
| RFC 8640 — Dynamic Subscription to YANG Events and Datastores over NETCONF(本文では引いていない) | RFC 8640(September 2019) | 2026-10-08 | https://www.rfc-editor.org/rfc/rfc8640.txt |
| RFC 8641 — Subscription to YANG Notifications for Datastore Updates | RFC 8641(September 2019) | 2026-10-08 | https://www.rfc-editor.org/rfc/rfc8641.txt |