blob: c95e2f3088554ce9253b45c2ed16d0cffa423808 [file] [log] [blame]
Carmelo Cascone8d99b172017-07-18 17:26:31 -04001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Carmelo Cascone8d99b172017-07-18 17:26:31 -04003 *
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;
18
19import com.google.common.collect.ImmutableList;
Yi Tseng82512da2017-08-16 19:46:36 -070020import com.google.common.collect.Lists;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040021import com.google.protobuf.ByteString;
22import org.onlab.util.ImmutableByteSequence;
Carmelo Cascone87892e22017-11-13 16:01:29 -080023import org.onosproject.net.pi.model.PiActionId;
24import org.onosproject.net.pi.model.PiActionParamId;
25import org.onosproject.net.pi.model.PiMatchFieldId;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040026import org.onosproject.net.pi.model.PiPipeconf;
Carmelo Cascone87892e22017-11-13 16:01:29 -080027import org.onosproject.net.pi.model.PiTableId;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040028import org.onosproject.net.pi.runtime.PiAction;
Yi Tseng82512da2017-08-16 19:46:36 -070029import org.onosproject.net.pi.runtime.PiActionGroupId;
30import org.onosproject.net.pi.runtime.PiActionGroupMemberId;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040031import org.onosproject.net.pi.runtime.PiActionParam;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040032import org.onosproject.net.pi.runtime.PiExactFieldMatch;
33import org.onosproject.net.pi.runtime.PiFieldMatch;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040034import org.onosproject.net.pi.runtime.PiLpmFieldMatch;
Carmelo Cascone0e896a02017-07-31 07:22:27 +020035import org.onosproject.net.pi.runtime.PiMatchKey;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040036import org.onosproject.net.pi.runtime.PiRangeFieldMatch;
37import org.onosproject.net.pi.runtime.PiTableAction;
38import org.onosproject.net.pi.runtime.PiTableEntry;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040039import org.onosproject.net.pi.runtime.PiTernaryFieldMatch;
40import org.onosproject.net.pi.runtime.PiValidFieldMatch;
41import org.slf4j.Logger;
Carmelo Cascone87b9b392017-10-02 18:33:20 +020042import p4.P4RuntimeOuterClass.Action;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040043import p4.P4RuntimeOuterClass.FieldMatch;
44import p4.P4RuntimeOuterClass.TableAction;
45import p4.P4RuntimeOuterClass.TableEntry;
46import p4.config.P4InfoOuterClass;
47
48import java.util.Collection;
49import java.util.Collections;
Yi Tseng82512da2017-08-16 19:46:36 -070050import java.util.List;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040051
52import static java.lang.String.format;
53import static org.onlab.util.ImmutableByteSequence.copyFrom;
Yi Tseng82512da2017-08-16 19:46:36 -070054import static org.onosproject.p4runtime.ctl.P4RuntimeUtils.assertPrefixLen;
55import static org.onosproject.p4runtime.ctl.P4RuntimeUtils.assertSize;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040056import static org.slf4j.LoggerFactory.getLogger;
57
58/**
Yi Tseng82512da2017-08-16 19:46:36 -070059 * Encoder/Decoder of table entries, from ONOS Pi* format, to P4Runtime protobuf messages, and vice versa.
Carmelo Cascone8d99b172017-07-18 17:26:31 -040060 */
61final class TableEntryEncoder {
Carmelo Cascone8d99b172017-07-18 17:26:31 -040062 private static final Logger log = getLogger(TableEntryEncoder.class);
63
Carmelo Cascone8d99b172017-07-18 17:26:31 -040064 private static final String VALUE_OF_PREFIX = "value of ";
65 private static final String MASK_OF_PREFIX = "mask of ";
66 private static final String HIGH_RANGE_VALUE_OF_PREFIX = "high range value of ";
67 private static final String LOW_RANGE_VALUE_OF_PREFIX = "low range value of ";
68
69 // TODO: implement cache of encoded entities.
70
71 private TableEntryEncoder() {
72 // hide.
73 }
74
75 /**
Carmelo Cascone7f75be42017-09-07 14:37:02 +020076 * Returns a collection of P4Runtime table entry protobuf messages, encoded from the given collection of PI table
77 * entries for the given pipeconf. If a PI table entry cannot be encoded, it is skipped, hence the returned
Carmelo Cascone8d99b172017-07-18 17:26:31 -040078 * collection might have different size than the input one.
79 * <p>
80 * Please check the log for an explanation of any error that might have occurred.
81 *
82 * @param piTableEntries PI table entries
83 * @param pipeconf PI pipeconf
84 * @return collection of P4Runtime table entry protobuf messages
85 */
86 static Collection<TableEntry> encode(Collection<PiTableEntry> piTableEntries, PiPipeconf pipeconf) {
87
88 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
89
90 if (browser == null) {
91 log.error("Unable to get a P4Info browser for pipeconf {}, skipping encoding of all table entries");
92 return Collections.emptyList();
93 }
94
95 ImmutableList.Builder<TableEntry> tableEntryMsgListBuilder = ImmutableList.builder();
96
97 for (PiTableEntry piTableEntry : piTableEntries) {
98 try {
99 tableEntryMsgListBuilder.add(encodePiTableEntry(piTableEntry, browser));
100 } catch (P4InfoBrowser.NotFoundException | EncodeException e) {
101 log.error("Unable to encode PI table entry: {}", e.getMessage());
102 }
103 }
104
105 return tableEntryMsgListBuilder.build();
106 }
107
108 /**
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200109 * Same as {@link #encode(Collection, PiPipeconf)} but encodes only one entry.
110 *
111 * @param piTableEntry table entry
112 * @param pipeconf pipeconf
113 * @return encoded table entry message
114 * @throws EncodeException if entry cannot be encoded
115 * @throws P4InfoBrowser.NotFoundException if the required information cannot be find in the pipeconf's P4info
116 */
117 static TableEntry encode(PiTableEntry piTableEntry, PiPipeconf pipeconf)
118 throws EncodeException, P4InfoBrowser.NotFoundException {
119
120 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
121 if (browser == null) {
122 throw new EncodeException(format("Unable to get a P4Info browser for pipeconf %s", pipeconf.id()));
123 }
124
125 return encodePiTableEntry(piTableEntry, browser);
126 }
127
128 /**
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400129 * Returns a collection of PI table entry objects, decoded from the given collection of P4Runtime table entry
130 * messages for the given pipeconf. If a table entry message cannot be decoded, it is skipped, hence the returned
131 * collection might have different size than the input one.
132 * <p>
133 * Please check the log for an explanation of any error that might have occurred.
134 *
135 * @param tableEntryMsgs P4Runtime table entry messages
136 * @param pipeconf PI pipeconf
137 * @return collection of PI table entry objects
138 */
139 static Collection<PiTableEntry> decode(Collection<TableEntry> tableEntryMsgs, PiPipeconf pipeconf) {
140
141 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
142
143 if (browser == null) {
144 log.error("Unable to get a P4Info browser for pipeconf {}, skipping decoding of all table entries");
145 return Collections.emptyList();
146 }
147
148 ImmutableList.Builder<PiTableEntry> piTableEntryListBuilder = ImmutableList.builder();
149
150 for (TableEntry tableEntryMsg : tableEntryMsgs) {
151 try {
152 piTableEntryListBuilder.add(decodeTableEntryMsg(tableEntryMsg, browser));
153 } catch (P4InfoBrowser.NotFoundException | EncodeException e) {
154 log.error("Unable to decode table entry message: {}", e.getMessage());
155 }
156 }
157
158 return piTableEntryListBuilder.build();
159 }
160
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200161 /**
162 * Same as {@link #decode(Collection, PiPipeconf)} but decodes only one entry.
163 *
164 * @param tableEntryMsg table entry message
165 * @param pipeconf pipeconf
166 * @return decoded PI table entry
167 * @throws EncodeException if message cannot be decoded
168 * @throws P4InfoBrowser.NotFoundException if the required information cannot be find in the pipeconf's P4info
169 */
170 static PiTableEntry decode(TableEntry tableEntryMsg, PiPipeconf pipeconf)
171 throws EncodeException, P4InfoBrowser.NotFoundException {
172
173 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
174 if (browser == null) {
175 throw new EncodeException(format("Unable to get a P4Info browser for pipeconf %s", pipeconf.id()));
176 }
177 return decodeTableEntryMsg(tableEntryMsg, browser);
178 }
179
180 /**
181 * Returns a table entry protobuf message, encoded from the given table id and match key, for the given pipeconf.
182 * The returned table entry message can be only used to reference an existing entry, i.e. a read operation, and not
183 * a write one wince it misses other fields (action, priority, etc.).
184 *
185 * @param tableId table identifier
186 * @param matchKey match key
187 * @param pipeconf pipeconf
188 * @return table entry message
189 * @throws EncodeException if message cannot be encoded
190 * @throws P4InfoBrowser.NotFoundException if the required information cannot be find in the pipeconf's P4info
191 */
192 static TableEntry encode(PiTableId tableId, PiMatchKey matchKey, PiPipeconf pipeconf)
193 throws EncodeException, P4InfoBrowser.NotFoundException {
194
195 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
196 TableEntry.Builder tableEntryMsgBuilder = TableEntry.newBuilder();
197
Carmelo Casconecb0a49c2017-10-03 14:32:23 +0200198 P4InfoOuterClass.Table tableInfo = browser.tables().getByName(tableId.id());
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200199
200 // Table id.
201 tableEntryMsgBuilder.setTableId(tableInfo.getPreamble().getId());
202
203 // Field matches.
Carmelo Casconef6c2f052018-03-23 18:02:15 -0700204 if (matchKey.equals(PiMatchKey.EMPTY)) {
205 tableEntryMsgBuilder.setIsDefaultAction(true);
206 } else {
207 for (PiFieldMatch piFieldMatch : matchKey.fieldMatches()) {
208 tableEntryMsgBuilder.addMatch(encodePiFieldMatch(piFieldMatch, tableInfo, browser));
209 }
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200210 }
211
212 return tableEntryMsgBuilder.build();
213 }
214
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400215 private static TableEntry encodePiTableEntry(PiTableEntry piTableEntry, P4InfoBrowser browser)
216 throws P4InfoBrowser.NotFoundException, EncodeException {
217
218 TableEntry.Builder tableEntryMsgBuilder = TableEntry.newBuilder();
219
Carmelo Casconecb0a49c2017-10-03 14:32:23 +0200220 P4InfoOuterClass.Table tableInfo = browser.tables().getByName(piTableEntry.table().id());
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400221
222 // Table id.
223 tableEntryMsgBuilder.setTableId(tableInfo.getPreamble().getId());
224
225 // Priority.
Yi Tseng088f4ce2017-08-15 10:54:14 -0700226 // FIXME: check on P4Runtime if/what is the default priority.
Yi Tseng02c4c572018-01-22 17:52:10 -0800227 piTableEntry.priority().ifPresent(tableEntryMsgBuilder::setPriority);
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400228
229 // Controller metadata (cookie)
230 tableEntryMsgBuilder.setControllerMetadata(piTableEntry.cookie());
231
232 // Timeout.
233 if (piTableEntry.timeout().isPresent()) {
234 log.warn("Found PI table entry with timeout set, not supported in P4Runtime: {}", piTableEntry);
235 }
236
237 // Table action.
238 tableEntryMsgBuilder.setAction(encodePiTableAction(piTableEntry.action(), browser));
239
240 // Field matches.
Carmelo Casconef6c2f052018-03-23 18:02:15 -0700241 if (piTableEntry.matchKey().equals(PiMatchKey.EMPTY)) {
242 tableEntryMsgBuilder.setIsDefaultAction(true);
243 } else {
244 for (PiFieldMatch piFieldMatch : piTableEntry.matchKey().fieldMatches()) {
245 tableEntryMsgBuilder.addMatch(encodePiFieldMatch(piFieldMatch, tableInfo, browser));
246 }
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400247 }
248
249 return tableEntryMsgBuilder.build();
250 }
251
252 private static PiTableEntry decodeTableEntryMsg(TableEntry tableEntryMsg, P4InfoBrowser browser)
253 throws P4InfoBrowser.NotFoundException, EncodeException {
254
255 PiTableEntry.Builder piTableEntryBuilder = PiTableEntry.builder();
256
257 P4InfoOuterClass.Table tableInfo = browser.tables().getById(tableEntryMsg.getTableId());
258
259 // Table id.
260 piTableEntryBuilder.forTable(PiTableId.of(tableInfo.getPreamble().getName()));
261
262 // Priority.
263 piTableEntryBuilder.withPriority(tableEntryMsg.getPriority());
264
265 // Controller metadata (cookie)
266 piTableEntryBuilder.withCookie(tableEntryMsg.getControllerMetadata());
267
268 // Table action.
269 piTableEntryBuilder.withAction(decodeTableActionMsg(tableEntryMsg.getAction(), browser));
270
271 // Timeout.
272 // FIXME: how to decode table entry messages with timeout, given that the timeout value is lost after encoding?
273
Carmelo Cascone0e896a02017-07-31 07:22:27 +0200274 // Match key for field matches.
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200275 piTableEntryBuilder.withMatchKey(decodeFieldMatchMsgs(tableEntryMsg.getMatchList(), tableInfo, browser));
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400276
277 return piTableEntryBuilder.build();
278 }
279
280 private static FieldMatch encodePiFieldMatch(PiFieldMatch piFieldMatch, P4InfoOuterClass.Table tableInfo,
281 P4InfoBrowser browser)
282 throws P4InfoBrowser.NotFoundException, EncodeException {
283
284 FieldMatch.Builder fieldMatchMsgBuilder = FieldMatch.newBuilder();
285
286 // FIXME: check how field names for stacked headers are constructed in P4Runtime.
287 String fieldName = piFieldMatch.fieldId().id();
288 int tableId = tableInfo.getPreamble().getId();
Carmelo Casconecb0a49c2017-10-03 14:32:23 +0200289 P4InfoOuterClass.MatchField matchFieldInfo = browser.matchFields(tableId).getByName(fieldName);
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400290 String entityName = format("field match '%s' of table '%s'",
291 matchFieldInfo.getName(), tableInfo.getPreamble().getName());
292 int fieldId = matchFieldInfo.getId();
293 int fieldBitwidth = matchFieldInfo.getBitwidth();
294
295 fieldMatchMsgBuilder.setFieldId(fieldId);
296
297 switch (piFieldMatch.type()) {
298 case EXACT:
299 PiExactFieldMatch fieldMatch = (PiExactFieldMatch) piFieldMatch;
300 ByteString exactValue = ByteString.copyFrom(fieldMatch.value().asReadOnlyBuffer());
301 assertSize(VALUE_OF_PREFIX + entityName, exactValue, fieldBitwidth);
302 return fieldMatchMsgBuilder.setExact(
303 FieldMatch.Exact
304 .newBuilder()
305 .setValue(exactValue)
306 .build())
307 .build();
308 case TERNARY:
309 PiTernaryFieldMatch ternaryMatch = (PiTernaryFieldMatch) piFieldMatch;
310 ByteString ternaryValue = ByteString.copyFrom(ternaryMatch.value().asReadOnlyBuffer());
311 ByteString ternaryMask = ByteString.copyFrom(ternaryMatch.mask().asReadOnlyBuffer());
312 assertSize(VALUE_OF_PREFIX + entityName, ternaryValue, fieldBitwidth);
313 assertSize(MASK_OF_PREFIX + entityName, ternaryMask, fieldBitwidth);
314 return fieldMatchMsgBuilder.setTernary(
315 FieldMatch.Ternary
316 .newBuilder()
317 .setValue(ternaryValue)
318 .setMask(ternaryMask)
319 .build())
320 .build();
321 case LPM:
322 PiLpmFieldMatch lpmMatch = (PiLpmFieldMatch) piFieldMatch;
323 ByteString lpmValue = ByteString.copyFrom(lpmMatch.value().asReadOnlyBuffer());
324 int lpmPrefixLen = lpmMatch.prefixLength();
325 assertSize(VALUE_OF_PREFIX + entityName, lpmValue, fieldBitwidth);
326 assertPrefixLen(entityName, lpmPrefixLen, fieldBitwidth);
327 return fieldMatchMsgBuilder.setLpm(
328 FieldMatch.LPM.newBuilder()
329 .setValue(lpmValue)
330 .setPrefixLen(lpmPrefixLen)
331 .build())
332 .build();
333 case RANGE:
334 PiRangeFieldMatch rangeMatch = (PiRangeFieldMatch) piFieldMatch;
335 ByteString rangeHighValue = ByteString.copyFrom(rangeMatch.highValue().asReadOnlyBuffer());
336 ByteString rangeLowValue = ByteString.copyFrom(rangeMatch.lowValue().asReadOnlyBuffer());
337 assertSize(HIGH_RANGE_VALUE_OF_PREFIX + entityName, rangeHighValue, fieldBitwidth);
338 assertSize(LOW_RANGE_VALUE_OF_PREFIX + entityName, rangeLowValue, fieldBitwidth);
339 return fieldMatchMsgBuilder.setRange(
340 FieldMatch.Range.newBuilder()
341 .setHigh(rangeHighValue)
342 .setLow(rangeLowValue)
343 .build())
344 .build();
345 case VALID:
346 PiValidFieldMatch validMatch = (PiValidFieldMatch) piFieldMatch;
347 return fieldMatchMsgBuilder.setValid(
348 FieldMatch.Valid.newBuilder()
349 .setValue(validMatch.isValid())
350 .build())
351 .build();
352 default:
353 throw new EncodeException(format(
354 "Building of match type %s not implemented", piFieldMatch.type()));
355 }
356 }
357
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200358 /**
359 * Returns a PI match key, decoded from the given table entry protobuf message, for the given pipeconf.
360 *
361 * @param tableEntryMsg table entry message
362 * @param pipeconf pipeconf
363 * @return PI match key
364 * @throws EncodeException if message cannot be decoded
365 * @throws P4InfoBrowser.NotFoundException if the required information cannot be find in the pipeconf's P4info
366 */
367 static PiMatchKey decodeMatchKey(TableEntry tableEntryMsg, PiPipeconf pipeconf)
368 throws P4InfoBrowser.NotFoundException, EncodeException {
369 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
370 P4InfoOuterClass.Table tableInfo = browser.tables().getById(tableEntryMsg.getTableId());
Carmelo Casconef6c2f052018-03-23 18:02:15 -0700371 if (tableEntryMsg.getMatchCount() == 0) {
372 return PiMatchKey.EMPTY;
373 } else {
374 return decodeFieldMatchMsgs(tableEntryMsg.getMatchList(), tableInfo, browser);
375 }
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200376 }
377
378 private static PiMatchKey decodeFieldMatchMsgs(Collection<FieldMatch> fieldMatchs, P4InfoOuterClass.Table tableInfo,
379 P4InfoBrowser browser)
380 throws P4InfoBrowser.NotFoundException, EncodeException {
381 // Match key for field matches.
382 PiMatchKey.Builder piMatchKeyBuilder = PiMatchKey.builder();
383 for (FieldMatch fieldMatchMsg : fieldMatchs) {
384 piMatchKeyBuilder.addFieldMatch(decodeFieldMatchMsg(fieldMatchMsg, tableInfo, browser));
385 }
386 return piMatchKeyBuilder.build();
387 }
388
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400389 private static PiFieldMatch decodeFieldMatchMsg(FieldMatch fieldMatchMsg, P4InfoOuterClass.Table tableInfo,
390 P4InfoBrowser browser)
391 throws P4InfoBrowser.NotFoundException, EncodeException {
392
393 int tableId = tableInfo.getPreamble().getId();
394 String fieldMatchName = browser.matchFields(tableId).getById(fieldMatchMsg.getFieldId()).getName();
Carmelo Cascone87892e22017-11-13 16:01:29 -0800395 PiMatchFieldId headerFieldId = PiMatchFieldId.of(fieldMatchName);
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400396
397 FieldMatch.FieldMatchTypeCase typeCase = fieldMatchMsg.getFieldMatchTypeCase();
398
399 switch (typeCase) {
400 case EXACT:
401 FieldMatch.Exact exactFieldMatch = fieldMatchMsg.getExact();
402 ImmutableByteSequence exactValue = copyFrom(exactFieldMatch.getValue().asReadOnlyByteBuffer());
403 return new PiExactFieldMatch(headerFieldId, exactValue);
404 case TERNARY:
405 FieldMatch.Ternary ternaryFieldMatch = fieldMatchMsg.getTernary();
406 ImmutableByteSequence ternaryValue = copyFrom(ternaryFieldMatch.getValue().asReadOnlyByteBuffer());
407 ImmutableByteSequence ternaryMask = copyFrom(ternaryFieldMatch.getMask().asReadOnlyByteBuffer());
408 return new PiTernaryFieldMatch(headerFieldId, ternaryValue, ternaryMask);
409 case LPM:
410 FieldMatch.LPM lpmFieldMatch = fieldMatchMsg.getLpm();
411 ImmutableByteSequence lpmValue = copyFrom(lpmFieldMatch.getValue().asReadOnlyByteBuffer());
412 int lpmPrefixLen = lpmFieldMatch.getPrefixLen();
413 return new PiLpmFieldMatch(headerFieldId, lpmValue, lpmPrefixLen);
414 case RANGE:
415 FieldMatch.Range rangeFieldMatch = fieldMatchMsg.getRange();
416 ImmutableByteSequence rangeHighValue = copyFrom(rangeFieldMatch.getHigh().asReadOnlyByteBuffer());
417 ImmutableByteSequence rangeLowValue = copyFrom(rangeFieldMatch.getLow().asReadOnlyByteBuffer());
418 return new PiRangeFieldMatch(headerFieldId, rangeLowValue, rangeHighValue);
419 case VALID:
420 FieldMatch.Valid validFieldMatch = fieldMatchMsg.getValid();
421 return new PiValidFieldMatch(headerFieldId, validFieldMatch.getValue());
422 default:
423 throw new EncodeException(format(
424 "Decoding of field match type '%s' not implemented", typeCase.name()));
425 }
426 }
427
Yi Tseng82512da2017-08-16 19:46:36 -0700428 static TableAction encodePiTableAction(PiTableAction piTableAction, P4InfoBrowser browser)
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400429 throws P4InfoBrowser.NotFoundException, EncodeException {
430
431 TableAction.Builder tableActionMsgBuilder = TableAction.newBuilder();
432
433 switch (piTableAction.type()) {
434 case ACTION:
435 PiAction piAction = (PiAction) piTableAction;
Yi Tseng82512da2017-08-16 19:46:36 -0700436 Action theAction = encodePiAction(piAction, browser);
437 tableActionMsgBuilder.setAction(theAction);
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400438 break;
Yi Tseng82512da2017-08-16 19:46:36 -0700439 case ACTION_GROUP_ID:
440 PiActionGroupId actionGroupId = (PiActionGroupId) piTableAction;
441 tableActionMsgBuilder.setActionProfileGroupId(actionGroupId.id());
442 break;
443 case GROUP_MEMBER_ID:
444 PiActionGroupMemberId actionGroupMemberId = (PiActionGroupMemberId) piTableAction;
445 tableActionMsgBuilder.setActionProfileMemberId(actionGroupMemberId.id());
446 break;
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400447 default:
448 throw new EncodeException(
449 format("Building of table action type %s not implemented", piTableAction.type()));
450 }
451
452 return tableActionMsgBuilder.build();
453 }
454
Yi Tseng82512da2017-08-16 19:46:36 -0700455 static PiTableAction decodeTableActionMsg(TableAction tableActionMsg, P4InfoBrowser browser)
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400456 throws P4InfoBrowser.NotFoundException, EncodeException {
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400457 TableAction.TypeCase typeCase = tableActionMsg.getTypeCase();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400458 switch (typeCase) {
459 case ACTION:
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400460 Action actionMsg = tableActionMsg.getAction();
Yi Tseng82512da2017-08-16 19:46:36 -0700461 return decodeActionMsg(actionMsg, browser);
Yi Tseng95390822018-01-22 17:57:22 -0800462 case ACTION_PROFILE_GROUP_ID:
463 return PiActionGroupId.of(tableActionMsg.getActionProfileGroupId());
464 case ACTION_PROFILE_MEMBER_ID:
465 return PiActionGroupMemberId.of(tableActionMsg.getActionProfileMemberId());
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400466 default:
467 throw new EncodeException(
468 format("Decoding of table action type %s not implemented", typeCase.name()));
469 }
470 }
471
Yi Tseng82512da2017-08-16 19:46:36 -0700472 static Action encodePiAction(PiAction piAction, P4InfoBrowser browser)
473 throws P4InfoBrowser.NotFoundException, EncodeException {
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400474
Carmelo Cascone87892e22017-11-13 16:01:29 -0800475 int actionId = browser.actions().getByName(piAction.id().toString()).getPreamble().getId();
Yi Tseng82512da2017-08-16 19:46:36 -0700476
477 Action.Builder actionMsgBuilder =
478 Action.newBuilder().setActionId(actionId);
479
480 for (PiActionParam p : piAction.parameters()) {
Carmelo Cascone87892e22017-11-13 16:01:29 -0800481 P4InfoOuterClass.Action.Param paramInfo = browser.actionParams(actionId).getByName(p.id().toString());
Yi Tseng82512da2017-08-16 19:46:36 -0700482 ByteString paramValue = ByteString.copyFrom(p.value().asReadOnlyBuffer());
483 assertSize(format("param '%s' of action '%s'", p.id(), piAction.id()),
484 paramValue, paramInfo.getBitwidth());
485 actionMsgBuilder.addParams(Action.Param.newBuilder()
486 .setParamId(paramInfo.getId())
487 .setValue(paramValue)
488 .build());
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400489 }
Yi Tseng82512da2017-08-16 19:46:36 -0700490
491 return actionMsgBuilder.build();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400492 }
493
Yi Tseng82512da2017-08-16 19:46:36 -0700494 static PiAction decodeActionMsg(Action action, P4InfoBrowser browser)
495 throws P4InfoBrowser.NotFoundException {
496 P4InfoBrowser.EntityBrowser<P4InfoOuterClass.Action.Param> paramInfo =
497 browser.actionParams(action.getActionId());
498 String actionName = browser.actions()
499 .getById(action.getActionId())
500 .getPreamble().getName();
501 PiActionId id = PiActionId.of(actionName);
502 List<PiActionParam> params = Lists.newArrayList();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400503
Yi Tseng82512da2017-08-16 19:46:36 -0700504 for (Action.Param p : action.getParamsList()) {
505 String paramName = paramInfo.getById(p.getParamId()).getName();
506 ImmutableByteSequence value = ImmutableByteSequence.copyFrom(p.getValue().toByteArray());
507 params.add(new PiActionParam(PiActionParamId.of(paramName), value));
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400508 }
Yi Tseng82512da2017-08-16 19:46:36 -0700509 return PiAction.builder().withId(id).withParameters(params).build();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400510 }
511}