blob: 647b9cd06e397d6191908f6646d8792127d59de2 [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
Yi Tsengd28936e2018-02-23 22:11:11 +010052import static com.google.common.base.Preconditions.checkNotNull;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040053import static java.lang.String.format;
54import static org.onlab.util.ImmutableByteSequence.copyFrom;
Yi Tseng82512da2017-08-16 19:46:36 -070055import static org.onosproject.p4runtime.ctl.P4RuntimeUtils.assertPrefixLen;
56import static org.onosproject.p4runtime.ctl.P4RuntimeUtils.assertSize;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040057import static org.slf4j.LoggerFactory.getLogger;
58
59/**
Yi Tseng82512da2017-08-16 19:46:36 -070060 * Encoder/Decoder of table entries, from ONOS Pi* format, to P4Runtime protobuf messages, and vice versa.
Carmelo Cascone8d99b172017-07-18 17:26:31 -040061 */
62final class TableEntryEncoder {
Carmelo Cascone8d99b172017-07-18 17:26:31 -040063 private static final Logger log = getLogger(TableEntryEncoder.class);
64
Carmelo Cascone8d99b172017-07-18 17:26:31 -040065 private static final String VALUE_OF_PREFIX = "value of ";
66 private static final String MASK_OF_PREFIX = "mask of ";
67 private static final String HIGH_RANGE_VALUE_OF_PREFIX = "high range value of ";
68 private static final String LOW_RANGE_VALUE_OF_PREFIX = "low range value of ";
69
70 // TODO: implement cache of encoded entities.
71
72 private TableEntryEncoder() {
73 // hide.
74 }
75
76 /**
Carmelo Cascone5bc7e102018-02-18 18:27:55 -080077 * Returns a collection of P4Runtime table entry protobuf messages, encoded
78 * from the given collection of PI table entries for the given pipeconf. If
79 * a PI table entry cannot be encoded, an EncodeException is thrown.
Carmelo Cascone8d99b172017-07-18 17:26:31 -040080 *
81 * @param piTableEntries PI table entries
82 * @param pipeconf PI pipeconf
83 * @return collection of P4Runtime table entry protobuf messages
Carmelo Cascone5bc7e102018-02-18 18:27:55 -080084 * @throws EncodeException if a PI table entry cannot be encoded
Carmelo Cascone8d99b172017-07-18 17:26:31 -040085 */
Carmelo Cascone5bc7e102018-02-18 18:27:55 -080086 static Collection<TableEntry> encode(Collection<PiTableEntry> piTableEntries,
87 PiPipeconf pipeconf)
88 throws EncodeException {
Carmelo Cascone8d99b172017-07-18 17:26:31 -040089
90 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
91
92 if (browser == null) {
Carmelo Cascone5bc7e102018-02-18 18:27:55 -080093 throw new EncodeException(format(
94 "Unable to get a P4Info browser for pipeconf %s", pipeconf.id()));
Carmelo Cascone8d99b172017-07-18 17:26:31 -040095 }
96
97 ImmutableList.Builder<TableEntry> tableEntryMsgListBuilder = ImmutableList.builder();
98
99 for (PiTableEntry piTableEntry : piTableEntries) {
100 try {
101 tableEntryMsgListBuilder.add(encodePiTableEntry(piTableEntry, browser));
Carmelo Cascone5bc7e102018-02-18 18:27:55 -0800102 } catch (P4InfoBrowser.NotFoundException e) {
103 throw new EncodeException(e.getMessage());
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400104 }
105 }
106
107 return tableEntryMsgListBuilder.build();
108 }
109
110 /**
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200111 * Same as {@link #encode(Collection, PiPipeconf)} but encodes only one entry.
112 *
113 * @param piTableEntry table entry
114 * @param pipeconf pipeconf
115 * @return encoded table entry message
116 * @throws EncodeException if entry cannot be encoded
117 * @throws P4InfoBrowser.NotFoundException if the required information cannot be find in the pipeconf's P4info
118 */
119 static TableEntry encode(PiTableEntry piTableEntry, PiPipeconf pipeconf)
120 throws EncodeException, P4InfoBrowser.NotFoundException {
121
122 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
123 if (browser == null) {
124 throw new EncodeException(format("Unable to get a P4Info browser for pipeconf %s", pipeconf.id()));
125 }
126
127 return encodePiTableEntry(piTableEntry, browser);
128 }
129
130 /**
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400131 * Returns a collection of PI table entry objects, decoded from the given collection of P4Runtime table entry
132 * messages for the given pipeconf. If a table entry message cannot be decoded, it is skipped, hence the returned
133 * collection might have different size than the input one.
134 * <p>
135 * Please check the log for an explanation of any error that might have occurred.
136 *
137 * @param tableEntryMsgs P4Runtime table entry messages
138 * @param pipeconf PI pipeconf
139 * @return collection of PI table entry objects
140 */
141 static Collection<PiTableEntry> decode(Collection<TableEntry> tableEntryMsgs, PiPipeconf pipeconf) {
142
143 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
144
145 if (browser == null) {
146 log.error("Unable to get a P4Info browser for pipeconf {}, skipping decoding of all table entries");
147 return Collections.emptyList();
148 }
149
150 ImmutableList.Builder<PiTableEntry> piTableEntryListBuilder = ImmutableList.builder();
151
152 for (TableEntry tableEntryMsg : tableEntryMsgs) {
153 try {
154 piTableEntryListBuilder.add(decodeTableEntryMsg(tableEntryMsg, browser));
155 } catch (P4InfoBrowser.NotFoundException | EncodeException e) {
156 log.error("Unable to decode table entry message: {}", e.getMessage());
157 }
158 }
159
160 return piTableEntryListBuilder.build();
161 }
162
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200163 /**
164 * Same as {@link #decode(Collection, PiPipeconf)} but decodes only one entry.
165 *
166 * @param tableEntryMsg table entry message
167 * @param pipeconf pipeconf
168 * @return decoded PI table entry
169 * @throws EncodeException if message cannot be decoded
170 * @throws P4InfoBrowser.NotFoundException if the required information cannot be find in the pipeconf's P4info
171 */
172 static PiTableEntry decode(TableEntry tableEntryMsg, PiPipeconf pipeconf)
173 throws EncodeException, P4InfoBrowser.NotFoundException {
174
175 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
176 if (browser == null) {
177 throw new EncodeException(format("Unable to get a P4Info browser for pipeconf %s", pipeconf.id()));
178 }
179 return decodeTableEntryMsg(tableEntryMsg, browser);
180 }
181
182 /**
183 * Returns a table entry protobuf message, encoded from the given table id and match key, for the given pipeconf.
184 * The returned table entry message can be only used to reference an existing entry, i.e. a read operation, and not
185 * a write one wince it misses other fields (action, priority, etc.).
186 *
187 * @param tableId table identifier
188 * @param matchKey match key
189 * @param pipeconf pipeconf
190 * @return table entry message
191 * @throws EncodeException if message cannot be encoded
192 * @throws P4InfoBrowser.NotFoundException if the required information cannot be find in the pipeconf's P4info
193 */
194 static TableEntry encode(PiTableId tableId, PiMatchKey matchKey, PiPipeconf pipeconf)
195 throws EncodeException, P4InfoBrowser.NotFoundException {
196
197 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
198 TableEntry.Builder tableEntryMsgBuilder = TableEntry.newBuilder();
199
Carmelo Casconecb0a49c2017-10-03 14:32:23 +0200200 P4InfoOuterClass.Table tableInfo = browser.tables().getByName(tableId.id());
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200201
202 // Table id.
203 tableEntryMsgBuilder.setTableId(tableInfo.getPreamble().getId());
204
205 // Field matches.
Carmelo Cascone4256bde2018-03-23 18:02:15 -0700206 if (matchKey.equals(PiMatchKey.EMPTY)) {
207 tableEntryMsgBuilder.setIsDefaultAction(true);
208 } else {
209 for (PiFieldMatch piFieldMatch : matchKey.fieldMatches()) {
210 tableEntryMsgBuilder.addMatch(encodePiFieldMatch(piFieldMatch, tableInfo, browser));
211 }
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200212 }
213
214 return tableEntryMsgBuilder.build();
215 }
216
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400217 private static TableEntry encodePiTableEntry(PiTableEntry piTableEntry, P4InfoBrowser browser)
218 throws P4InfoBrowser.NotFoundException, EncodeException {
219
220 TableEntry.Builder tableEntryMsgBuilder = TableEntry.newBuilder();
221
Carmelo Casconecb0a49c2017-10-03 14:32:23 +0200222 P4InfoOuterClass.Table tableInfo = browser.tables().getByName(piTableEntry.table().id());
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400223
224 // Table id.
225 tableEntryMsgBuilder.setTableId(tableInfo.getPreamble().getId());
226
227 // Priority.
Yi Tseng088f4ce2017-08-15 10:54:14 -0700228 // FIXME: check on P4Runtime if/what is the default priority.
Yi Tseng02c4c572018-01-22 17:52:10 -0800229 piTableEntry.priority().ifPresent(tableEntryMsgBuilder::setPriority);
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400230
231 // Controller metadata (cookie)
232 tableEntryMsgBuilder.setControllerMetadata(piTableEntry.cookie());
233
234 // Timeout.
235 if (piTableEntry.timeout().isPresent()) {
236 log.warn("Found PI table entry with timeout set, not supported in P4Runtime: {}", piTableEntry);
237 }
238
239 // Table action.
Yi Tsengd28936e2018-02-23 22:11:11 +0100240 if (piTableEntry.action() != null) {
241 tableEntryMsgBuilder.setAction(encodePiTableAction(piTableEntry.action(), browser));
242 }
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400243
244 // Field matches.
Carmelo Cascone4256bde2018-03-23 18:02:15 -0700245 if (piTableEntry.matchKey().equals(PiMatchKey.EMPTY)) {
246 tableEntryMsgBuilder.setIsDefaultAction(true);
247 } else {
248 for (PiFieldMatch piFieldMatch : piTableEntry.matchKey().fieldMatches()) {
249 tableEntryMsgBuilder.addMatch(encodePiFieldMatch(piFieldMatch, tableInfo, browser));
250 }
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400251 }
252
253 return tableEntryMsgBuilder.build();
254 }
255
256 private static PiTableEntry decodeTableEntryMsg(TableEntry tableEntryMsg, P4InfoBrowser browser)
257 throws P4InfoBrowser.NotFoundException, EncodeException {
258
259 PiTableEntry.Builder piTableEntryBuilder = PiTableEntry.builder();
260
261 P4InfoOuterClass.Table tableInfo = browser.tables().getById(tableEntryMsg.getTableId());
262
263 // Table id.
264 piTableEntryBuilder.forTable(PiTableId.of(tableInfo.getPreamble().getName()));
265
266 // Priority.
267 piTableEntryBuilder.withPriority(tableEntryMsg.getPriority());
268
269 // Controller metadata (cookie)
270 piTableEntryBuilder.withCookie(tableEntryMsg.getControllerMetadata());
271
272 // Table action.
Yi Tsengd28936e2018-02-23 22:11:11 +0100273 if (tableEntryMsg.hasAction()) {
274 piTableEntryBuilder.withAction(decodeTableActionMsg(tableEntryMsg.getAction(), browser));
275 }
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400276
277 // Timeout.
278 // FIXME: how to decode table entry messages with timeout, given that the timeout value is lost after encoding?
279
Carmelo Cascone0e896a02017-07-31 07:22:27 +0200280 // Match key for field matches.
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200281 piTableEntryBuilder.withMatchKey(decodeFieldMatchMsgs(tableEntryMsg.getMatchList(), tableInfo, browser));
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400282
283 return piTableEntryBuilder.build();
284 }
285
286 private static FieldMatch encodePiFieldMatch(PiFieldMatch piFieldMatch, P4InfoOuterClass.Table tableInfo,
287 P4InfoBrowser browser)
288 throws P4InfoBrowser.NotFoundException, EncodeException {
289
290 FieldMatch.Builder fieldMatchMsgBuilder = FieldMatch.newBuilder();
291
292 // FIXME: check how field names for stacked headers are constructed in P4Runtime.
293 String fieldName = piFieldMatch.fieldId().id();
294 int tableId = tableInfo.getPreamble().getId();
Carmelo Casconecb0a49c2017-10-03 14:32:23 +0200295 P4InfoOuterClass.MatchField matchFieldInfo = browser.matchFields(tableId).getByName(fieldName);
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400296 String entityName = format("field match '%s' of table '%s'",
297 matchFieldInfo.getName(), tableInfo.getPreamble().getName());
298 int fieldId = matchFieldInfo.getId();
299 int fieldBitwidth = matchFieldInfo.getBitwidth();
300
301 fieldMatchMsgBuilder.setFieldId(fieldId);
302
303 switch (piFieldMatch.type()) {
304 case EXACT:
305 PiExactFieldMatch fieldMatch = (PiExactFieldMatch) piFieldMatch;
306 ByteString exactValue = ByteString.copyFrom(fieldMatch.value().asReadOnlyBuffer());
307 assertSize(VALUE_OF_PREFIX + entityName, exactValue, fieldBitwidth);
308 return fieldMatchMsgBuilder.setExact(
309 FieldMatch.Exact
310 .newBuilder()
311 .setValue(exactValue)
312 .build())
313 .build();
314 case TERNARY:
315 PiTernaryFieldMatch ternaryMatch = (PiTernaryFieldMatch) piFieldMatch;
316 ByteString ternaryValue = ByteString.copyFrom(ternaryMatch.value().asReadOnlyBuffer());
317 ByteString ternaryMask = ByteString.copyFrom(ternaryMatch.mask().asReadOnlyBuffer());
318 assertSize(VALUE_OF_PREFIX + entityName, ternaryValue, fieldBitwidth);
319 assertSize(MASK_OF_PREFIX + entityName, ternaryMask, fieldBitwidth);
320 return fieldMatchMsgBuilder.setTernary(
321 FieldMatch.Ternary
322 .newBuilder()
323 .setValue(ternaryValue)
324 .setMask(ternaryMask)
325 .build())
326 .build();
327 case LPM:
328 PiLpmFieldMatch lpmMatch = (PiLpmFieldMatch) piFieldMatch;
329 ByteString lpmValue = ByteString.copyFrom(lpmMatch.value().asReadOnlyBuffer());
330 int lpmPrefixLen = lpmMatch.prefixLength();
331 assertSize(VALUE_OF_PREFIX + entityName, lpmValue, fieldBitwidth);
332 assertPrefixLen(entityName, lpmPrefixLen, fieldBitwidth);
333 return fieldMatchMsgBuilder.setLpm(
334 FieldMatch.LPM.newBuilder()
335 .setValue(lpmValue)
336 .setPrefixLen(lpmPrefixLen)
337 .build())
338 .build();
339 case RANGE:
340 PiRangeFieldMatch rangeMatch = (PiRangeFieldMatch) piFieldMatch;
341 ByteString rangeHighValue = ByteString.copyFrom(rangeMatch.highValue().asReadOnlyBuffer());
342 ByteString rangeLowValue = ByteString.copyFrom(rangeMatch.lowValue().asReadOnlyBuffer());
343 assertSize(HIGH_RANGE_VALUE_OF_PREFIX + entityName, rangeHighValue, fieldBitwidth);
344 assertSize(LOW_RANGE_VALUE_OF_PREFIX + entityName, rangeLowValue, fieldBitwidth);
345 return fieldMatchMsgBuilder.setRange(
346 FieldMatch.Range.newBuilder()
347 .setHigh(rangeHighValue)
348 .setLow(rangeLowValue)
349 .build())
350 .build();
351 case VALID:
352 PiValidFieldMatch validMatch = (PiValidFieldMatch) piFieldMatch;
353 return fieldMatchMsgBuilder.setValid(
354 FieldMatch.Valid.newBuilder()
355 .setValue(validMatch.isValid())
356 .build())
357 .build();
358 default:
359 throw new EncodeException(format(
360 "Building of match type %s not implemented", piFieldMatch.type()));
361 }
362 }
363
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200364 /**
365 * Returns a PI match key, decoded from the given table entry protobuf message, for the given pipeconf.
366 *
367 * @param tableEntryMsg table entry message
368 * @param pipeconf pipeconf
369 * @return PI match key
370 * @throws EncodeException if message cannot be decoded
371 * @throws P4InfoBrowser.NotFoundException if the required information cannot be find in the pipeconf's P4info
372 */
373 static PiMatchKey decodeMatchKey(TableEntry tableEntryMsg, PiPipeconf pipeconf)
374 throws P4InfoBrowser.NotFoundException, EncodeException {
375 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
376 P4InfoOuterClass.Table tableInfo = browser.tables().getById(tableEntryMsg.getTableId());
Carmelo Cascone4256bde2018-03-23 18:02:15 -0700377 if (tableEntryMsg.getMatchCount() == 0) {
378 return PiMatchKey.EMPTY;
379 } else {
380 return decodeFieldMatchMsgs(tableEntryMsg.getMatchList(), tableInfo, browser);
381 }
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200382 }
383
384 private static PiMatchKey decodeFieldMatchMsgs(Collection<FieldMatch> fieldMatchs, P4InfoOuterClass.Table tableInfo,
385 P4InfoBrowser browser)
386 throws P4InfoBrowser.NotFoundException, EncodeException {
387 // Match key for field matches.
388 PiMatchKey.Builder piMatchKeyBuilder = PiMatchKey.builder();
389 for (FieldMatch fieldMatchMsg : fieldMatchs) {
390 piMatchKeyBuilder.addFieldMatch(decodeFieldMatchMsg(fieldMatchMsg, tableInfo, browser));
391 }
392 return piMatchKeyBuilder.build();
393 }
394
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400395 private static PiFieldMatch decodeFieldMatchMsg(FieldMatch fieldMatchMsg, P4InfoOuterClass.Table tableInfo,
396 P4InfoBrowser browser)
397 throws P4InfoBrowser.NotFoundException, EncodeException {
398
399 int tableId = tableInfo.getPreamble().getId();
400 String fieldMatchName = browser.matchFields(tableId).getById(fieldMatchMsg.getFieldId()).getName();
Carmelo Cascone87892e22017-11-13 16:01:29 -0800401 PiMatchFieldId headerFieldId = PiMatchFieldId.of(fieldMatchName);
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400402
403 FieldMatch.FieldMatchTypeCase typeCase = fieldMatchMsg.getFieldMatchTypeCase();
404
405 switch (typeCase) {
406 case EXACT:
407 FieldMatch.Exact exactFieldMatch = fieldMatchMsg.getExact();
408 ImmutableByteSequence exactValue = copyFrom(exactFieldMatch.getValue().asReadOnlyByteBuffer());
409 return new PiExactFieldMatch(headerFieldId, exactValue);
410 case TERNARY:
411 FieldMatch.Ternary ternaryFieldMatch = fieldMatchMsg.getTernary();
412 ImmutableByteSequence ternaryValue = copyFrom(ternaryFieldMatch.getValue().asReadOnlyByteBuffer());
413 ImmutableByteSequence ternaryMask = copyFrom(ternaryFieldMatch.getMask().asReadOnlyByteBuffer());
414 return new PiTernaryFieldMatch(headerFieldId, ternaryValue, ternaryMask);
415 case LPM:
416 FieldMatch.LPM lpmFieldMatch = fieldMatchMsg.getLpm();
417 ImmutableByteSequence lpmValue = copyFrom(lpmFieldMatch.getValue().asReadOnlyByteBuffer());
418 int lpmPrefixLen = lpmFieldMatch.getPrefixLen();
419 return new PiLpmFieldMatch(headerFieldId, lpmValue, lpmPrefixLen);
420 case RANGE:
421 FieldMatch.Range rangeFieldMatch = fieldMatchMsg.getRange();
422 ImmutableByteSequence rangeHighValue = copyFrom(rangeFieldMatch.getHigh().asReadOnlyByteBuffer());
423 ImmutableByteSequence rangeLowValue = copyFrom(rangeFieldMatch.getLow().asReadOnlyByteBuffer());
424 return new PiRangeFieldMatch(headerFieldId, rangeLowValue, rangeHighValue);
425 case VALID:
426 FieldMatch.Valid validFieldMatch = fieldMatchMsg.getValid();
427 return new PiValidFieldMatch(headerFieldId, validFieldMatch.getValue());
428 default:
429 throw new EncodeException(format(
430 "Decoding of field match type '%s' not implemented", typeCase.name()));
431 }
432 }
433
Yi Tseng82512da2017-08-16 19:46:36 -0700434 static TableAction encodePiTableAction(PiTableAction piTableAction, P4InfoBrowser browser)
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400435 throws P4InfoBrowser.NotFoundException, EncodeException {
Yi Tsengd28936e2018-02-23 22:11:11 +0100436 checkNotNull(piTableAction, "Cannot encode null PiTableAction");
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400437 TableAction.Builder tableActionMsgBuilder = TableAction.newBuilder();
438
439 switch (piTableAction.type()) {
440 case ACTION:
441 PiAction piAction = (PiAction) piTableAction;
Yi Tseng82512da2017-08-16 19:46:36 -0700442 Action theAction = encodePiAction(piAction, browser);
443 tableActionMsgBuilder.setAction(theAction);
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400444 break;
Yi Tseng82512da2017-08-16 19:46:36 -0700445 case ACTION_GROUP_ID:
446 PiActionGroupId actionGroupId = (PiActionGroupId) piTableAction;
447 tableActionMsgBuilder.setActionProfileGroupId(actionGroupId.id());
448 break;
449 case GROUP_MEMBER_ID:
450 PiActionGroupMemberId actionGroupMemberId = (PiActionGroupMemberId) piTableAction;
451 tableActionMsgBuilder.setActionProfileMemberId(actionGroupMemberId.id());
452 break;
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400453 default:
454 throw new EncodeException(
455 format("Building of table action type %s not implemented", piTableAction.type()));
456 }
457
458 return tableActionMsgBuilder.build();
459 }
460
Yi Tseng82512da2017-08-16 19:46:36 -0700461 static PiTableAction decodeTableActionMsg(TableAction tableActionMsg, P4InfoBrowser browser)
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400462 throws P4InfoBrowser.NotFoundException, EncodeException {
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400463 TableAction.TypeCase typeCase = tableActionMsg.getTypeCase();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400464 switch (typeCase) {
465 case ACTION:
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400466 Action actionMsg = tableActionMsg.getAction();
Yi Tseng82512da2017-08-16 19:46:36 -0700467 return decodeActionMsg(actionMsg, browser);
Yi Tseng95390822018-01-22 17:57:22 -0800468 case ACTION_PROFILE_GROUP_ID:
469 return PiActionGroupId.of(tableActionMsg.getActionProfileGroupId());
470 case ACTION_PROFILE_MEMBER_ID:
471 return PiActionGroupMemberId.of(tableActionMsg.getActionProfileMemberId());
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400472 default:
473 throw new EncodeException(
474 format("Decoding of table action type %s not implemented", typeCase.name()));
475 }
476 }
477
Yi Tseng82512da2017-08-16 19:46:36 -0700478 static Action encodePiAction(PiAction piAction, P4InfoBrowser browser)
479 throws P4InfoBrowser.NotFoundException, EncodeException {
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400480
Carmelo Cascone87892e22017-11-13 16:01:29 -0800481 int actionId = browser.actions().getByName(piAction.id().toString()).getPreamble().getId();
Yi Tseng82512da2017-08-16 19:46:36 -0700482
483 Action.Builder actionMsgBuilder =
484 Action.newBuilder().setActionId(actionId);
485
486 for (PiActionParam p : piAction.parameters()) {
Carmelo Cascone87892e22017-11-13 16:01:29 -0800487 P4InfoOuterClass.Action.Param paramInfo = browser.actionParams(actionId).getByName(p.id().toString());
Yi Tseng82512da2017-08-16 19:46:36 -0700488 ByteString paramValue = ByteString.copyFrom(p.value().asReadOnlyBuffer());
489 assertSize(format("param '%s' of action '%s'", p.id(), piAction.id()),
490 paramValue, paramInfo.getBitwidth());
491 actionMsgBuilder.addParams(Action.Param.newBuilder()
492 .setParamId(paramInfo.getId())
493 .setValue(paramValue)
494 .build());
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400495 }
Yi Tseng82512da2017-08-16 19:46:36 -0700496
497 return actionMsgBuilder.build();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400498 }
499
Yi Tseng82512da2017-08-16 19:46:36 -0700500 static PiAction decodeActionMsg(Action action, P4InfoBrowser browser)
501 throws P4InfoBrowser.NotFoundException {
502 P4InfoBrowser.EntityBrowser<P4InfoOuterClass.Action.Param> paramInfo =
503 browser.actionParams(action.getActionId());
504 String actionName = browser.actions()
505 .getById(action.getActionId())
506 .getPreamble().getName();
507 PiActionId id = PiActionId.of(actionName);
508 List<PiActionParam> params = Lists.newArrayList();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400509
Yi Tseng82512da2017-08-16 19:46:36 -0700510 for (Action.Param p : action.getParamsList()) {
511 String paramName = paramInfo.getById(p.getParamId()).getName();
512 ImmutableByteSequence value = ImmutableByteSequence.copyFrom(p.getValue().toByteArray());
513 params.add(new PiActionParam(PiActionParamId.of(paramName), value));
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400514 }
Yi Tseng82512da2017-08-16 19:46:36 -0700515 return PiAction.builder().withId(id).withParameters(params).build();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400516 }
517}