blob: 505b4cbdb9b9ac0a2057fa315db27bb5935a2600 [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;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040040import org.slf4j.Logger;
Carmelo Cascone6af4e172018-06-15 16:01:30 +020041import p4.v1.P4RuntimeOuterClass.Action;
42import p4.v1.P4RuntimeOuterClass.FieldMatch;
43import p4.v1.P4RuntimeOuterClass.TableAction;
44import p4.v1.P4RuntimeOuterClass.TableEntry;
45import p4.config.v1.P4InfoOuterClass;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040046
47import java.util.Collection;
48import java.util.Collections;
Yi Tseng82512da2017-08-16 19:46:36 -070049import java.util.List;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040050
Yi Tsengd28936e2018-02-23 22:11:11 +010051import static com.google.common.base.Preconditions.checkNotNull;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040052import 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 Cascone5bc7e102018-02-18 18:27:55 -080076 * Returns a collection of P4Runtime table entry protobuf messages, encoded
77 * from the given collection of PI table entries for the given pipeconf. If
78 * a PI table entry cannot be encoded, an EncodeException is thrown.
Carmelo Cascone8d99b172017-07-18 17:26:31 -040079 *
80 * @param piTableEntries PI table entries
81 * @param pipeconf PI pipeconf
82 * @return collection of P4Runtime table entry protobuf messages
Carmelo Cascone5bc7e102018-02-18 18:27:55 -080083 * @throws EncodeException if a PI table entry cannot be encoded
Carmelo Cascone8d99b172017-07-18 17:26:31 -040084 */
Carmelo Cascone5bc7e102018-02-18 18:27:55 -080085 static Collection<TableEntry> encode(Collection<PiTableEntry> piTableEntries,
86 PiPipeconf pipeconf)
87 throws EncodeException {
Carmelo Cascone8d99b172017-07-18 17:26:31 -040088
89 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
90
91 if (browser == null) {
Carmelo Cascone5bc7e102018-02-18 18:27:55 -080092 throw new EncodeException(format(
93 "Unable to get a P4Info browser for pipeconf %s", pipeconf.id()));
Carmelo Cascone8d99b172017-07-18 17:26:31 -040094 }
95
96 ImmutableList.Builder<TableEntry> tableEntryMsgListBuilder = ImmutableList.builder();
97
98 for (PiTableEntry piTableEntry : piTableEntries) {
99 try {
100 tableEntryMsgListBuilder.add(encodePiTableEntry(piTableEntry, browser));
Carmelo Cascone5bc7e102018-02-18 18:27:55 -0800101 } catch (P4InfoBrowser.NotFoundException e) {
102 throw new EncodeException(e.getMessage());
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400103 }
104 }
105
106 return tableEntryMsgListBuilder.build();
107 }
108
109 /**
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200110 * Same as {@link #encode(Collection, PiPipeconf)} but encodes only one entry.
111 *
112 * @param piTableEntry table entry
113 * @param pipeconf pipeconf
114 * @return encoded table entry message
115 * @throws EncodeException if entry cannot be encoded
116 * @throws P4InfoBrowser.NotFoundException if the required information cannot be find in the pipeconf's P4info
117 */
118 static TableEntry encode(PiTableEntry piTableEntry, PiPipeconf pipeconf)
119 throws EncodeException, P4InfoBrowser.NotFoundException {
120
121 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
122 if (browser == null) {
123 throw new EncodeException(format("Unable to get a P4Info browser for pipeconf %s", pipeconf.id()));
124 }
125
126 return encodePiTableEntry(piTableEntry, browser);
127 }
128
129 /**
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400130 * Returns a collection of PI table entry objects, decoded from the given collection of P4Runtime table entry
131 * messages for the given pipeconf. If a table entry message cannot be decoded, it is skipped, hence the returned
132 * collection might have different size than the input one.
133 * <p>
134 * Please check the log for an explanation of any error that might have occurred.
135 *
136 * @param tableEntryMsgs P4Runtime table entry messages
137 * @param pipeconf PI pipeconf
138 * @return collection of PI table entry objects
139 */
140 static Collection<PiTableEntry> decode(Collection<TableEntry> tableEntryMsgs, PiPipeconf pipeconf) {
141
142 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
143
144 if (browser == null) {
145 log.error("Unable to get a P4Info browser for pipeconf {}, skipping decoding of all table entries");
146 return Collections.emptyList();
147 }
148
149 ImmutableList.Builder<PiTableEntry> piTableEntryListBuilder = ImmutableList.builder();
150
151 for (TableEntry tableEntryMsg : tableEntryMsgs) {
152 try {
153 piTableEntryListBuilder.add(decodeTableEntryMsg(tableEntryMsg, browser));
154 } catch (P4InfoBrowser.NotFoundException | EncodeException e) {
155 log.error("Unable to decode table entry message: {}", e.getMessage());
156 }
157 }
158
159 return piTableEntryListBuilder.build();
160 }
161
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200162 /**
163 * Same as {@link #decode(Collection, PiPipeconf)} but decodes only one entry.
164 *
165 * @param tableEntryMsg table entry message
166 * @param pipeconf pipeconf
167 * @return decoded PI table entry
168 * @throws EncodeException if message cannot be decoded
169 * @throws P4InfoBrowser.NotFoundException if the required information cannot be find in the pipeconf's P4info
170 */
171 static PiTableEntry decode(TableEntry tableEntryMsg, PiPipeconf pipeconf)
172 throws EncodeException, P4InfoBrowser.NotFoundException {
173
174 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
175 if (browser == null) {
176 throw new EncodeException(format("Unable to get a P4Info browser for pipeconf %s", pipeconf.id()));
177 }
178 return decodeTableEntryMsg(tableEntryMsg, browser);
179 }
180
181 /**
182 * Returns a table entry protobuf message, encoded from the given table id and match key, for the given pipeconf.
183 * The returned table entry message can be only used to reference an existing entry, i.e. a read operation, and not
184 * a write one wince it misses other fields (action, priority, etc.).
185 *
186 * @param tableId table identifier
187 * @param matchKey match key
188 * @param pipeconf pipeconf
189 * @return table entry message
190 * @throws EncodeException if message cannot be encoded
191 * @throws P4InfoBrowser.NotFoundException if the required information cannot be find in the pipeconf's P4info
192 */
193 static TableEntry encode(PiTableId tableId, PiMatchKey matchKey, PiPipeconf pipeconf)
194 throws EncodeException, P4InfoBrowser.NotFoundException {
195
196 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
197 TableEntry.Builder tableEntryMsgBuilder = TableEntry.newBuilder();
198
Carmelo Casconecb0a49c2017-10-03 14:32:23 +0200199 P4InfoOuterClass.Table tableInfo = browser.tables().getByName(tableId.id());
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200200
201 // Table id.
202 tableEntryMsgBuilder.setTableId(tableInfo.getPreamble().getId());
203
204 // Field matches.
Carmelo Cascone4256bde2018-03-23 18:02:15 -0700205 if (matchKey.equals(PiMatchKey.EMPTY)) {
206 tableEntryMsgBuilder.setIsDefaultAction(true);
207 } else {
208 for (PiFieldMatch piFieldMatch : matchKey.fieldMatches()) {
209 tableEntryMsgBuilder.addMatch(encodePiFieldMatch(piFieldMatch, tableInfo, browser));
210 }
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200211 }
212
213 return tableEntryMsgBuilder.build();
214 }
215
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400216 private static TableEntry encodePiTableEntry(PiTableEntry piTableEntry, P4InfoBrowser browser)
217 throws P4InfoBrowser.NotFoundException, EncodeException {
218
219 TableEntry.Builder tableEntryMsgBuilder = TableEntry.newBuilder();
220
Carmelo Casconecb0a49c2017-10-03 14:32:23 +0200221 P4InfoOuterClass.Table tableInfo = browser.tables().getByName(piTableEntry.table().id());
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400222
223 // Table id.
224 tableEntryMsgBuilder.setTableId(tableInfo.getPreamble().getId());
225
226 // Priority.
Yi Tseng088f4ce2017-08-15 10:54:14 -0700227 // FIXME: check on P4Runtime if/what is the default priority.
Yi Tseng02c4c572018-01-22 17:52:10 -0800228 piTableEntry.priority().ifPresent(tableEntryMsgBuilder::setPriority);
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400229
230 // Controller metadata (cookie)
231 tableEntryMsgBuilder.setControllerMetadata(piTableEntry.cookie());
232
233 // Timeout.
234 if (piTableEntry.timeout().isPresent()) {
235 log.warn("Found PI table entry with timeout set, not supported in P4Runtime: {}", piTableEntry);
236 }
237
238 // Table action.
Yi Tsengd28936e2018-02-23 22:11:11 +0100239 if (piTableEntry.action() != null) {
240 tableEntryMsgBuilder.setAction(encodePiTableAction(piTableEntry.action(), browser));
241 }
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400242
243 // Field matches.
Carmelo Cascone4256bde2018-03-23 18:02:15 -0700244 if (piTableEntry.matchKey().equals(PiMatchKey.EMPTY)) {
245 tableEntryMsgBuilder.setIsDefaultAction(true);
246 } else {
247 for (PiFieldMatch piFieldMatch : piTableEntry.matchKey().fieldMatches()) {
248 tableEntryMsgBuilder.addMatch(encodePiFieldMatch(piFieldMatch, tableInfo, browser));
249 }
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400250 }
251
252 return tableEntryMsgBuilder.build();
253 }
254
255 private static PiTableEntry decodeTableEntryMsg(TableEntry tableEntryMsg, P4InfoBrowser browser)
256 throws P4InfoBrowser.NotFoundException, EncodeException {
257
258 PiTableEntry.Builder piTableEntryBuilder = PiTableEntry.builder();
259
260 P4InfoOuterClass.Table tableInfo = browser.tables().getById(tableEntryMsg.getTableId());
261
262 // Table id.
263 piTableEntryBuilder.forTable(PiTableId.of(tableInfo.getPreamble().getName()));
264
265 // Priority.
266 piTableEntryBuilder.withPriority(tableEntryMsg.getPriority());
267
268 // Controller metadata (cookie)
269 piTableEntryBuilder.withCookie(tableEntryMsg.getControllerMetadata());
270
271 // Table action.
Yi Tsengd28936e2018-02-23 22:11:11 +0100272 if (tableEntryMsg.hasAction()) {
273 piTableEntryBuilder.withAction(decodeTableActionMsg(tableEntryMsg.getAction(), browser));
274 }
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400275
276 // Timeout.
277 // FIXME: how to decode table entry messages with timeout, given that the timeout value is lost after encoding?
278
Carmelo Cascone0e896a02017-07-31 07:22:27 +0200279 // Match key for field matches.
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200280 piTableEntryBuilder.withMatchKey(decodeFieldMatchMsgs(tableEntryMsg.getMatchList(), tableInfo, browser));
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400281
282 return piTableEntryBuilder.build();
283 }
284
285 private static FieldMatch encodePiFieldMatch(PiFieldMatch piFieldMatch, P4InfoOuterClass.Table tableInfo,
286 P4InfoBrowser browser)
287 throws P4InfoBrowser.NotFoundException, EncodeException {
288
289 FieldMatch.Builder fieldMatchMsgBuilder = FieldMatch.newBuilder();
290
291 // FIXME: check how field names for stacked headers are constructed in P4Runtime.
292 String fieldName = piFieldMatch.fieldId().id();
293 int tableId = tableInfo.getPreamble().getId();
Carmelo Casconecb0a49c2017-10-03 14:32:23 +0200294 P4InfoOuterClass.MatchField matchFieldInfo = browser.matchFields(tableId).getByName(fieldName);
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400295 String entityName = format("field match '%s' of table '%s'",
296 matchFieldInfo.getName(), tableInfo.getPreamble().getName());
297 int fieldId = matchFieldInfo.getId();
298 int fieldBitwidth = matchFieldInfo.getBitwidth();
299
300 fieldMatchMsgBuilder.setFieldId(fieldId);
301
302 switch (piFieldMatch.type()) {
303 case EXACT:
304 PiExactFieldMatch fieldMatch = (PiExactFieldMatch) piFieldMatch;
305 ByteString exactValue = ByteString.copyFrom(fieldMatch.value().asReadOnlyBuffer());
306 assertSize(VALUE_OF_PREFIX + entityName, exactValue, fieldBitwidth);
307 return fieldMatchMsgBuilder.setExact(
308 FieldMatch.Exact
309 .newBuilder()
310 .setValue(exactValue)
311 .build())
312 .build();
313 case TERNARY:
314 PiTernaryFieldMatch ternaryMatch = (PiTernaryFieldMatch) piFieldMatch;
315 ByteString ternaryValue = ByteString.copyFrom(ternaryMatch.value().asReadOnlyBuffer());
316 ByteString ternaryMask = ByteString.copyFrom(ternaryMatch.mask().asReadOnlyBuffer());
317 assertSize(VALUE_OF_PREFIX + entityName, ternaryValue, fieldBitwidth);
318 assertSize(MASK_OF_PREFIX + entityName, ternaryMask, fieldBitwidth);
319 return fieldMatchMsgBuilder.setTernary(
320 FieldMatch.Ternary
321 .newBuilder()
322 .setValue(ternaryValue)
323 .setMask(ternaryMask)
324 .build())
325 .build();
326 case LPM:
327 PiLpmFieldMatch lpmMatch = (PiLpmFieldMatch) piFieldMatch;
328 ByteString lpmValue = ByteString.copyFrom(lpmMatch.value().asReadOnlyBuffer());
329 int lpmPrefixLen = lpmMatch.prefixLength();
330 assertSize(VALUE_OF_PREFIX + entityName, lpmValue, fieldBitwidth);
331 assertPrefixLen(entityName, lpmPrefixLen, fieldBitwidth);
332 return fieldMatchMsgBuilder.setLpm(
333 FieldMatch.LPM.newBuilder()
334 .setValue(lpmValue)
335 .setPrefixLen(lpmPrefixLen)
336 .build())
337 .build();
338 case RANGE:
339 PiRangeFieldMatch rangeMatch = (PiRangeFieldMatch) piFieldMatch;
340 ByteString rangeHighValue = ByteString.copyFrom(rangeMatch.highValue().asReadOnlyBuffer());
341 ByteString rangeLowValue = ByteString.copyFrom(rangeMatch.lowValue().asReadOnlyBuffer());
342 assertSize(HIGH_RANGE_VALUE_OF_PREFIX + entityName, rangeHighValue, fieldBitwidth);
343 assertSize(LOW_RANGE_VALUE_OF_PREFIX + entityName, rangeLowValue, fieldBitwidth);
344 return fieldMatchMsgBuilder.setRange(
345 FieldMatch.Range.newBuilder()
346 .setHigh(rangeHighValue)
347 .setLow(rangeLowValue)
348 .build())
349 .build();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400350 default:
351 throw new EncodeException(format(
352 "Building of match type %s not implemented", piFieldMatch.type()));
353 }
354 }
355
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200356 /**
357 * Returns a PI match key, decoded from the given table entry protobuf message, for the given pipeconf.
358 *
359 * @param tableEntryMsg table entry message
360 * @param pipeconf pipeconf
361 * @return PI match key
362 * @throws EncodeException if message cannot be decoded
363 * @throws P4InfoBrowser.NotFoundException if the required information cannot be find in the pipeconf's P4info
364 */
365 static PiMatchKey decodeMatchKey(TableEntry tableEntryMsg, PiPipeconf pipeconf)
366 throws P4InfoBrowser.NotFoundException, EncodeException {
367 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
368 P4InfoOuterClass.Table tableInfo = browser.tables().getById(tableEntryMsg.getTableId());
Carmelo Cascone4256bde2018-03-23 18:02:15 -0700369 if (tableEntryMsg.getMatchCount() == 0) {
370 return PiMatchKey.EMPTY;
371 } else {
372 return decodeFieldMatchMsgs(tableEntryMsg.getMatchList(), tableInfo, browser);
373 }
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200374 }
375
376 private static PiMatchKey decodeFieldMatchMsgs(Collection<FieldMatch> fieldMatchs, P4InfoOuterClass.Table tableInfo,
377 P4InfoBrowser browser)
378 throws P4InfoBrowser.NotFoundException, EncodeException {
379 // Match key for field matches.
380 PiMatchKey.Builder piMatchKeyBuilder = PiMatchKey.builder();
381 for (FieldMatch fieldMatchMsg : fieldMatchs) {
382 piMatchKeyBuilder.addFieldMatch(decodeFieldMatchMsg(fieldMatchMsg, tableInfo, browser));
383 }
384 return piMatchKeyBuilder.build();
385 }
386
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400387 private static PiFieldMatch decodeFieldMatchMsg(FieldMatch fieldMatchMsg, P4InfoOuterClass.Table tableInfo,
388 P4InfoBrowser browser)
389 throws P4InfoBrowser.NotFoundException, EncodeException {
390
391 int tableId = tableInfo.getPreamble().getId();
392 String fieldMatchName = browser.matchFields(tableId).getById(fieldMatchMsg.getFieldId()).getName();
Carmelo Cascone87892e22017-11-13 16:01:29 -0800393 PiMatchFieldId headerFieldId = PiMatchFieldId.of(fieldMatchName);
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400394
395 FieldMatch.FieldMatchTypeCase typeCase = fieldMatchMsg.getFieldMatchTypeCase();
396
397 switch (typeCase) {
398 case EXACT:
399 FieldMatch.Exact exactFieldMatch = fieldMatchMsg.getExact();
400 ImmutableByteSequence exactValue = copyFrom(exactFieldMatch.getValue().asReadOnlyByteBuffer());
401 return new PiExactFieldMatch(headerFieldId, exactValue);
402 case TERNARY:
403 FieldMatch.Ternary ternaryFieldMatch = fieldMatchMsg.getTernary();
404 ImmutableByteSequence ternaryValue = copyFrom(ternaryFieldMatch.getValue().asReadOnlyByteBuffer());
405 ImmutableByteSequence ternaryMask = copyFrom(ternaryFieldMatch.getMask().asReadOnlyByteBuffer());
406 return new PiTernaryFieldMatch(headerFieldId, ternaryValue, ternaryMask);
407 case LPM:
408 FieldMatch.LPM lpmFieldMatch = fieldMatchMsg.getLpm();
409 ImmutableByteSequence lpmValue = copyFrom(lpmFieldMatch.getValue().asReadOnlyByteBuffer());
410 int lpmPrefixLen = lpmFieldMatch.getPrefixLen();
411 return new PiLpmFieldMatch(headerFieldId, lpmValue, lpmPrefixLen);
412 case RANGE:
413 FieldMatch.Range rangeFieldMatch = fieldMatchMsg.getRange();
414 ImmutableByteSequence rangeHighValue = copyFrom(rangeFieldMatch.getHigh().asReadOnlyByteBuffer());
415 ImmutableByteSequence rangeLowValue = copyFrom(rangeFieldMatch.getLow().asReadOnlyByteBuffer());
416 return new PiRangeFieldMatch(headerFieldId, rangeLowValue, rangeHighValue);
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400417 default:
418 throw new EncodeException(format(
419 "Decoding of field match type '%s' not implemented", typeCase.name()));
420 }
421 }
422
Yi Tseng82512da2017-08-16 19:46:36 -0700423 static TableAction encodePiTableAction(PiTableAction piTableAction, P4InfoBrowser browser)
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400424 throws P4InfoBrowser.NotFoundException, EncodeException {
Yi Tsengd28936e2018-02-23 22:11:11 +0100425 checkNotNull(piTableAction, "Cannot encode null PiTableAction");
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400426 TableAction.Builder tableActionMsgBuilder = TableAction.newBuilder();
427
428 switch (piTableAction.type()) {
429 case ACTION:
430 PiAction piAction = (PiAction) piTableAction;
Yi Tseng82512da2017-08-16 19:46:36 -0700431 Action theAction = encodePiAction(piAction, browser);
432 tableActionMsgBuilder.setAction(theAction);
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400433 break;
Yi Tseng82512da2017-08-16 19:46:36 -0700434 case ACTION_GROUP_ID:
435 PiActionGroupId actionGroupId = (PiActionGroupId) piTableAction;
436 tableActionMsgBuilder.setActionProfileGroupId(actionGroupId.id());
437 break;
438 case GROUP_MEMBER_ID:
439 PiActionGroupMemberId actionGroupMemberId = (PiActionGroupMemberId) piTableAction;
440 tableActionMsgBuilder.setActionProfileMemberId(actionGroupMemberId.id());
441 break;
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400442 default:
443 throw new EncodeException(
444 format("Building of table action type %s not implemented", piTableAction.type()));
445 }
446
447 return tableActionMsgBuilder.build();
448 }
449
Yi Tseng82512da2017-08-16 19:46:36 -0700450 static PiTableAction decodeTableActionMsg(TableAction tableActionMsg, P4InfoBrowser browser)
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400451 throws P4InfoBrowser.NotFoundException, EncodeException {
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400452 TableAction.TypeCase typeCase = tableActionMsg.getTypeCase();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400453 switch (typeCase) {
454 case ACTION:
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400455 Action actionMsg = tableActionMsg.getAction();
Yi Tseng82512da2017-08-16 19:46:36 -0700456 return decodeActionMsg(actionMsg, browser);
Yi Tseng95390822018-01-22 17:57:22 -0800457 case ACTION_PROFILE_GROUP_ID:
458 return PiActionGroupId.of(tableActionMsg.getActionProfileGroupId());
459 case ACTION_PROFILE_MEMBER_ID:
460 return PiActionGroupMemberId.of(tableActionMsg.getActionProfileMemberId());
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400461 default:
462 throw new EncodeException(
463 format("Decoding of table action type %s not implemented", typeCase.name()));
464 }
465 }
466
Yi Tseng82512da2017-08-16 19:46:36 -0700467 static Action encodePiAction(PiAction piAction, P4InfoBrowser browser)
468 throws P4InfoBrowser.NotFoundException, EncodeException {
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400469
Carmelo Cascone87892e22017-11-13 16:01:29 -0800470 int actionId = browser.actions().getByName(piAction.id().toString()).getPreamble().getId();
Yi Tseng82512da2017-08-16 19:46:36 -0700471
472 Action.Builder actionMsgBuilder =
473 Action.newBuilder().setActionId(actionId);
474
475 for (PiActionParam p : piAction.parameters()) {
Carmelo Cascone87892e22017-11-13 16:01:29 -0800476 P4InfoOuterClass.Action.Param paramInfo = browser.actionParams(actionId).getByName(p.id().toString());
Yi Tseng82512da2017-08-16 19:46:36 -0700477 ByteString paramValue = ByteString.copyFrom(p.value().asReadOnlyBuffer());
478 assertSize(format("param '%s' of action '%s'", p.id(), piAction.id()),
479 paramValue, paramInfo.getBitwidth());
480 actionMsgBuilder.addParams(Action.Param.newBuilder()
481 .setParamId(paramInfo.getId())
482 .setValue(paramValue)
483 .build());
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400484 }
Yi Tseng82512da2017-08-16 19:46:36 -0700485
486 return actionMsgBuilder.build();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400487 }
488
Yi Tseng82512da2017-08-16 19:46:36 -0700489 static PiAction decodeActionMsg(Action action, P4InfoBrowser browser)
490 throws P4InfoBrowser.NotFoundException {
491 P4InfoBrowser.EntityBrowser<P4InfoOuterClass.Action.Param> paramInfo =
492 browser.actionParams(action.getActionId());
493 String actionName = browser.actions()
494 .getById(action.getActionId())
495 .getPreamble().getName();
496 PiActionId id = PiActionId.of(actionName);
497 List<PiActionParam> params = Lists.newArrayList();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400498
Yi Tseng82512da2017-08-16 19:46:36 -0700499 for (Action.Param p : action.getParamsList()) {
500 String paramName = paramInfo.getById(p.getParamId()).getName();
501 ImmutableByteSequence value = ImmutableByteSequence.copyFrom(p.getValue().toByteArray());
502 params.add(new PiActionParam(PiActionParamId.of(paramName), value));
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400503 }
Yi Tseng82512da2017-08-16 19:46:36 -0700504 return PiAction.builder().withId(id).withParameters(params).build();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400505 }
506}