1.. _grpc-dev:
2
3***************
4Northbound gRPC
5***************
6
7.. _grpc-languages-bindings:
8
9Programming Language Bindings
10=============================
11
12The gRPC supported programming language bindings can be found here:
13https://grpc.io/docs/languages/
14
15After picking a programming language that supports gRPC bindings, the
16next step is to generate the FRR northbound bindings. To generate the
17northbound bindings you'll need the programming language binding
18generator tools and those are language specific.
19
20Next sections will use Ruby as an example for writing scripts to use
21the northbound.
22
23
24.. _grpc-ruby-generate:
25
26Generating Ruby FRR Bindings
27----------------------------
28
29Generating FRR northbound bindings for Ruby example:
30
31::
32
33   # Install the required gems:
34   # - grpc: the gem that will talk with FRR's gRPC plugin.
35   # - grpc-tools: the gem that provides the code generator.
36   gem install grpc
37   gem install grpc-tools
38
39   # Create your project/scripts directory:
40   mkdir /tmp/frr-ruby
41
42   # Go to FRR's grpc directory:
43   cd grpc
44
45   # Generate the ruby bindings:
46   grpc_tools_ruby_protoc \
47     --ruby_out=/tmp/frr-ruby \
48     --grpc_out=/tmp/frr-ruby \
49     frr-northbound.proto
50
51
52.. _grpc-ruby-if-sample:
53
54Using Ruby To Get Interfaces State
55----------------------------------
56
57Here is a sample script to print all interfaces FRR discovered:
58
59::
60
61   require 'frr-northbound_services_pb'
62
63   # Create the connection with FRR's gRPC:
64   stub = Frr::Northbound::Stub.new('localhost:50051', :this_channel_is_insecure)
65
66   # Create a new state request to get interface state:
67   request = Frr::GetRequest.new
68   request.type = :STATE
69   request.path.push('/frr-interface:lib')
70
71   # Ask FRR.
72   response = stub.get(request)
73
74   # Print the response.
75   response.each do |result|
76     result.data.data.each_line do |line|
77       puts line
78     end
79   end
80
81
82.. note::
83
84   The generated files will assume that they are in the search path (e.g.
85   inside gem) so you'll need to either edit it to use ``require_relative`` or
86   tell Ruby where to look for them. For simplicity we'll use ``-I .`` to tell
87   it is in the current directory.
88
89
90The previous script will output something like this:
91
92::
93
94   $ cd /tmp/frr-ruby
95   # Add `-I.` so ruby finds the FRR generated file locally.
96   $ ruby -I. interface.rb
97   {
98     "frr-interface:lib": {
99       "interface": [
100         {
101           "name": "eth0",
102           "vrf": "default",
103           "state": {
104             "if-index": 2,
105             "mtu": 1500,
106             "mtu6": 1500,
107             "speed": 1000,
108             "metric": 0,
109             "phy-address": "11:22:33:44:55:66"
110           },
111           "frr-zebra:zebra": {
112             "state": {
113               "up-count": 0,
114               "down-count": 0
115             }
116           }
117         },
118         {
119           "name": "lo",
120           "vrf": "default",
121           "state": {
122             "if-index": 1,
123             "mtu": 0,
124             "mtu6": 65536,
125             "speed": 0,
126             "metric": 0,
127             "phy-address": "00:00:00:00:00:00"
128           },
129           "frr-zebra:zebra": {
130             "state": {
131               "up-count": 0,
132               "down-count": 0
133             }
134           }
135         }
136       ]
137     }
138   }
139
140
141.. _grpc-ruby-bfd-profile-sample:
142
143Using Ruby To Create BFD Profiles
144---------------------------------
145
146In this example you'll learn how to edit configuration using JSON
147and programmatic (XPath) format.
148
149::
150
151   require 'frr-northbound_services_pb'
152
153   # Create the connection with FRR's gRPC:
154   stub = Frr::Northbound::Stub.new('localhost:50051', :this_channel_is_insecure)
155
156   # Create a new candidate configuration change.
157   new_candidate = stub.create_candidate(Frr::CreateCandidateRequest.new)
158
159   # Use JSON to configure.
160   request = Frr::LoadToCandidateRequest.new
161   request.candidate_id = new_candidate.candidate_id
162   request.type = :MERGE
163   request.config = Frr::DataTree.new
164   request.config.encoding = :JSON
165   request.config.data = <<-EOJ
166   {
167     "frr-bfdd:bfdd": {
168       "bfd": {
169         "profile": [
170           {
171             "name": "test-prof",
172             "detection-multiplier": 4,
173             "required-receive-interval": 800000
174           }
175         ]
176       }
177     }
178   }
179   EOJ
180
181   # Load configuration to candidate.
182   stub.load_to_candidate(request)
183
184   # Commit candidate.
185   stub.commit(
186     Frr::CommitRequest.new(
187       candidate_id: new_candidate.candidate_id,
188       phase: :ALL,
189       comment: 'create test-prof'
190     )
191   )
192
193   #
194   # Now lets delete the previous profile and create a new one.
195   #
196
197   # Create a new candidate configuration change.
198   new_candidate = stub.create_candidate(Frr::CreateCandidateRequest.new)
199
200   # Edit the configuration candidate.
201   request = Frr::EditCandidateRequest.new
202   request.candidate_id = new_candidate.candidate_id
203
204   # Delete previously created profile.
205   request.delete.push(
206     Frr::PathValue.new(
207       path: "/frr-bfdd:bfdd/bfd/profile[name='test-prof']",
208     )
209   )
210
211   # Add new profile with two configurations.
212   request.update.push(
213     Frr::PathValue.new(
214       path: "/frr-bfdd:bfdd/bfd/profile[name='test-prof-2']/detection-multiplier",
215       value: 5.to_s
216     )
217   )
218   request.update.push(
219     Frr::PathValue.new(
220       path: "/frr-bfdd:bfdd/bfd/profile[name='test-prof-2']/desired-transmission-interval",
221       value: 900_000.to_s
222     )
223   )
224
225   # Modify the candidate.
226   stub.edit_candidate(request)
227
228   # Commit the candidate configuration.
229   stub.commit(
230     Frr::CommitRequest.new(
231       candidate_id: new_candidate.candidate_id,
232       phase: :ALL,
233       comment: 'replace test-prof with test-prof-2'
234     )
235   )
236
237
238And here is the new FRR configuration:
239
240::
241
242   $ sudo vtysh -c 'show running-config'
243   ...
244   bfd
245    profile test-prof-2
246     detect-multiplier 5
247     transmit-interval 900
248    !
249   !
250