Skip to content

Commit 3f64f7d

Browse files
adding doc for gnmi-dial-out, fixing spacing issues
1 parent 4b14b59 commit 3f64f7d

File tree

6 files changed

+398
-263
lines changed

6 files changed

+398
-263
lines changed

docs/_media/gnmi-dial-in.png

428 KB
Loading

docs/_media/gnmi-dial-out.png

177 KB
Loading

docs/_media/gnmi-tunnel.png

175 KB
Loading
Lines changed: 397 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,397 @@
1+
## Overview
2+
3+
The OpenConfig gNMI service typically operates on a **dial-in model**, where the client/collector initiates the
4+
connection with the gNMI server (running on switch).
5+
6+
However, this model has limitations if the client cannot connect to the server, due to factors like firewalls blocking
7+
inbound connections or the server being behind a router implementing NAT.
8+
9+
To address such issues, a **dial-out model** is more advantageous, allowing the server to instantiate a connection
10+
in reverse to the client/collector.
11+
12+
| Dial-in | Dial-out |
13+
|:-------:| :-------:|
14+
|![dial-in](../../../_media/gnmi-dial-in.png)|![dial-in](../../../_media/gnmi-dial-out.png)|
15+
16+
This page provides examples for configuring and using gNMI Dial-out on EOS, which can be achieved using two methods:
17+
18+
1. gNMIReverse client
19+
2. gNMI Dial-out via gRPC Tunnel
20+
21+
### gNMIReverse client
22+
23+
gNMIReverse client is a Dial-Out gRPC service
24+
([GitHub](https://github.com/aristanetworks/goarista/tree/master/cmd/gnmireverse_client))
25+
that reverses the direction of the dial for gNMI Subscriptions, where the gNMIReverse client running along with
26+
gNMI target (on the switch) sends data to the gNMIReverse Server.
27+
28+
#### Building the gNMIReverse binaries
29+
30+
:information_source: [Go](https://go.dev/doc/install) is required for compiling the
31+
gNMIReverse client and server binaries.
32+
33+
Once Go is set up, run the following commands to compile the `gnmireverse_client` binary,
34+
which will be installed on the switch.
35+
36+
For 32-bit EOS:
37+
38+
```shell
39+
GOOS=linux GOARCH=386 CGO_ENABLED=0 go install github.com/aristanetworks/goarista/cmd/gnmireverse_client@latest
40+
```
41+
42+
For 64-bit EOS:
43+
44+
```shell
45+
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go install github.com/aristanetworks/goarista/cmd/gnmireverse_client@latest
46+
```
47+
48+
This will build the `gnmireverse_client` binary in the `$GOPATH/bin` or `$GOPATH/bin/linux_386` or
49+
`$GOPATH/bin/linux_amd64` directory.
50+
51+
:information_source: **Note**: To find the architecture of EOS, use the following command:
52+
53+
```text
54+
switch# show version | include Arch
55+
Architecture: i686 <<-- 32 bit architecture
56+
57+
switch# show version | include Arch
58+
Architecture: x86_64 <<-- 64 bit architecture
59+
```
60+
61+
Copy the client binary to `/mnt/flash` directory on the switch, using scp or WinSCP
62+
63+
```shell
64+
scp $GOPATH/bin/linux_amd64/gnmireverse_client <USERNAME>@<switch-MGMT-IP>:/mnt/flash/
65+
```
66+
67+
To build the collector binary implementing a gNMIReverse server, use the following command:
68+
69+
```shell
70+
go install github.com/aristanetworks/goarista/cmd/gnmireverse_server@latest
71+
```
72+
73+
:information_source: **Note**: Starting from release EOS-4.28.1 `gnmireverse_client` and `gnmireverse_server`
74+
binaries are also bundled with Octa on EOS.
75+
76+
```text
77+
leaf2# show version | include Soft|Arch
78+
Software image version: 4.28.1F-27567367.4281F
79+
Architecture: x86_64
80+
81+
leaf2# bash which gnmireverse_client; which gnmireverse_server
82+
/usr/bin/gnmireverse_client
83+
/usr/bin/gnmireverse_server
84+
85+
leaf2# bash gnmireverse_client --help
86+
Usage of gnmireverse_client:
87+
-clientSideWildcard
88+
forces client side wildcard resolution (default true)
89+
-collector_addr string
90+
Address of collector in the form of [<vrf-name>/]host:port.
91+
The host portion must be enclosed in square brackets if it is a literal IPv6 address.
92+
For example, -collector_addr mgmt/[::1]:1234
93+
<--snipped-->
94+
```
95+
96+
#### gNMIReverse client configuration
97+
98+
Before proceeding, the gNMI server needs to be enabled on the switch,
99+
refer to [this](../../../configuration/openconfig.md#gnmi)
100+
section for sample configuration.
101+
102+
:information_source: **Note**: If subscribing to `eos_native` paths, Octa also needs to be enabled.
103+
Refer to [this](../../../configuration/openconfig.md#octa) section for more details on Octa.
104+
105+
To see the full list of options and documentation, run `gnmireverse_client --help`.
106+
Some of the important flags are explained
107+
[in this section](https://github.com/aristanetworks/goarista/tree/master/cmd/gnmireverse_client#options).
108+
109+
With gNMI server enabled, gNMIReverse client daemon can be configured as follows:
110+
111+
> Default VRF
112+
113+
```text
114+
!
115+
daemon gnmireverse
116+
exec /mnt/flash/gnmireverse_client -target_value=leaf1
117+
-collector_addr=192.185.128.100:30000 -collector_tls=false
118+
-sample /interfaces/interface[name=Ethernet1]/state/counters@30s
119+
-subscribe system/memory/state/free
120+
no shutdown
121+
!
122+
```
123+
124+
:information_source: **Note**: When configuring on EOS CLI, combine the wrapped exec command flags into a single line.
125+
126+
In above example both gNMI server and collector are in *default VRF*:
127+
128+
- Target is the default Unix domain socket gNMI server, which does not require authentication.
129+
- The collector/client `192.185.128.100` is reachable via the default VRF on port 30000.
130+
- Counters for Interface Ethernet1 are sampled at a 30-second interval
131+
- Subscription is done for OpenConfig path `system/memory/state/free`.
132+
133+
> Non default VRF
134+
135+
```text
136+
!
137+
daemon gnmireverse
138+
exec /mnt/flash/gnmireverse_client
139+
-target_addr=MGMT/172.100.100.2:6030 -target_value=spine1
140+
-username=admin -password=admin
141+
-collector_addr=MGMT/192.185.128.100:30000 -collector_tls=false
142+
-get_sample_interval=10s -get interfaces/interface/state/oper-status
143+
-get components/component/state/memory -get eos_native:/Eos/image
144+
no shutdown
145+
!
146+
```
147+
148+
:information_source: **Note**: When configuring on EOS CLI, combine the wrapped exec command flags into a single line.
149+
150+
In above example both gNMI server and collector are in *non default VRF* named `MGMT`:
151+
152+
- Target is the Ma1 interface IP in the `MGMT` VRF, utilizing the authentication credentials `admin/admin`.
153+
- The collector/client `192.185.128.100` is reachable via the `MGMT` VRF on port 30000.
154+
- A gNMI Get request is issued every 10 seconds to retrieve
155+
- all interfaces operational status
156+
- system memory
157+
- EOS image information from the EOS native path.
158+
159+
#### Running the gNMIReverse Server
160+
161+
Using the following command, the gNMIReverse server is started on the collector
162+
163+
```shell
164+
gnmireverse_server -tls=false -addr=192.185.128.100:30000 -debug -1
165+
```
166+
167+
<details><summary>Reveal output</summary>
168+
<p>
169+
```shell
170+
client=172.100.100.2:34152 res=get n=0 rx_time=2025-10-21T05:42:21.103533957Z notif_time=2025-10-21T05:42:21.102427813Z
171+
last_rx_ago=0s last_notif_ago=0s latency=0s path=/interfaces/interface[name=Ethernet1]/state/oper-status val=UP
172+
client=172.100.100.2:34152 res=get n=0 rx_time=2025-10-21T05:42:21.103533957Z notif_time=2025-10-21T05:42:21.102427813Z
173+
last_rx_ago=0s last_notif_ago=0s latency=0s path=/interfaces/interface[name=Ethernet2]/state/oper-status val=UP
174+
client=172.100.100.2:34152 res=get n=0 rx_time=2025-10-21T05:42:21.103533957Z notif_time=2025-10-21T05:42:21.102427813Z
175+
last_rx_ago=0s last_notif_ago=0s latency=0s path=/interfaces/interface[name=Management1]/state/oper-status val=UP
176+
client=172.100.100.2:34152 res=get n=0 rx_time=2025-10-21T05:42:21.103533957Z notif_time=2025-10-21T05:42:21.102427813Z
177+
client=172.100.100.2:34152 res=get n=0 rx_time=2025-10-21T05:42:21.103533957Z notif_time=2025-10-21T05:42:21.102427813Z
178+
last_rx_ago=0s last_notif_ago=0s latency=0s path=/Eos/image/displayVersion val=4.35.0F-44178984.4350F
179+
client=172.100.100.2:34152 res=get n=0 rx_time=2025-10-21T05:42:21.103533957Z notif_time=2025-10-21T05:42:21.102427813Z
180+
last_rx_ago=0s last_notif_ago=0s latency=0s path=/Eos/image/serialNum val=33b708fe-8b04-48db-bb84-7f77a6b3cc66
181+
client=172.100.100.2:34152 res=get n=0 rx_time=2025-10-21T05:42:21.103533957Z notif_time=2025-10-21T05:42:21.102427813Z
182+
last_rx_ago=0s last_notif_ago=0s latency=0s path=/Eos/image/version val=4.35.0F
183+
client=172.100.100.2:34152 res=get n=0 rx_time=2025-10-21T05:42:21.103533957Z notif_time=2025-10-21T05:42:21.102427813Z
184+
last_rx_ago=0s last_notif_ago=0s latency=0s path=/Eos/image/arch val=x86_64
185+
client=172.100.100.2:34152 res=get n=0 rx_time=2025-10-21T05:42:21.103533957Z notif_time=2025-10-21T05:42:21.102427813Z
186+
last_rx_ago=0s last_notif_ago=0s latency=0s path=/Eos/image/blessed val=false
187+
client=172.100.100.2:34152 res=get n=0 rx_time=2025-10-21T05:42:21.103533957Z notif_time=2025-10-21T05:42:21.102427813Z
188+
last_rx_ago=0s last_notif_ago=0s latency=0s path=/Eos/image/flavor val=cEOS
189+
client=172.100.100.2:34152 res=get n=0 rx_time=2025-10-21T05:42:21.103533957Z notif_time=2025-10-21T05:42:21.102427813Z
190+
last_rx_ago=0s last_notif_ago=0s latency=0s path=/Eos/image/name val=image
191+
client=172.100.100.2:34152 res=get n=0 rx_time=2025-10-21T05:42:21.103533957Z notif_time=2025-10-21T05:42:21.102427813Z
192+
last_rx_ago=0s last_notif_ago=0s latency=0s path=/Eos/image/release val=44178984.4350F
193+
client=172.100.100.2:34152 res=get n=0 rx_time=2025-10-21T05:42:21.103533957Z notif_time=2025-10-21T05:42:21.102427813Z
194+
last_rx_ago=0s last_notif_ago=0s latency=0s path=/Eos/image/variant val=US
195+
client=172.100.100.2:34152 res=get n=0 rx_time=2025-10-21T05:42:21.103533957Z notif_time=2025-10-21T05:42:21.102427813Z
196+
last_rx_ago=0s last_notif_ago=0s latency=0s path=/Eos/image/buildHost val=dhcp-224-68-53.sjc.aristanetworks.com
197+
client=172.100.100.2:34152 res=get n=0 rx_time=2025-10-21T05:42:21.103533957Z notif_time=2025-10-21T05:42:21.102427813Z
198+
last_rx_ago=0s last_notif_ago=0s latency=0s path=/Eos/image/buildTime val=1759431887000000000
199+
```
200+
201+
</p>
202+
</details>
203+
204+
#### Troubleshooting
205+
206+
Use the following command to check the logs for configured gnmireverse daemon:
207+
208+
```shell
209+
show agent gnmireverse logs
210+
```
211+
212+
### gNMI Dial-out via gRPC Tunnel
213+
214+
Another way for using gNMI Dial-out involves leveraging the
215+
gRPC Tunnel [specification](https://github.com/openconfig/grpctunnel/blob/main/doc/grpctunnel_design.md).
216+
For more details on this feature
217+
refer to [EOS TOI](https://www.arista.com/en/support/toi/eos-4-27-0f/14851-gnmi-dial-out-via-grpc-tunnel).
218+
219+
In this method the gNMI Dial-out sequence involves the following steps:
220+
221+
- The gRPC tunnel client on the switch initiates a connection, dialing out to the collector.
222+
- The collector, running a gRPC tunnel server, listens for and accepts the incoming tunnel request.
223+
- A secure gRPC tunnel session is established between the switch and the collector.
224+
- The collector sends a gNMI request to the gNMI server, via the established gRPC tunnel.
225+
- The gNMI server returns the corresponding responses to the collector via the same tunnel.
226+
227+
![grpc-tunnel](../../../_media/gnmi-tunnel.png)
228+
229+
#### gRPC tunnel client configuration
230+
231+
Under `management api gnmi` use the `transport grpc-tunnel <name>` to configure a gRPC tunnel client.
232+
233+
```text
234+
!
235+
management api gnmi
236+
transport grpc-tunnel tunnel1
237+
vrf MGMT
238+
destination 192.185.128.100 port 30000
239+
local interface Management1 port 50000
240+
target spine1
241+
provider eos-native
242+
!
243+
```
244+
245+
The above example configures a gRPC tunnel client named `tunnel1` (*multiple such clients can be configured*):
246+
247+
- The client is dialing out from non default VRF `MGMT`, this config is optional.
248+
- The collector is running on 192.185.128.100 on port 30000, **this is a required configuration to start the client**.
249+
- The client dials out using the Management1 interface IP and port 50000, this config is optional.
250+
- The target ID is `spine1`, this is a user defined string, used to identify the switch used in the gRPC tunnel
251+
establishment and **is a required configuration to start the client**.
252+
- The optional tunnel and gNMI server SSL/TLS profiles can also be configured.
253+
- For more information on configuration options refer to the feature
254+
[TOI](https://www.arista.com/en/support/toi/eos-4-27-0f/14851-gnmi-dial-out-via-grpc-tunnel).
255+
256+
Following command will show the the status of gRPC tunnel clients:
257+
258+
```text
259+
switch# show management api gnmi
260+
Octa: enabled
261+
262+
Transport gRPC-tunnel: tunnel1
263+
Status: tunnel connection established
264+
Enabled: yes
265+
VRF: MGMT
266+
Destination address: 192.185.128.100, port 30000
267+
Local interface: Management1
268+
Local address: 172.100.100.2, port 50000
269+
Target ID: spine1
270+
```
271+
272+
#### gNMIC Tunnel Server
273+
274+
This demo will be using the tunnel server which is available as part of the
275+
[gNMIc](https://gnmic.openconfig.net/user_guide/tunnel_server/) tool.
276+
Following `gnmic.yml` configuration file is used to specify all the command line flags by means of a single file.
277+
278+
```yaml
279+
---
280+
insecure: true
281+
log: true
282+
username: admin
283+
password: admin
284+
285+
subscriptions:
286+
system-info:
287+
mode: once
288+
paths:
289+
- '/system/state/software-version'
290+
- '/system/state/hostname'
291+
port-stats:
292+
paths:
293+
- 'interfaces/interface[name=Management1]/state/counters/in-octets'
294+
- 'interfaces/interface[name=Management1]/state/counters/out-octets'
295+
stream_mode: on-change
296+
mem-stats:
297+
sample-interval: 5s
298+
paths:
299+
- 'eos_native:/Kernel/proc/meminfo'
300+
cpu-stats:
301+
sample-interval: 5s
302+
paths:
303+
- 'eos_native:/Kernel/proc/cpu/utilization/total'
304+
305+
tunnel-server:
306+
address: ":30000"
307+
targets:
308+
- id: spine1
309+
config:
310+
subscriptions:
311+
- system-info
312+
- mem-stats
313+
- port-stats
314+
```
315+
316+
Using the following command, the tunnel server is started on the collector:
317+
318+
```shell
319+
gnmic --config ./gnmic.yml --use-tunnel-server subscribe
320+
```
321+
322+
<details><summary>Reveal output</summary>
323+
<p>
324+
```shell
325+
2025/10/21 17:48:14.648027 [gnmic] tunnel server discovered target {ID:spine1 Type:GNMI_GNOI}
326+
2025/10/21 17:48:14.648373 [gnmic] starting target "spine1" listener
327+
2025/10/21 17:48:14.648405 [gnmic] queuing target "spine1"
328+
2025/10/21 17:48:14.648417 [gnmic] subscribing to target: "spine1"
329+
2025/10/21 17:48:14.648896 [gnmic] target "spine1" gNMI client created
330+
2025/10/21 17:48:14.648964 [gnmic] dialing tunnel connection for tunnel target "spine1"
331+
2025/10/21 17:48:14.648904 [gnmic] sending gNMI SubscribeRequest:
332+
subscribe='subscribe:{subscription:{path:{elem:{name:"system"} elem:{name:"state"} elem:{name:"software-version"}}}
333+
subscription:{path:{elem:{name:"system"} elem:{name:"state"} elem:{name:"hostname"}}} mode:ONCE}', mode='ONCE',
334+
encoding='JSON', to spine1
335+
2025/10/21 17:48:14.649543 [gnmic] sending gNMI SubscribeRequest:
336+
subscribe='subscribe:{subscription:{path:{origin:"eos_native" elem:{name:"Kernel"} elem:{name:"proc"}
337+
elem:{name:"meminfo"}} sample_interval:5000000000}}', mode='STREAM', encoding='JSON', to spine1
338+
{
339+
"source": "spine1",
340+
"subscription-name": "system-info",
341+
"timestamp": 1761025184960219526,
342+
"time": "2025-10-21T11:09:44.960219526+05:30",
343+
"updates": [
344+
{
345+
"Path": "system/state/software-version",
346+
"values": {
347+
"system/state/software-version": "4.35.0F-44178984.4350F"
348+
}
349+
}
350+
]
351+
}
352+
{
353+
"source": "spine1",
354+
"subscription-name": "system-info",
355+
"timestamp": 1761025185169768456,
356+
"time": "2025-10-21T11:09:45.169768456+05:30",
357+
"updates": [
358+
{
359+
"Path": "system/state/hostname",
360+
"values": {
361+
"system/state/hostname": "spine1"
362+
}
363+
}
364+
]
365+
}
366+
{
367+
"sync-response": true
368+
}
369+
{
370+
"source": "spine1",
371+
"subscription-name": "mem-stats",
372+
"timestamp": 1761025184961897312,
373+
"time": "2025-10-21T11:09:44.961897312+05:30",
374+
"prefix": "eos_native:Kernel/proc/meminfo",
375+
"updates": [
376+
{
377+
"Path": "bounce",
378+
"values": {
379+
"bounce": 0
380+
}
381+
}
382+
```
383+
384+
</p>
385+
</details>
386+
387+
Another collector which can be used is `gnmi_collector`, detailed example for the same is available
388+
in the [GitHub](https://github.com/aristanetworks/gnmi/tree/master/cmd/gnmi_collector) repo.
389+
390+
#### Troubleshooting
391+
392+
Use the following command to check the Octa/Openconfig agent logs:
393+
394+
```shell
395+
show agent Octa logs <<-- use this command if Octa is enabled
396+
show agent OpenConfig logs
397+
```

0 commit comments

Comments
 (0)