7 To enable gRPC support one needs to add `--enable-grpc` when running
8 `configure`. Additionally, when launching each daemon one needs to request
9 the gRPC module be loaded and which port to bind to. This can be done by adding
10 `-M grpc:<port>` to the daemon's CLI arguments.
12 Currently there is no gRPC "routing" so you will need to bind your gRPC
13 `channel` to the particular daemon's gRPC port to interact with that daemon's
14 gRPC northbound interface.
16 The minimum version of gRPC known to work is 1.16.1.
18 .. _grpc-languages-bindings:
20 Programming Language Bindings
21 =============================
23 The gRPC supported programming language bindings can be found here:
24 https://grpc.io/docs/languages/
26 After picking a programming language that supports gRPC bindings, the
27 next step is to generate the FRR northbound bindings. To generate the
28 northbound bindings you'll need the programming language binding
29 generator tools and those are language specific.
34 The next sections will use C++ as an example for accessing FRR
35 northbound through gRPC.
37 .. _grpc-c++-generate:
39 Generating C++ FRR Bindings
40 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
42 Generating FRR northbound bindings for C++ example:
46 # Install gRPC (e.g., on Ubuntu 20.04)
47 sudo apt-get install libgrpc++-dev libgrpc-dev
52 protoc --cpp_out=/tmp/frr-cpp \
53 --grpc_out=/tmp/frr-cpp \
55 --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` \
59 .. _grpc-c++-if-sample:
61 Using C++ To Get Version and Interfaces State
62 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
64 Below is a sample program to print all interfaces discovered.
71 #include <grpc/grpc.h>
72 #include <grpcpp/create_channel.h>
73 #include "frr-northbound.pb.h"
74 #include "frr-northbound.grpc.pb.h"
77 frr::GetRequest request;
78 frr::GetResponse reply;
79 grpc::ClientContext context;
82 auto channel = grpc::CreateChannel("localhost:50051",
83 grpc::InsecureChannelCredentials());
84 auto stub = frr::Northbound::NewStub(channel);
86 request.set_type(frr::GetRequest::ALL);
87 request.set_encoding(frr::JSON);
88 request.set_with_defaults(true);
89 request.add_path("/frr-interface:lib");
90 auto stream = stub->Get(&context, request);
92 std::ostringstream ss;
93 while (stream->Read(&reply))
94 ss << reply.data().data() << std::endl;
96 status = stream->Finish();
98 std::cout << "Interface Info:\n" << ss.str() << std::endl;
101 Below is how to compile and run the program, with the example output:
105 $ g++ -o test test.cpp frr-northbound.grpc.pb.cc frr-northbound.pb.cc -lgrpc++ -lprotobuf
109 "frr-interface:lib": {
120 "phy-address": "00:00:00:00:00:00"
126 "ptm-status": "disabled"
139 "phy-address": "02:37:ac:63:59:b9"
145 "ptm-status": "disabled"
152 "mcast-rpf-lookup": "mrib-then-urib",
153 "workqueue-hold-timer": 10,
154 "zapi-packets": 1000,
155 "import-kernel-table": {
158 "dplane-queue-limit": 200
164 .. _grpc-python-example:
169 The next sections will use Python as an example for writing scripts to use
172 .. _grpc-python-generate:
174 Generating Python FRR Bindings
175 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
177 Generating FRR northbound bindings for Python example:
181 # Install python3 virtual environment capability e.g.,
182 sudo apt-get install python3-venv
184 # Create a virtual environment for python grpc and activate
185 python3 -m venv venv-grpc
186 source venv-grpc/bin/activate
188 # Install grpc requirements
189 pip install grpcio grpcio-tools
191 mkdir /tmp/frr-python
194 python3 -m grpc_tools.protoc \
195 --python_out=/tmp/frr-python \
196 --grpc_python_out=/tmp/frr-python \
200 .. _grpc-python-if-sample:
202 Using Python To Get Capabilities and Interfaces State
203 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
205 Below is a sample script to print capabilities and all interfaces Python
206 discovered. This demostrates the 2 different RPC results one gets from gRPC,
207 Unary (`GetCapabilities`) and Streaming (`Get`) for the interface state.
212 import frr_northbound_pb2
213 import frr_northbound_pb2_grpc
215 channel = grpc.insecure_channel('localhost:50051')
216 stub = frr_northbound_pb2_grpc.NorthboundStub(channel)
219 request = frr_northbound_pb2.GetCapabilitiesRequest()
220 response = stub.GetCapabilities(request)
223 # Print Interface State and Config
224 request = frr_northbound_pb2.GetRequest()
225 request.path.append("/frr-interface:lib")
226 request.type=frr_northbound_pb2.GetRequest.ALL
227 request.encoding=frr_northbound_pb2.XML
229 for r in stub.Get(request):
232 The previous script will output something like:
236 frr_version: "7.7-dev-my-manual-build"
237 rollback_support: true
240 organization: "FRRouting"
241 revision: "2019-07-04"
244 name: "frr-interface"
245 organization: "FRRouting"
246 revision: "2020-02-05"
249 supported_encodings: JSON
250 supported_encodings: XML
252 <lib xmlns="http://frrouting.org/yang/interface">
257 <if-index>1</if-index>
262 <phy-address>00:00:00:00:00:00</phy-address>
264 <zebra xmlns="http://frrouting.org/yang/zebra">
266 <up-count>0</up-count>
267 <down-count>0</down-count>
275 <if-index>2</if-index>
280 <phy-address>f2:62:2e:f3:4c:e4</phy-address>
282 <zebra xmlns="http://frrouting.org/yang/zebra">
284 <up-count>0</up-count>
285 <down-count>0</down-count>
291 .. _grpc-ruby-example:
296 Next sections will use Ruby as an example for writing scripts to use
299 .. _grpc-ruby-generate:
301 Generating Ruby FRR Bindings
302 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
304 Generating FRR northbound bindings for Ruby example:
308 # Install the required gems:
309 # - grpc: the gem that will talk with FRR's gRPC plugin.
310 # - grpc-tools: the gem that provides the code generator.
312 gem install grpc-tools
314 # Create your project/scripts directory:
317 # Go to FRR's grpc directory:
320 # Generate the ruby bindings:
321 grpc_tools_ruby_protoc \
322 --ruby_out=/tmp/frr-ruby \
323 --grpc_out=/tmp/frr-ruby \
327 .. _grpc-ruby-if-sample:
329 Using Ruby To Get Interfaces State
330 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
332 Here is a sample script to print all interfaces FRR discovered:
336 require 'frr-northbound_services_pb'
338 # Create the connection with FRR's gRPC:
339 stub = Frr::Northbound::Stub.new('localhost:50051', :this_channel_is_insecure)
341 # Create a new state request to get interface state:
342 request = Frr::GetRequest.new
343 request.type = :STATE
344 request.path.push('/frr-interface:lib')
347 response = stub.get(request)
349 # Print the response.
350 response.each do |result|
351 result.data.data.each_line do |line|
359 The generated files will assume that they are in the search path (e.g.
360 inside gem) so you'll need to either edit it to use ``require_relative`` or
361 tell Ruby where to look for them. For simplicity we'll use ``-I .`` to tell
362 it is in the current directory.
365 The previous script will output something like this:
370 # Add `-I.` so ruby finds the FRR generated file locally.
371 $ ruby -I. interface.rb
373 "frr-interface:lib": {
384 "phy-address": "11:22:33:44:55:66"
402 "phy-address": "00:00:00:00:00:00"
416 .. _grpc-ruby-bfd-profile-sample:
418 Using Ruby To Create BFD Profiles
419 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
421 In this example you'll learn how to edit configuration using JSON
422 and programmatic (XPath) format.
426 require 'frr-northbound_services_pb'
428 # Create the connection with FRR's gRPC:
429 stub = Frr::Northbound::Stub.new('localhost:50051', :this_channel_is_insecure)
431 # Create a new candidate configuration change.
432 new_candidate = stub.create_candidate(Frr::CreateCandidateRequest.new)
434 # Use JSON to configure.
435 request = Frr::LoadToCandidateRequest.new
436 request.candidate_id = new_candidate.candidate_id
437 request.type = :MERGE
438 request.config = Frr::DataTree.new
439 request.config.encoding = :JSON
440 request.config.data = <<-EOJ
447 "detection-multiplier": 4,
448 "required-receive-interval": 800000
456 # Load configuration to candidate.
457 stub.load_to_candidate(request)
461 Frr::CommitRequest.new(
462 candidate_id: new_candidate.candidate_id,
464 comment: 'create test-prof'
469 # Now lets delete the previous profile and create a new one.
472 # Create a new candidate configuration change.
473 new_candidate = stub.create_candidate(Frr::CreateCandidateRequest.new)
475 # Edit the configuration candidate.
476 request = Frr::EditCandidateRequest.new
477 request.candidate_id = new_candidate.candidate_id
479 # Delete previously created profile.
482 path: "/frr-bfdd:bfdd/bfd/profile[name='test-prof']",
486 # Add new profile with two configurations.
489 path: "/frr-bfdd:bfdd/bfd/profile[name='test-prof-2']/detection-multiplier",
495 path: "/frr-bfdd:bfdd/bfd/profile[name='test-prof-2']/desired-transmission-interval",
500 # Modify the candidate.
501 stub.edit_candidate(request)
503 # Commit the candidate configuration.
505 Frr::CommitRequest.new(
506 candidate_id: new_candidate.candidate_id,
508 comment: 'replace test-prof with test-prof-2'
513 And here is the new FRR configuration:
517 $ sudo vtysh -c 'show running-config'
522 transmit-interval 900