gNMI / OpenConfig Telemetry
Read the supported gNMI and OpenConfig operational-state interfaces.
Read the supported gNMI and OpenConfig operational-state interfaces.
rustbgpd exposes gnmi.gNMI for a strict OpenConfig BGP operational-state
subset. It is intended for collectors and tools such as gnmic that already
speak gNMI/OpenConfig.
This is not a full OpenConfig router model, and gnmi.gNMI is outside the
narrow v1 stability contract. The current surface is
deliberately narrow: Capabilities, Get, and Subscribe for BGP global and neighbor
state, plus a small Set subset for durable static BGP neighbor, peer-group,
and dynamic-neighbor-prefix config. Set maps supported OpenConfig mutations onto the ADR-0076 transaction model:
payloads are redacted in audit logs, delete / replace / update operations are
normalized into gNMI application order, and successful mutations build full
candidate TOML before using the same plan/apply/persist/rollback path as native
config transactions.
Design details live in ADR-0070. The complete native gRPC reference remains API.md.
Listener Setup
Network gNMI is registered only on TCP listeners with native mTLS enabled. A
plaintext or bearer-token-only TCP listener serves the native rustbgpd.v1 API
but does not register gnmi.gNMI.
The local Unix socket may also expose gnmi.gNMI as a same-host convenience for
co-located collectors. That UDS path is a rustbgpd extension, not
standards-compliant network gNMI.
Minimal TCP listener:
[global.telemetry.grpc_tcp]
address = "0.0.0.0:50051"
tls_cert_file = "/etc/rustbgpd/certs/server.pem"
tls_key_file = "/etc/rustbgpd/certs/server.key"
tls_client_ca_file = "/etc/rustbgpd/certs/ca.pem"
[security.grpc.roles]
"rustbgpd://observer/collector" = "observer"[security.grpc].enforcement = "tier" is the default and, since v0.63.0, the
only accepted mode. For mTLS listeners, the
principal is derived from the verified client certificate in ADR-0064 order:
rustbgpd: URI SAN, then email SAN, then Subject CN. The principal must have a
matching [security.grpc.roles] entry. Capabilities, Get, and Subscribe
are sensitive_read; Set is operator_only.
Supported RPCs
| RPC | Status |
|---|---|
Capabilities | Returns gNMI version 0.10.0, the OpenConfig modules backing the supported paths, and JSON / JSON_IETF encodings. |
Get | Returns the supported OpenConfig BGP global and neighbor state subset. |
Subscribe | Supports ONCE, POLL, STREAM SAMPLE, and STREAM ON_CHANGE (the last is scoped to the neighbor session-state leaf — see below). |
Set | Operator-only. Supports the static-neighbor, peer-group, and dynamic-neighbor-prefix config subsets below through ADR-0076 transactions; unsupported paths return UNIMPLEMENTED, malformed values return INVALID_ARGUMENT, and transaction precondition failures return FAILED_PRECONDITION. Lower-tier callers receive PERMISSION_DENIED before the handler runs. |
Neighbor snapshots for Get, subscription bootstrap, periodic sampling, and
heartbeat reconciliation use the peer manager's operator-read lane on TLS and
Unix listeners and for dial-out subscriptions. They report the same live
session observations as native neighbor reads and can complete during policy
waits that admit operator reads; they do not pin peers to a common policy
generation. The existing two-second peer-manager budget covers both queue
admission and reply. An unavailable or timed-out snapshot still fails the
request or terminates the subscription with its error; dial-out reconnects.
Set static-neighbor scope
The first supported config surface is static, numbered BGP neighbors under:
/network-instances/network-instance[name=DEFAULT]/protocols/protocol[identifier=BGP][name=BGP]/bgp/neighbors/neighbor[neighbor-address=X]/configSupported operations:
update/replacethe leaf valuesneighbor-address,peer-as,description, andpeer-group.update/replace.../graceful-restart/config/enabled,.../graceful-restart/config/restart-time, and.../graceful-restart/config/stale-routes-time, mapped to nativegraceful_restart,gr_restart_time, andgr_stale_routes_time.stale-routes-timeaccepts whole seconds only; fractional decimal64 values are rejected, never rounded.config/helper-onlyreturnsUNIMPLEMENTED— rustbgpd GR helper behavior is not a per-session knob.- Create a new static neighbor by setting
peer-asunder a concreteneighbor[neighbor-address=X]entry. The list key supplies the durable[[neighbors]].address; ifconfig/neighbor-addressis also supplied, it must match the key. - Delete a whole static neighbor list entry by deleting
.../neighbors/neighbor[neighbor-address=X]. Per gNMI, deleting a missing entry is silently accepted.
Transaction and validation behavior:
- Set payloads are summarized as operation counts only; values are redacted
before
grpc_authzaudit logging because future OpenConfig config leaves can carry credentials. delete,replace, andupdateare prefix-expanded and forwarded in the gNMI-specified application order: all deletes, then replaces, then updates.replaceandupdaterequireTypedValue; the deprecatedValuefield is rejected withINVALID_ARGUMENT.- non-empty
union_replacereturnsUNIMPLEMENTEDuntil dedicated support ships. - the standard gNMI commit-confirmed extension is supported for
commit,confirm,cancel, andset_rollback_durationactions. Unsupported extension types returnUNIMPLEMENTED. - supported changes translate the live runtime config snapshot into candidate TOML and call the ADR-0076 transaction controller. There is no parallel commit path.
- If either the running or generated candidate references external
.rpolgraphs or[policy.datasets]snapshots, a supported non-noop Set is rejected before mutation: those bytes are outside the transaction token and rollback boundary. A true no-op remains a no-op. Deploy the TOML and external files together and use SIGHUP. (The native transaction API's targeted pure-[[fib_tables]]exception is not a gNMI Set surface.) - unsupported config leaves, including
enabled,local-as, auth, timers, transport, BFD, AFI-SAFI, policy, route-reflector/client, route-server-client, and Add-Path settings, returnUNIMPLEMENTED. - IPv6 link-local / BGP unnumbered neighbor Set is deferred because OpenConfig's
neighbor-addresskey does not carry the interface identity rustbgpd needs to identify those peers safely. peer-groupreferences must name an existing rustbgpd peer group.- Create a peer group in its own Set transaction before referencing it from a new neighbor. ADR-0076 still rejects mixed-family candidates such as "create peer group and add neighbor" in one Set when the combined diff cannot be classified as one supported transaction family.
Set peer-group scope
The supported peer-group config surface is under:
/network-instances/network-instance[name=DEFAULT]/protocols/protocol[identifier=BGP][name=BGP]/bgp/peer-groups/peer-group[peer-group-name=NAME]Supported operations:
update/replace.../config/peer-group-name. The value must match thepeer-group[peer-group-name=NAME]key; setting it creates an empty native[peer_groups.NAME]entry when one does not already exist.update/replace.../config/auth-password, mapped to nativemd5_password.update/replace.../config/remove-private-as, mapped to nativeremove_private_as. The bridge accepts rustbgpd's native values (remove,all,replace) and common OpenConfig identity spellings such asPRIVATE_AS_REMOVE_ALL.update/replace.../timers/config/hold-time, mapped to nativehold_time.update/replace.../graceful-restart/config/enabled,.../graceful-restart/config/restart-time, and.../graceful-restart/config/stale-routes-time, mapped to the native inheritedgraceful_restart,gr_restart_time, andgr_stale_routes_timegroup keys, with the same value rules as the static-neighbor graceful-restart scope above.- Delete a whole peer-group list entry by deleting
.../peer-groups/peer-group[peer-group-name=NAME]. Per gNMI, deleting a missing entry is silently accepted.
Transaction and validation behavior:
- Peer-group Set changes use the same candidate-TOML transaction path as native config changes. Unused peer-group catalog edits commit as catalog-only transactions; edits that affect live sessions use ADR-0076's peer-group/session reshape executor — static members are reconfigured in place, and live dynamic sessions accepted by an affected range are gracefully reset after persist to re-accept under the committed config (ADR-0086).
- The external-policy-input fence above applies even when the requested peer-group leaf itself is unrelated to policy; the executor would otherwise adopt the whole generated candidate snapshot.
- If a candidate peer-group edit would affect a dynamic-neighbor range in a way that the transaction model cannot safely reshape (for example a range peer-group reassignment, or mixed policy/session impact), the transaction is rejected by the native planner rather than silently drifting.
- OpenConfig peer-group leaves without a native inherited config model remain
unsupported, including
config/peer-as,config/local-as,config/peer-type,config/send-community-type, andconfig/description.
Set dynamic-neighbor-prefix scope
The supported dynamic-neighbor-prefix surface is under:
/network-instances/network-instance[name=DEFAULT]/protocols/protocol[identifier=BGP][name=BGP]/bgp/global/dynamic-neighbor-prefixes/dynamic-neighbor-prefix[prefix=P]Supported operations:
update/replace.../config/prefix. The value must match thedynamic-neighbor-prefix[prefix=P]key.update/replace.../config/peer-group, referencing an existing native peer group.- Delete a whole dynamic-neighbor-prefix list entry by deleting
.../dynamic-neighbor-prefix[prefix=P]. Per gNMI, deleting a missing entry is silently accepted.
Transaction and validation behavior:
- OpenConfig dynamic ranges expose
prefixandpeer-grouponly. rustbgpd maps an OpenConfig-created range to native[[dynamic_neighbors]]withremote_asn = 0(accept any ASN from the peer's OPEN) and no description. - Native config validation still applies:
peer-groupmust exist, exact duplicate effective prefixes are rejected, IPv4/IPv6 prefix lengths are bounded, overlapping different-length ranges are allowed, and BFD-enabled peer groups are rejected for dynamic ranges. - Dynamic range changes use the existing
[[dynamic_neighbors]]full-set transaction family. Creating a peer group and dynamic range in the same Set may still be rejected as a mixed-family candidate; create the peer group first, then apply the dynamic range. - Dynamic-neighbor state paths and native-only fields such as range
descriptionor explicitremote_asnare not supported by OpenConfig Set.
Set commit-confirmed workflow
The gNMI Commit extension maps onto the same ADR-0076 commit-confirmed
controller used by rbgp config apply --confirm-id:
CommitRequeststarts a confirmed Set. It must include normal Set operations and a non-emptyid; the optionalrollback_durationmaps to the native confirm timeout. If omitted, the native default timeout is used.CommitConfirmconfirms a pending transaction. It must carry only the extension, with no delete / replace / update operations.CommitCancelaborts and rolls back a pending transaction. It must also carry only the extension.CommitSetRollbackDurationresets the rollback timer for the pending transaction. Itsidmust match the pending transaction, it must include a positive whole-secondrollback_duration, and it overwrites the current timer rather than appending time.
Only one confirmed transaction may be pending at a time. While pending, normal
Set mutations return FAILED_PRECONDITION until the transaction is confirmed,
canceled, or auto-reverted.
STREAM ON_CHANGE v1 scope
STREAM ON_CHANGE covers the
…/neighbor[neighbor-address=*]/state/session-state leaf only.
Both the explicit * wildcard (the form gnmic and most OpenConfig
collectors emit) and the no-key shorthand …/neighbor/state/session-state
lower to "all configured neighbors"; a concrete address is also
accepted.
- EHM required.
Subscribe ON_CHANGEsources transitions from the durable event broadcast (ADR-0072). When[event_history]is disabled or EHM is in pass-through, the RPC returnsFAILED_PRECONDITIONimmediately on subscribe. - Initial sync. The handler emits one OpenConfig leaf
Updateper configured peer (including non-Established peers —IDLE/CONNECT/ACTIVE/OPENSENT/OPENCONFIRM/ESTABLISHED) followed bysync_response. Withupdates_only, it emits the sync without an initial peer snapshot; later events and heartbeats remain active. - Live stream. For every FSM transition committed to EHM under
EVENT_CATEGORY_SESSION, the handler emits a singlesession-stateleafUpdatewith the new short-form state. An authoritative peer removal emits that exact leaf inNotification.delete; the producer emits one removal per managed-peer lifecycle, and a later peer add or state transition makes the path present again. Exact deletes are idempotent: an event racing a due heartbeat may expose the same delete twice. A normal stream seeds presence only after its initial Update is accepted by the response channel, so removing a peer absent from that baseline is silent. Anupdates_onlystream deliberately has no baseline: its first post-sync peer-removal event is therefore emitted as a delete, as the next observedON_CHANGEtransition. - Heartbeat. A nonzero per-path
heartbeat_intervalfrom 1 second through 1 hour emits the current leaf value on a fixed monotonic cadence anchored after initial sync. Co-due paths share one peer snapshot, missed periods are skipped without bursts, and live events neither satisfy nor rearm heartbeats. A due snapshot deletes only previously delivered leaves covered by those due paths that are now absent. A newer live event cancels any overlapping pending actor snapshot before delivery; the still-due heartbeat is then rendered afresh, preventing stale state from overtaking the event. Presence tracking retains no absent tombstones, so a healthy, event-complete wildcard stream scales with its delivered/current roster rather than lifetime address churn. - Reconnect. gNMI carries no cursor on reconnect, so a fresh
subscription gets a fresh initial snapshot — the disconnect
window is not replayed. Collectors that need historical
replay use
EventService.SubscribeFromEventdirectly. - Unsupported leaves. Any other path under
ON_CHANGEreturnsUNIMPLEMENTEDwith a message naming the supported leaf. The counter leaves (messages/*) and theenabledleaf stay SAMPLE/POLL-only. - Loss. Broadcast lag or a later producer-side EHM loss closes the stream
with
DATA_LOSS, including during the initial snapshot orsync_response. To repair the gap, reconnect withoutupdates_onlyand consume a full initial snapshot. A fresh subscription baselines prior loss; it is not permanently poisoned by the process-lifetime degraded latch. The producer signal is service-wide, so loss in any event category closes every ON_CHANGE stream rather than risking a silently incomplete view. - Mixed-mode subscriptions. A
SubscriptionListthat mixesSAMPLEandON_CHANGEsubscriptions is rejected withUNIMPLEMENTED— the current dispatch picks one mode per stream.
Broad subtree requests are bounded; the current surface does not use gNMI to stream the full route table.
A concrete keyed-neighbor subscription whose successful peer snapshot does not
contain that neighbor emits no update for the cycle; sync still completes and
POLL/STREAM remain live for later appearances. Concrete neighbor Get returns
NOT_FOUND for an unknown neighbor, except during startup: until the
configured-peer roster is installed it returns retryable UNAVAILABLE (see
API.md). Peer-snapshot failures
remain UNAVAILABLE.
Dial-out (device-initiated push)
Everything above is dial-in: a collector connects to the daemon. The
[gnmi_dialout] config section inverts only the transport direction —
the daemon opens a persistent gRPC connection to each configured
collector and pushes the exact SubscribeResponse stream the dial-in
Subscribe server would produce for the same subscription (initial
snapshot, sync_response, then SAMPLE ticks or ON_CHANGE events; same
supported paths, same ON_CHANGE scope, same validation). This is the
ingestion model large fleets use: devices behind NAT push to a central
sink instead of every collector dialing every device.
The wire contract is rustbgpd.gnmi_dialout.v1.GnmiDialout/Publish
(proto/rustbgpd_dialout.proto): the device is the gRPC client and
sends stream gnmi.SubscribeResponse; the collector's response stream
is reserved for future flow control and may stay silent. This mirrors
the de-facto vendor dial-out shape without impersonating any vendor
namespace; a collector implements one trivially by serving that proto.
The OpenConfig grpc-tunnel model solves the same reachability inversion
at the transport layer and remains a possible future alternative.
Subscriptions are declared in config (paths + sample/on_change mode
per target), TLS uses the standard tls_ca_file/tls_cert_file/
tls_key_file path idiom, reconnects use capped exponential backoff,
and connection state, bounded response-queue depth, resync count, and the last
transport-handoff timestamp are exported as gnmi_dialout_*{target} metrics.
Full field reference: docs/reference/configuration.md [gnmi_dialout];
operational behavior: docs/reference/operations.md.
Supported Paths
All paths hang under the default network instance and BGP protocol:
/network-instances/network-instance[name=DEFAULT]/protocols/protocol[identifier=BGP][name=BGP]/bgpThe default network-instance key is DEFAULT. The BGP protocol identifier uses
the bare identity value BGP, not oc-pol-types:BGP. The protocol name is the
operator-assigned instance name; BGP is the normal rustbgpd value.
Supported global state:
/network-instances/network-instance[name=DEFAULT]/protocols/protocol[identifier=BGP][name=BGP]/bgp/global/state
/network-instances/network-instance[name=DEFAULT]/protocols/protocol[identifier=BGP][name=BGP]/bgp/global/state/as
/network-instances/network-instance[name=DEFAULT]/protocols/protocol[identifier=BGP][name=BGP]/bgp/global/state/router-idSupported neighbor state:
/network-instances/network-instance[name=DEFAULT]/protocols/protocol[identifier=BGP][name=BGP]/bgp/neighbors/neighbor[neighbor-address=X]/state
/network-instances/network-instance[name=DEFAULT]/protocols/protocol[identifier=BGP][name=BGP]/bgp/neighbors/neighbor[neighbor-address=X]/state/neighbor-address
/network-instances/network-instance[name=DEFAULT]/protocols/protocol[identifier=BGP][name=BGP]/bgp/neighbors/neighbor[neighbor-address=X]/state/enabled
/network-instances/network-instance[name=DEFAULT]/protocols/protocol[identifier=BGP][name=BGP]/bgp/neighbors/neighbor[neighbor-address=X]/state/peer-as
/network-instances/network-instance[name=DEFAULT]/protocols/protocol[identifier=BGP][name=BGP]/bgp/neighbors/neighbor[neighbor-address=X]/state/local-as
/network-instances/network-instance[name=DEFAULT]/protocols/protocol[identifier=BGP][name=BGP]/bgp/neighbors/neighbor[neighbor-address=X]/state/session-state
/network-instances/network-instance[name=DEFAULT]/protocols/protocol[identifier=BGP][name=BGP]/bgp/neighbors/neighbor[neighbor-address=X]/state/established-transitions
/network-instances/network-instance[name=DEFAULT]/protocols/protocol[identifier=BGP][name=BGP]/bgp/neighbors/neighbor[neighbor-address=X]/state/messagesFor scoped IPv6 link-local neighbors, the OpenConfig neighbor-address key is
the bare IP address, not fe80::x%ifname. rustbgpd v1 rejects configuring the
same link-local neighbor address on multiple interfaces, so the bare key remains
unambiguous.
gnmic Examples
Set these once for the examples:
export RUSTBGPD_GNMI_ADDR=rustbgpd.example.net:50051
export RUSTBGPD_TLS_CA=/etc/rustbgpd/certs/ca.pem
export RUSTBGPD_TLS_CERT=/etc/operator/collector.pem
export RUSTBGPD_TLS_KEY=/etc/operator/collector.key
export RUSTBGPD_TLS_SERVER_NAME=rustbgpd.example.net
export OC_BGP='/network-instances/network-instance[name=DEFAULT]/protocols/protocol[identifier=BGP][name=BGP]/bgp'Capabilities:
gnmic \
--address "$RUSTBGPD_GNMI_ADDR" \
--tls-ca "$RUSTBGPD_TLS_CA" \
--tls-cert "$RUSTBGPD_TLS_CERT" \
--tls-key "$RUSTBGPD_TLS_KEY" \
--tls-server-name "$RUSTBGPD_TLS_SERVER_NAME" \
capabilitiesGlobal state:
gnmic \
--address "$RUSTBGPD_GNMI_ADDR" \
--tls-ca "$RUSTBGPD_TLS_CA" \
--tls-cert "$RUSTBGPD_TLS_CERT" \
--tls-key "$RUSTBGPD_TLS_KEY" \
--tls-server-name "$RUSTBGPD_TLS_SERVER_NAME" \
get \
--encoding json_ietf \
--type STATE \
--path "$OC_BGP/global/state"One neighbor:
gnmic \
--address "$RUSTBGPD_GNMI_ADDR" \
--tls-ca "$RUSTBGPD_TLS_CA" \
--tls-cert "$RUSTBGPD_TLS_CERT" \
--tls-key "$RUSTBGPD_TLS_KEY" \
--tls-server-name "$RUSTBGPD_TLS_SERVER_NAME" \
get \
--encoding json_ietf \
--type STATE \
--path "$OC_BGP/neighbors/neighbor[neighbor-address=10.0.0.2]/state"Add and delete a static numbered neighbor:
gnmic \
--address "$RUSTBGPD_GNMI_ADDR" \
--tls-ca "$RUSTBGPD_TLS_CA" \
--tls-cert "$RUSTBGPD_TLS_CERT" \
--tls-key "$RUSTBGPD_TLS_KEY" \
--tls-server-name "$RUSTBGPD_TLS_SERVER_NAME" \
set \
--update "$OC_BGP/neighbors/neighbor[neighbor-address=10.0.0.3]/config/peer-as:::uint:::65003"
gnmic \
--address "$RUSTBGPD_GNMI_ADDR" \
--tls-ca "$RUSTBGPD_TLS_CA" \
--tls-cert "$RUSTBGPD_TLS_CERT" \
--tls-key "$RUSTBGPD_TLS_KEY" \
--tls-server-name "$RUSTBGPD_TLS_SERVER_NAME" \
set \
--delete "$OC_BGP/neighbors/neighbor[neighbor-address=10.0.0.3]"Commit-confirmed Set:
gnmic \
--address "$RUSTBGPD_GNMI_ADDR" \
--tls-ca "$RUSTBGPD_TLS_CA" \
--tls-cert "$RUSTBGPD_TLS_CERT" \
--tls-key "$RUSTBGPD_TLS_KEY" \
--tls-server-name "$RUSTBGPD_TLS_SERVER_NAME" \
set \
--commit-id deploy-42 \
--commit-request \
--rollback-duration 120s \
--update "$OC_BGP/neighbors/neighbor[neighbor-address=10.0.0.4]/config/peer-as:::uint:::65004"
gnmic \
--address "$RUSTBGPD_GNMI_ADDR" \
--tls-ca "$RUSTBGPD_TLS_CA" \
--tls-cert "$RUSTBGPD_TLS_CERT" \
--tls-key "$RUSTBGPD_TLS_KEY" \
--tls-server-name "$RUSTBGPD_TLS_SERVER_NAME" \
set \
--commit-id deploy-42 \
--commit-confirmTo abort the pending change before the timeout, use --commit-cancel with the
same --commit-id.
Sampled stream:
gnmic \
--address "$RUSTBGPD_GNMI_ADDR" \
--tls-ca "$RUSTBGPD_TLS_CA" \
--tls-cert "$RUSTBGPD_TLS_CERT" \
--tls-key "$RUSTBGPD_TLS_KEY" \
--tls-server-name "$RUSTBGPD_TLS_SERVER_NAME" \
subscribe \
--encoding json_ietf \
--mode stream \
--stream-mode sample \
--sample-interval 10s \
--path "$OC_BGP/global/state/router-id"For STREAM/SAMPLE, a zero/missing --sample-interval uses the 1-second floor.
Nonzero intervals from 1 second through 1 hour are retained exactly; sub-second
or above-1-hour requests fail with INVALID_ARGUMENT. Multiple SAMPLE paths in
one subscription retain their own accepted intervals; co-due neighbor paths
share one peer snapshot, and delayed ticks skip missed periods without bursts.
STREAM/SAMPLE also supports per-path suppress_redundant and
heartbeat_interval. Suppression compares the exact rendered TypedValue at
each fully resolved leaf path and emits changed, new, or reappearing leaves at
the next sample deadline. A nonzero heartbeat from 1 second through 1 hour
forces all current leaves on its own fixed monotonic cadence; zero disables it.
Missed heartbeat periods are skipped, and coincident sample/heartbeat deadlines
coalesce into one batch and one peer snapshot. With updates_only, suppressed
paths are read into the hidden comparison baseline before sync_response, but
their initial values are withheld.
Nondefault controls on ONCE/POLL return INVALID_ARGUMENT. ON_CHANGE rejects
suppress_redundant with INVALID_ARGUMENT but accepts the same nonzero
1-second-through-1-hour heartbeat_interval bounds as SAMPLE. STREAM/
TARGET_DEFINED remains unsupported.
Troubleshooting
| Symptom | Likely cause |
|---|---|
gnmi.gNMI is missing on a TCP listener | The listener is plaintext or bearer-token-only. Configure native mTLS with tls_cert_file, tls_key_file, and tls_client_ca_file. |
PERMISSION_DENIED | The method exceeds the listener max_tier, the mTLS principal is not mapped in [security.grpc.roles], or the mapped role is below the method tier. |
UNIMPLEMENTED for a path | The path is valid OpenConfig but outside rustbgpd's supported whitelist. This is expected for per-AFI counters, negotiated capabilities, last-established, and unsupported subtrees. |
INVALID_ARGUMENT | The path is malformed, uses unsupported key syntax, or omits required keys such as network-instance, protocol, or neighbor-address. |
NOT_FOUND | The requested keyed object does not exist, such as a neighbor address that is not configured. |
UNAVAILABLE | The daemon is starting and the configured-peer roster is not installed yet (retry), or the peer snapshot failed. |
Set returns UNIMPLEMENTED | The path or extension is outside the supported Set subset, such as unsupported neighbor leaves, union_replace, or a non-Commit extension. |
Interop Proof
M54 validates this surface with the real gnmic client over mTLS, including
Capabilities, Get, Set add/delete, commit-confirmed Set confirm/cancel,
Set denial for an observer principal (sensitive_read ceiling),
unsupported-path rejection, and Subscribe SAMPLE:
bash tests/interop/scripts/gen-m54-certs.sh
containerlab deploy -t tests/interop/m54-gnmi-openconfig.clab.yml
bash tests/interop/scripts/test-m54-gnmi-openconfig.sh
containerlab destroy -t tests/interop/m54-gnmi-openconfig.clab.yml --cleanup