blob: c85c7e8efc15448f98175186a1a5948e238178ba [file] [log] [blame]
Carmelo Cascone4c289b72019-01-22 15:30:45 -08001/*
2 * Copyright 2019-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.p4runtime.ctl.client;
18
19import com.google.common.util.concurrent.Futures;
20import io.grpc.stub.StreamObserver;
21import org.onosproject.net.pi.model.PiActionProfileId;
22import org.onosproject.net.pi.model.PiCounterId;
23import org.onosproject.net.pi.model.PiMeterId;
24import org.onosproject.net.pi.model.PiPipeconf;
25import org.onosproject.net.pi.model.PiTableId;
26import org.onosproject.net.pi.runtime.PiHandle;
27import org.onosproject.p4runtime.api.P4RuntimeReadClient;
28import org.onosproject.p4runtime.ctl.codec.CodecException;
29import org.onosproject.p4runtime.ctl.utils.P4InfoBrowser;
30import org.onosproject.p4runtime.ctl.utils.PipeconfHelper;
31import org.slf4j.Logger;
32import p4.v1.P4RuntimeOuterClass;
33
34import java.util.concurrent.CompletableFuture;
35
36import static com.google.common.base.Preconditions.checkNotNull;
37import static java.util.concurrent.CompletableFuture.completedFuture;
38import static org.onosproject.p4runtime.ctl.client.P4RuntimeClientImpl.SHORT_TIMEOUT_SECONDS;
39import static org.onosproject.p4runtime.ctl.codec.Codecs.CODECS;
40import static org.slf4j.LoggerFactory.getLogger;
41
42/**
43 * Handles the creation of P4Runtime ReadRequest and execution of the Read RPC
44 * on the server.
45 */
46public final class ReadRequestImpl implements P4RuntimeReadClient.ReadRequest {
47
48 private static final Logger log = getLogger(ReadRequestImpl.class);
49
50 private final P4RuntimeClientImpl client;
51 private final PiPipeconf pipeconf;
52 private final P4RuntimeOuterClass.ReadRequest.Builder requestMsg;
53
54 ReadRequestImpl(P4RuntimeClientImpl client, PiPipeconf pipeconf) {
55 this.client = client;
56 this.pipeconf = pipeconf;
57 this.requestMsg = P4RuntimeOuterClass.ReadRequest.newBuilder()
58 .setDeviceId(client.p4DeviceId());
59 }
60
61 @Override
62 public P4RuntimeReadClient.ReadRequest handles(Iterable<? extends PiHandle> handles) {
63 checkNotNull(handles);
64 handles.forEach(this::handle);
65 return this;
66 }
67
68 @Override
69 public P4RuntimeReadClient.ReadRequest tableEntries(Iterable<PiTableId> tableIds) {
70 checkNotNull(tableIds);
71 tableIds.forEach(this::tableEntries);
72 return this;
73 }
74
75 @Override
76 public P4RuntimeReadClient.ReadRequest defaultTableEntry(Iterable<PiTableId> tableIds) {
77 checkNotNull(tableIds);
78 tableIds.forEach(this::defaultTableEntry);
79 return this;
80 }
81
82 @Override
83 public P4RuntimeReadClient.ReadRequest actionProfileGroups(Iterable<PiActionProfileId> actionProfileIds) {
84 checkNotNull(actionProfileIds);
85 actionProfileIds.forEach(this::actionProfileGroups);
86 return this;
87 }
88
89 @Override
90 public P4RuntimeReadClient.ReadRequest actionProfileMembers(Iterable<PiActionProfileId> actionProfileIds) {
91 checkNotNull(actionProfileIds);
92 actionProfileIds.forEach(this::actionProfileMembers);
93 return this;
94 }
95
96 @Override
97 public P4RuntimeReadClient.ReadRequest counterCells(Iterable<PiCounterId> counterIds) {
98 checkNotNull(counterIds);
99 counterIds.forEach(this::counterCells);
100 return this;
101 }
102
103 @Override
104 public P4RuntimeReadClient.ReadRequest directCounterCells(Iterable<PiTableId> tableIds) {
105 checkNotNull(tableIds);
106 tableIds.forEach(this::directCounterCells);
107 return this;
108 }
109
110 @Override
111 public P4RuntimeReadClient.ReadRequest meterCells(Iterable<PiMeterId> meterIds) {
112 checkNotNull(meterIds);
113 meterIds.forEach(this::meterCells);
114 return this;
115 }
116
117 @Override
118 public P4RuntimeReadClient.ReadRequest directMeterCells(Iterable<PiTableId> tableIds) {
119 checkNotNull(tableIds);
120 tableIds.forEach(this::directMeterCells);
121 return this;
122 }
123
124 @Override
125 public P4RuntimeReadClient.ReadRequest handle(PiHandle handle) {
126 checkNotNull(handle);
127 try {
128 requestMsg.addEntities(CODECS.handle().encode(handle, null, pipeconf));
129 } catch (CodecException e) {
130 log.warn("Unable to read {} from {}: {} [{}]",
131 handle.entityType(), client.deviceId(), e.getMessage(), handle);
132 }
133 return this;
134 }
135
136 @Override
137 public P4RuntimeReadClient.ReadRequest tableEntries(PiTableId tableId) {
138 try {
139 doTableEntry(tableId, false);
140 } catch (InternalRequestException e) {
141 log.warn("Unable to read entries for table '{}' from {}: {}",
142 tableId, client.deviceId(), e.getMessage());
143 }
144 return this;
145 }
146
147 @Override
148 public P4RuntimeReadClient.ReadRequest defaultTableEntry(PiTableId tableId) {
149 try {
150 doTableEntry(tableId, true);
151 } catch (InternalRequestException e) {
152 log.warn("Unable to read default entry for table '{}' from {}: {}",
153 tableId, client.deviceId(), e.getMessage());
154 }
155 return this;
156 }
157
158 @Override
159 public P4RuntimeReadClient.ReadRequest actionProfileGroups(PiActionProfileId actionProfileId) {
160 try {
161 requestMsg.addEntities(
162 P4RuntimeOuterClass.Entity.newBuilder()
163 .setActionProfileGroup(
164 P4RuntimeOuterClass.ActionProfileGroup.newBuilder()
165 .setActionProfileId(
166 p4ActionProfileId(actionProfileId))
167 .build())
168 .build());
169 } catch (InternalRequestException e) {
170 log.warn("Unable to read groups for action profile '{}' from {}: {}",
171 actionProfileId, client.deviceId(), e.getMessage());
172 }
173 return this;
174 }
175
176 @Override
177 public P4RuntimeReadClient.ReadRequest actionProfileMembers(PiActionProfileId actionProfileId) {
178 try {
179 requestMsg.addEntities(
180 P4RuntimeOuterClass.Entity.newBuilder()
181 .setActionProfileMember(
182 P4RuntimeOuterClass.ActionProfileMember.newBuilder()
183 .setActionProfileId(
184 p4ActionProfileId(actionProfileId))
185 .build())
186 .build());
187 } catch (InternalRequestException e) {
188 log.warn("Unable to read members for action profile '{}' from {}: {}",
189 actionProfileId, client.deviceId(), e.getMessage());
190 }
191 return this;
192 }
193
194 @Override
195 public P4RuntimeReadClient.ReadRequest counterCells(PiCounterId counterId) {
196 try {
197 requestMsg.addEntities(
198 P4RuntimeOuterClass.Entity.newBuilder()
199 .setCounterEntry(
200 P4RuntimeOuterClass.CounterEntry.newBuilder()
201 .setCounterId(p4CounterId(counterId))
202 .build())
203 .build());
204 } catch (InternalRequestException e) {
205 log.warn("Unable to read cells for counter '{}' from {}: {}",
206 counterId, client.deviceId(), e.getMessage());
207 }
208 return this;
209 }
210
211 @Override
212 public P4RuntimeReadClient.ReadRequest meterCells(PiMeterId meterId) {
213 try {
214 requestMsg.addEntities(
215 P4RuntimeOuterClass.Entity.newBuilder()
216 .setMeterEntry(
217 P4RuntimeOuterClass.MeterEntry.newBuilder()
218 .setMeterId(p4MeterId(meterId))
219 .build())
220 .build());
221 } catch (InternalRequestException e) {
222 log.warn("Unable to read cells for meter '{}' from {}: {}",
223 meterId, client.deviceId(), e.getMessage());
224 }
225 return this;
226 }
227
228 @Override
229 public P4RuntimeReadClient.ReadRequest directCounterCells(PiTableId tableId) {
230 try {
231 requestMsg.addEntities(
232 P4RuntimeOuterClass.Entity.newBuilder()
233 .setDirectCounterEntry(
234 P4RuntimeOuterClass.DirectCounterEntry.newBuilder()
235 .setTableEntry(
236 P4RuntimeOuterClass.TableEntry
237 .newBuilder()
238 .setTableId(p4TableId(tableId))
239 .build())
240 .build())
241 .build());
242 } catch (InternalRequestException e) {
243 log.warn("Unable to read direct counter cells for table '{}' from {}: {}",
244 tableId, client.deviceId(), e.getMessage());
245 }
246 return this;
247 }
248
249 @Override
250 public P4RuntimeReadClient.ReadRequest directMeterCells(PiTableId tableId) {
251 try {
252 requestMsg.addEntities(
253 P4RuntimeOuterClass.Entity.newBuilder()
254 .setDirectMeterEntry(
255 P4RuntimeOuterClass.DirectMeterEntry.newBuilder()
256 .setTableEntry(
257 P4RuntimeOuterClass.TableEntry
258 .newBuilder()
259 .setTableId(p4TableId(tableId))
260 .build())
261 .build())
262 .build());
263 } catch (InternalRequestException e) {
264 log.warn("Unable to read direct meter cells for table '{}' from {}: {}",
265 tableId, client.deviceId(), e.getMessage());
266 }
267 return this;
268 }
269
270 private void doTableEntry(PiTableId piTableId, boolean defaultEntries)
271 throws InternalRequestException {
272 checkNotNull(piTableId);
273 final P4RuntimeOuterClass.Entity entityMsg = P4RuntimeOuterClass.Entity
274 .newBuilder()
275 .setTableEntry(
276 P4RuntimeOuterClass.TableEntry.newBuilder()
277 .setTableId(p4TableId(piTableId))
278 .setIsDefaultAction(defaultEntries)
279 .setCounterData(P4RuntimeOuterClass.CounterData
280 .getDefaultInstance())
281 .build())
282 .build();
283 requestMsg.addEntities(entityMsg);
284 }
285
286 @Override
287 public CompletableFuture<P4RuntimeReadClient.ReadResponse> submit() {
288 final P4RuntimeOuterClass.ReadRequest readRequest = requestMsg.build();
289 log.debug("Sending read request to {} for {} entities...",
290 client.deviceId(), readRequest.getEntitiesCount());
291 if (readRequest.getEntitiesCount() == 0) {
292 // No need to ask the server.
293 return completedFuture(ReadResponseImpl.EMPTY);
294 }
295 final CompletableFuture<P4RuntimeReadClient.ReadResponse> future =
296 new CompletableFuture<>();
297 // Instantiate response builder and let stream observer populate it.
298 final ReadResponseImpl.Builder responseBuilder =
299 ReadResponseImpl.builder(client.deviceId(), pipeconf);
300 final StreamObserver<P4RuntimeOuterClass.ReadResponse> observer =
301 new StreamObserver<P4RuntimeOuterClass.ReadResponse>() {
302 @Override
303 public void onNext(P4RuntimeOuterClass.ReadResponse value) {
304 log.debug("Received read response from {} with {} entities...",
305 client.deviceId(), value.getEntitiesCount());
306 value.getEntitiesList().forEach(responseBuilder::addEntity);
307 }
308 @Override
309 public void onError(Throwable t) {
310 client.handleRpcError(t, "READ");
311 // TODO: implement parsing of trailer errors
312 future.complete(responseBuilder.fail(t));
313 }
314 @Override
315 public void onCompleted() {
316 future.complete(responseBuilder.build());
317 }
318 };
319 client.execRpc(s -> s.read(readRequest, observer), SHORT_TIMEOUT_SECONDS);
320 return future;
321 }
322
323 @Override
324 public P4RuntimeReadClient.ReadResponse submitSync() {
325 return Futures.getUnchecked(submit());
326 }
327
328 private int p4TableId(PiTableId piTableId) throws InternalRequestException {
329 try {
330 return getBrowser().tables().getByName(piTableId.id())
331 .getPreamble().getId();
332 } catch (P4InfoBrowser.NotFoundException e) {
333 throw new InternalRequestException(e.getMessage());
334 }
335 }
336
337 private int p4ActionProfileId(PiActionProfileId piActionProfileId)
338 throws InternalRequestException {
339 try {
340 return getBrowser().actionProfiles().getByName(piActionProfileId.id())
341 .getPreamble().getId();
342 } catch (P4InfoBrowser.NotFoundException e) {
343 throw new InternalRequestException(e.getMessage());
344 }
345 }
346
347 private int p4CounterId(PiCounterId counterId)
348 throws InternalRequestException {
349 try {
350 return getBrowser().counters().getByName(counterId.id())
351 .getPreamble().getId();
352 } catch (P4InfoBrowser.NotFoundException e) {
353 throw new InternalRequestException(e.getMessage());
354 }
355 }
356
357 private int p4MeterId(PiMeterId meterId)
358 throws InternalRequestException {
359 try {
360 return getBrowser().meters().getByName(meterId.id())
361 .getPreamble().getId();
362 } catch (P4InfoBrowser.NotFoundException e) {
363 throw new InternalRequestException(e.getMessage());
364 }
365 }
366
367 private P4InfoBrowser getBrowser() throws InternalRequestException {
368 final P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
369 if (browser == null) {
370 throw new InternalRequestException(
371 "Unable to get a P4Info browser for pipeconf " + pipeconf.id());
372 }
373 return browser;
374 }
375
376 /**
377 * Internal exception to signal that something went wrong when populating
378 * the request.
379 */
380 private final class InternalRequestException extends Exception {
381
382 private InternalRequestException(String message) {
383 super(message);
384 }
385 }
386}