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