A C++ server based on gNMI specification to communicate with sysrepo datastore.
Supported RPCs:
- Capabilities
- Set
- Get
- Subscribe
Supported encoding:
- No encoding/gNMI native encoding (use
PROTO
) - JSON IETF encoding (use
JSON_IETF
) - JSON encoding (if you ask for
JSON
you will haveJSON_IETF
) -
Protobuf encoding -
Binary encoding -
ASCII encoding
Supported authentication/encryption methods:
- no encryption, no username/password (DEBUGGING ONLY)
-
no encryption, username/password -
TLS/SSL encryption only: server key pair only - TLS/SSL encryption + Username/password authentication: server key pair only
- TLS/SSL encryption & authentication: server and client key pairs (RECOMMENDED)
sysrepo-gnxi
+-- protobuf (>=3.0) #because of gnmi
+-- jsoncpp #because of get JSON
+-- grpc (cpp) (>=1.18.0) #because of TLS bug to verify client cert
+-- libyang-cpp (>=1.0-r3) #because of feature_enable
+-- sysrepo-cpp (>=0.7.7)
| +-- libyang
| +-- ...
You can either install dependencies from sources or from the packages.
Install dependencies from source:
- If
libyang (>=1.0-r3)
is packaged on your distrib use it, else runscripts/install-libyang.sh
to install the required version of libyang. you can use an older version and apply commit bf1aa13ba2dfb7b5938ed2345a67de316fc34917 to it - You can run
scripts/install-sysrepo.sh
to install sysrepo. Check here for installation instructions of sysrepo.
By default, grpc and protobuf are linked statically. But you can build it to have them linked dynamically.
Install deb and rpm from https://github.com/YohanPipereau/sysrepo-gnxi/releases
mkdir -p build
cd build
cmake -D DYNAMIC_LINK_GRPC=OFF .. # GRPC can be linked dynamically if other applications are using it
make
make install
Packages are built with Cpack module for cmake:
mkdir -p build
cd build
cmake -D CPACK_GENERATOR="DEB" ..
make package
mkdir -p build
cd build
cmake -D CPACK_GENERATOR="RPM" ..
make package
On CA machine:
#Generate a self-signed certificate for CA if you don’t have one
openssl req -x509 -days 365 -nodes -newkey rsa:2048 -keyout ca.key -out ca.crt
On gNXI server:
#Generate a private key & certificate request for server
#CN (Common Name) or FQDN is mandatory and must be server domain name
openssl req -new -days 365 -nodes -newkey rsa:2048 -keyout server.key -out server.certreq.csr
cat server.certreq.csr | grep "CERTIFICATE REQUEST" #check it is a cert request
On CA machine:
#CA sign server certificate request:
openssl x509 -req -days 360 -in server.certreq.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -sha256
On client machine:
#Generate client key, certificate request, make CA sign it
#FQDN/CN is used for MUTUAL TLS authentication. So CN will be the identiy used for access control
openssl req -new -days 365 -nodes -newkey rsa:2048 -keyout client.key -out client.certreq.csr
On CA machine:
#CA sign client certificate request:
openssl x509 -req -days 360 -in client.certreq.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -sha256
Verify the informations:
#Check information
openssl x509 -noout -subject -issuer -in server.crt
openssl x509 -noout -subject -issuer -in client.crt
# Verify chain certs
openssl verify -CAfile ca.crt -show_chain client.crt
openssl verify -CAfile ca.crt -show_chain server.crt
- Server/client in INSECURE mode (no username/password) and no TLS connection
gnxi_server -f
gnmi -addr localhost:50051 get /ietf-interfaces:interfaces-state
- Server/client with TLS connection for encryption and authentication:
gnxi_server -k server.key -c server.crt -l4
gnmi -addr localhost:50051 -certfile=client.crt -keyfile=client.key get /ietf-interfaces:interfaces-state
- Server/client with username/password + TLS connection for encryption only:
gnxi_server -k server.key -c server.crt --username cisco --password cisco -l4
gnmi -addr localhost:50051 -cafile ca.crt -username cisco -password cisco get /ietf-interfaces:interfaces-state
Here is a list of gNMI clients, not all of them work because they don't all respect the specification.
- Arista gnmi
- Openconfig gnmi_cli
- Google gnmi_capabilities, gnmi_get, gnmi_set
- InfluxData Telegraf
- Cisco pipeline-gnmi
- Openconfig gnmi_collector
- Nokia pygnmi
Documentation and examples for:
- gnmi is provided here
- Telegraf-gnmi is provided here
- pipeline-gnmi is provided here
gNMI clients which should work:
A JSON library would not be enough because JSON is not detailed enough and miss information required to build an XPATH (key of sysrepo datastore).
Typically, in a JSON encoded format containing a list, you don't know which field would be the YANG key of the list element.
Ex: /ietf-interfaces:interfaces/interface contains multiple leaves. "name" is the key but JSON does not give this information.
Your gnmi client for a get
or subscribe
rpc must have yang models downloaded if it wants to recognize which is the key from a JSON list.
Ex: Which field is the key for interface list ?
{
"interface" : [
{
"admin-status" : "down",
"name" : "GigabitEthernet0/8/0",
"oper-status" : "down",
"phys-address" : "08:00:27:60:b7:12",
"speed" : "1000000",
"type" : "iana-if-type:ethernetCsmacd"
},
{
"admin-status" : "down",
"name" : "local0",
"oper-status" : "down",
"phys-address" : "00:00:00:00:00:00",
"speed" : "0",
"type" : "iana-if-type:ethernetCsmacd"
}
]
}
The problem is that all encodings do not agree on the type which must be used to store a value.
For example:
/ietf-interfaces:interfaces/interface[name="eth0"]/statistics/octets
can be stored as a uint64_t
with no encoding or as a string
with JSON IETF encoding.
Protobuf, binary and ASCII encodings requires gNMI client and server to have a convention regarding the data exchanged. On the contrary, JSON IETF [RFC7951] and JSON are self describing, so both clients and server nows how data is encoded (Key:Value).
No encoding means your value can be encoded in one of the following type i.e. string, int64, uint64, bool, bytes, float, Decimal64. This types are all supported types for a YANG leaf node.
If you are using "No Encoding", or "Native Encoding", you must know that it is not part of gNMI specification. If you use this, you would receive a list of xpath and their value. (Though it is not supported for now).
It should be used if:
- Your gNMI client support raw types;
- You are making a Get or Subscribe Request;
- You are making a Set request with a XPATH qualifying a YANG leaf;
- You want to exchange lighter messages (typically for telemetry).
This server compiles with grpc 1.12.0 but as reported here grpc/grpc#17500 , if we want to use TLS for authentication and no root certificate is specified on server side, there will be no checking of client certificate . Thus, anyone could access the server without authenticating.
Because grpc++ is not packaged on Centos and Ubuntu/Debian, and it takes a long time to compile it.