blob: 7e2df982f1854442764db00255874e212c6512ae [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;
steven308017632e152018-10-20 00:51:08 +080032import org.onosproject.net.pi.runtime.PiCounterCellData;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040033import org.onosproject.net.pi.runtime.PiExactFieldMatch;
34import org.onosproject.net.pi.runtime.PiFieldMatch;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040035import org.onosproject.net.pi.runtime.PiLpmFieldMatch;
Carmelo Cascone0e896a02017-07-31 07:22:27 +020036import org.onosproject.net.pi.runtime.PiMatchKey;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040037import org.onosproject.net.pi.runtime.PiRangeFieldMatch;
38import org.onosproject.net.pi.runtime.PiTableAction;
39import org.onosproject.net.pi.runtime.PiTableEntry;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040040import org.onosproject.net.pi.runtime.PiTernaryFieldMatch;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040041import org.slf4j.Logger;
Carmelo Casconee44592f2018-09-12 02:24:47 -070042import p4.config.v1.P4InfoOuterClass;
Carmelo Cascone6af4e172018-06-15 16:01:30 +020043import p4.v1.P4RuntimeOuterClass.Action;
steven308017632e152018-10-20 00:51:08 +080044import p4.v1.P4RuntimeOuterClass.CounterData;
Carmelo Cascone6af4e172018-06-15 16:01:30 +020045import p4.v1.P4RuntimeOuterClass.FieldMatch;
46import p4.v1.P4RuntimeOuterClass.TableAction;
47import p4.v1.P4RuntimeOuterClass.TableEntry;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040048
49import java.util.Collection;
50import java.util.Collections;
Yi Tseng82512da2017-08-16 19:46:36 -070051import java.util.List;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040052
Yi Tsengd28936e2018-02-23 22:11:11 +010053import static com.google.common.base.Preconditions.checkNotNull;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040054import static java.lang.String.format;
55import static org.onlab.util.ImmutableByteSequence.copyFrom;
Yi Tseng82512da2017-08-16 19:46:36 -070056import static org.onosproject.p4runtime.ctl.P4RuntimeUtils.assertPrefixLen;
57import static org.onosproject.p4runtime.ctl.P4RuntimeUtils.assertSize;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040058import static org.slf4j.LoggerFactory.getLogger;
59
60/**
Yi Tseng82512da2017-08-16 19:46:36 -070061 * Encoder/Decoder of table entries, from ONOS Pi* format, to P4Runtime protobuf messages, and vice versa.
Carmelo Cascone8d99b172017-07-18 17:26:31 -040062 */
63final class TableEntryEncoder {
Carmelo Cascone8d99b172017-07-18 17:26:31 -040064 private static final Logger log = getLogger(TableEntryEncoder.class);
65
Carmelo Cascone8d99b172017-07-18 17:26:31 -040066 private static final String VALUE_OF_PREFIX = "value of ";
67 private static final String MASK_OF_PREFIX = "mask of ";
68 private static final String HIGH_RANGE_VALUE_OF_PREFIX = "high range value of ";
69 private static final String LOW_RANGE_VALUE_OF_PREFIX = "low range value of ";
70
71 // TODO: implement cache of encoded entities.
72
73 private TableEntryEncoder() {
74 // hide.
75 }
76
77 /**
Carmelo Cascone5bc7e102018-02-18 18:27:55 -080078 * Returns a collection of P4Runtime table entry protobuf messages, encoded
79 * from the given collection of PI table entries for the given pipeconf. If
80 * a PI table entry cannot be encoded, an EncodeException is thrown.
Carmelo Cascone8d99b172017-07-18 17:26:31 -040081 *
82 * @param piTableEntries PI table entries
83 * @param pipeconf PI pipeconf
84 * @return collection of P4Runtime table entry protobuf messages
Carmelo Cascone5bc7e102018-02-18 18:27:55 -080085 * @throws EncodeException if a PI table entry cannot be encoded
Carmelo Cascone8d99b172017-07-18 17:26:31 -040086 */
Carmelo Casconee44592f2018-09-12 02:24:47 -070087 static List<TableEntry> encode(List<PiTableEntry> piTableEntries,
Carmelo Cascone5bc7e102018-02-18 18:27:55 -080088 PiPipeconf pipeconf)
89 throws EncodeException {
Carmelo Cascone8d99b172017-07-18 17:26:31 -040090
91 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
92
93 if (browser == null) {
Carmelo Cascone5bc7e102018-02-18 18:27:55 -080094 throw new EncodeException(format(
95 "Unable to get a P4Info browser for pipeconf %s", pipeconf.id()));
Carmelo Cascone8d99b172017-07-18 17:26:31 -040096 }
97
98 ImmutableList.Builder<TableEntry> tableEntryMsgListBuilder = ImmutableList.builder();
99
100 for (PiTableEntry piTableEntry : piTableEntries) {
101 try {
102 tableEntryMsgListBuilder.add(encodePiTableEntry(piTableEntry, browser));
Carmelo Cascone5bc7e102018-02-18 18:27:55 -0800103 } catch (P4InfoBrowser.NotFoundException e) {
104 throw new EncodeException(e.getMessage());
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400105 }
106 }
107
108 return tableEntryMsgListBuilder.build();
109 }
110
111 /**
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200112 * Same as {@link #encode(Collection, PiPipeconf)} but encodes only one entry.
113 *
114 * @param piTableEntry table entry
115 * @param pipeconf pipeconf
116 * @return encoded table entry message
117 * @throws EncodeException if entry cannot be encoded
118 * @throws P4InfoBrowser.NotFoundException if the required information cannot be find in the pipeconf's P4info
119 */
120 static TableEntry encode(PiTableEntry piTableEntry, PiPipeconf pipeconf)
121 throws EncodeException, P4InfoBrowser.NotFoundException {
122
123 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
124 if (browser == null) {
125 throw new EncodeException(format("Unable to get a P4Info browser for pipeconf %s", pipeconf.id()));
126 }
127
128 return encodePiTableEntry(piTableEntry, browser);
129 }
130
131 /**
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400132 * Returns a collection of PI table entry objects, decoded from the given collection of P4Runtime table entry
133 * messages for the given pipeconf. If a table entry message cannot be decoded, it is skipped, hence the returned
134 * collection might have different size than the input one.
135 * <p>
136 * Please check the log for an explanation of any error that might have occurred.
137 *
138 * @param tableEntryMsgs P4Runtime table entry messages
139 * @param pipeconf PI pipeconf
140 * @return collection of PI table entry objects
141 */
Carmelo Casconee44592f2018-09-12 02:24:47 -0700142 static List<PiTableEntry> decode(List<TableEntry> tableEntryMsgs, PiPipeconf pipeconf) {
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400143
144 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
145
146 if (browser == null) {
147 log.error("Unable to get a P4Info browser for pipeconf {}, skipping decoding of all table entries");
148 return Collections.emptyList();
149 }
150
151 ImmutableList.Builder<PiTableEntry> piTableEntryListBuilder = ImmutableList.builder();
152
153 for (TableEntry tableEntryMsg : tableEntryMsgs) {
154 try {
155 piTableEntryListBuilder.add(decodeTableEntryMsg(tableEntryMsg, browser));
156 } catch (P4InfoBrowser.NotFoundException | EncodeException e) {
157 log.error("Unable to decode table entry message: {}", e.getMessage());
158 }
159 }
160
161 return piTableEntryListBuilder.build();
162 }
163
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200164 /**
165 * Same as {@link #decode(Collection, PiPipeconf)} but decodes only one entry.
166 *
167 * @param tableEntryMsg table entry message
168 * @param pipeconf pipeconf
169 * @return decoded PI table entry
170 * @throws EncodeException if message cannot be decoded
171 * @throws P4InfoBrowser.NotFoundException if the required information cannot be find in the pipeconf's P4info
172 */
173 static PiTableEntry decode(TableEntry tableEntryMsg, PiPipeconf pipeconf)
174 throws EncodeException, P4InfoBrowser.NotFoundException {
175
176 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
177 if (browser == null) {
178 throw new EncodeException(format("Unable to get a P4Info browser for pipeconf %s", pipeconf.id()));
179 }
180 return decodeTableEntryMsg(tableEntryMsg, browser);
181 }
182
183 /**
184 * Returns a table entry protobuf message, encoded from the given table id and match key, for the given pipeconf.
185 * The returned table entry message can be only used to reference an existing entry, i.e. a read operation, and not
186 * a write one wince it misses other fields (action, priority, etc.).
187 *
188 * @param tableId table identifier
189 * @param matchKey match key
190 * @param pipeconf pipeconf
191 * @return table entry message
192 * @throws EncodeException if message cannot be encoded
193 * @throws P4InfoBrowser.NotFoundException if the required information cannot be find in the pipeconf's P4info
194 */
195 static TableEntry encode(PiTableId tableId, PiMatchKey matchKey, PiPipeconf pipeconf)
196 throws EncodeException, P4InfoBrowser.NotFoundException {
197
198 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
199 TableEntry.Builder tableEntryMsgBuilder = TableEntry.newBuilder();
200
Carmelo Casconecb0a49c2017-10-03 14:32:23 +0200201 P4InfoOuterClass.Table tableInfo = browser.tables().getByName(tableId.id());
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200202
203 // Table id.
204 tableEntryMsgBuilder.setTableId(tableInfo.getPreamble().getId());
205
206 // Field matches.
Carmelo Cascone4256bde2018-03-23 18:02:15 -0700207 if (matchKey.equals(PiMatchKey.EMPTY)) {
208 tableEntryMsgBuilder.setIsDefaultAction(true);
209 } else {
210 for (PiFieldMatch piFieldMatch : matchKey.fieldMatches()) {
211 tableEntryMsgBuilder.addMatch(encodePiFieldMatch(piFieldMatch, tableInfo, browser));
212 }
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200213 }
214
215 return tableEntryMsgBuilder.build();
216 }
217
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400218 private static TableEntry encodePiTableEntry(PiTableEntry piTableEntry, P4InfoBrowser browser)
219 throws P4InfoBrowser.NotFoundException, EncodeException {
220
221 TableEntry.Builder tableEntryMsgBuilder = TableEntry.newBuilder();
222
Carmelo Casconecb0a49c2017-10-03 14:32:23 +0200223 P4InfoOuterClass.Table tableInfo = browser.tables().getByName(piTableEntry.table().id());
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400224
225 // Table id.
226 tableEntryMsgBuilder.setTableId(tableInfo.getPreamble().getId());
227
228 // Priority.
Yi Tseng088f4ce2017-08-15 10:54:14 -0700229 // FIXME: check on P4Runtime if/what is the default priority.
Yi Tseng02c4c572018-01-22 17:52:10 -0800230 piTableEntry.priority().ifPresent(tableEntryMsgBuilder::setPriority);
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400231
232 // Controller metadata (cookie)
233 tableEntryMsgBuilder.setControllerMetadata(piTableEntry.cookie());
234
235 // Timeout.
236 if (piTableEntry.timeout().isPresent()) {
237 log.warn("Found PI table entry with timeout set, not supported in P4Runtime: {}", piTableEntry);
238 }
239
240 // Table action.
Yi Tsengd28936e2018-02-23 22:11:11 +0100241 if (piTableEntry.action() != null) {
242 tableEntryMsgBuilder.setAction(encodePiTableAction(piTableEntry.action(), browser));
243 }
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400244
245 // Field matches.
Carmelo Cascone4256bde2018-03-23 18:02:15 -0700246 if (piTableEntry.matchKey().equals(PiMatchKey.EMPTY)) {
247 tableEntryMsgBuilder.setIsDefaultAction(true);
248 } else {
249 for (PiFieldMatch piFieldMatch : piTableEntry.matchKey().fieldMatches()) {
250 tableEntryMsgBuilder.addMatch(encodePiFieldMatch(piFieldMatch, tableInfo, browser));
251 }
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400252 }
253
steven308017632e152018-10-20 00:51:08 +0800254 // Counter.
255 if (piTableEntry.counter() != null) {
256 tableEntryMsgBuilder.setCounterData(encodeCounter(piTableEntry.counter()));
257 }
258
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400259 return tableEntryMsgBuilder.build();
260 }
261
262 private static PiTableEntry decodeTableEntryMsg(TableEntry tableEntryMsg, P4InfoBrowser browser)
263 throws P4InfoBrowser.NotFoundException, EncodeException {
264
265 PiTableEntry.Builder piTableEntryBuilder = PiTableEntry.builder();
266
267 P4InfoOuterClass.Table tableInfo = browser.tables().getById(tableEntryMsg.getTableId());
268
269 // Table id.
270 piTableEntryBuilder.forTable(PiTableId.of(tableInfo.getPreamble().getName()));
271
272 // Priority.
Carmelo Cascone50d195f2018-09-11 13:26:38 -0700273 if (tableEntryMsg.getPriority() > 0) {
274 piTableEntryBuilder.withPriority(tableEntryMsg.getPriority());
275 }
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400276
277 // Controller metadata (cookie)
278 piTableEntryBuilder.withCookie(tableEntryMsg.getControllerMetadata());
279
280 // Table action.
Yi Tsengd28936e2018-02-23 22:11:11 +0100281 if (tableEntryMsg.hasAction()) {
282 piTableEntryBuilder.withAction(decodeTableActionMsg(tableEntryMsg.getAction(), browser));
283 }
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400284
285 // Timeout.
286 // FIXME: how to decode table entry messages with timeout, given that the timeout value is lost after encoding?
287
Carmelo Cascone0e896a02017-07-31 07:22:27 +0200288 // Match key for field matches.
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200289 piTableEntryBuilder.withMatchKey(decodeFieldMatchMsgs(tableEntryMsg.getMatchList(), tableInfo, browser));
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400290
steven308017632e152018-10-20 00:51:08 +0800291 // Counter.
292 piTableEntryBuilder.withCounterCellData(decodeCounter(tableEntryMsg.getCounterData()));
293
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400294 return piTableEntryBuilder.build();
295 }
296
297 private static FieldMatch encodePiFieldMatch(PiFieldMatch piFieldMatch, P4InfoOuterClass.Table tableInfo,
298 P4InfoBrowser browser)
299 throws P4InfoBrowser.NotFoundException, EncodeException {
300
301 FieldMatch.Builder fieldMatchMsgBuilder = FieldMatch.newBuilder();
302
303 // FIXME: check how field names for stacked headers are constructed in P4Runtime.
304 String fieldName = piFieldMatch.fieldId().id();
305 int tableId = tableInfo.getPreamble().getId();
Carmelo Casconecb0a49c2017-10-03 14:32:23 +0200306 P4InfoOuterClass.MatchField matchFieldInfo = browser.matchFields(tableId).getByName(fieldName);
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400307 String entityName = format("field match '%s' of table '%s'",
308 matchFieldInfo.getName(), tableInfo.getPreamble().getName());
309 int fieldId = matchFieldInfo.getId();
310 int fieldBitwidth = matchFieldInfo.getBitwidth();
311
312 fieldMatchMsgBuilder.setFieldId(fieldId);
313
314 switch (piFieldMatch.type()) {
315 case EXACT:
316 PiExactFieldMatch fieldMatch = (PiExactFieldMatch) piFieldMatch;
317 ByteString exactValue = ByteString.copyFrom(fieldMatch.value().asReadOnlyBuffer());
318 assertSize(VALUE_OF_PREFIX + entityName, exactValue, fieldBitwidth);
319 return fieldMatchMsgBuilder.setExact(
320 FieldMatch.Exact
321 .newBuilder()
322 .setValue(exactValue)
323 .build())
324 .build();
325 case TERNARY:
326 PiTernaryFieldMatch ternaryMatch = (PiTernaryFieldMatch) piFieldMatch;
327 ByteString ternaryValue = ByteString.copyFrom(ternaryMatch.value().asReadOnlyBuffer());
328 ByteString ternaryMask = ByteString.copyFrom(ternaryMatch.mask().asReadOnlyBuffer());
329 assertSize(VALUE_OF_PREFIX + entityName, ternaryValue, fieldBitwidth);
330 assertSize(MASK_OF_PREFIX + entityName, ternaryMask, fieldBitwidth);
331 return fieldMatchMsgBuilder.setTernary(
332 FieldMatch.Ternary
333 .newBuilder()
334 .setValue(ternaryValue)
335 .setMask(ternaryMask)
336 .build())
337 .build();
338 case LPM:
339 PiLpmFieldMatch lpmMatch = (PiLpmFieldMatch) piFieldMatch;
340 ByteString lpmValue = ByteString.copyFrom(lpmMatch.value().asReadOnlyBuffer());
341 int lpmPrefixLen = lpmMatch.prefixLength();
342 assertSize(VALUE_OF_PREFIX + entityName, lpmValue, fieldBitwidth);
343 assertPrefixLen(entityName, lpmPrefixLen, fieldBitwidth);
344 return fieldMatchMsgBuilder.setLpm(
345 FieldMatch.LPM.newBuilder()
346 .setValue(lpmValue)
347 .setPrefixLen(lpmPrefixLen)
348 .build())
349 .build();
350 case RANGE:
351 PiRangeFieldMatch rangeMatch = (PiRangeFieldMatch) piFieldMatch;
352 ByteString rangeHighValue = ByteString.copyFrom(rangeMatch.highValue().asReadOnlyBuffer());
353 ByteString rangeLowValue = ByteString.copyFrom(rangeMatch.lowValue().asReadOnlyBuffer());
354 assertSize(HIGH_RANGE_VALUE_OF_PREFIX + entityName, rangeHighValue, fieldBitwidth);
355 assertSize(LOW_RANGE_VALUE_OF_PREFIX + entityName, rangeLowValue, fieldBitwidth);
356 return fieldMatchMsgBuilder.setRange(
357 FieldMatch.Range.newBuilder()
358 .setHigh(rangeHighValue)
359 .setLow(rangeLowValue)
360 .build())
361 .build();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400362 default:
363 throw new EncodeException(format(
364 "Building of match type %s not implemented", piFieldMatch.type()));
365 }
366 }
367
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200368 /**
369 * Returns a PI match key, decoded from the given table entry protobuf message, for the given pipeconf.
370 *
371 * @param tableEntryMsg table entry message
372 * @param pipeconf pipeconf
373 * @return PI match key
374 * @throws EncodeException if message cannot be decoded
375 * @throws P4InfoBrowser.NotFoundException if the required information cannot be find in the pipeconf's P4info
376 */
377 static PiMatchKey decodeMatchKey(TableEntry tableEntryMsg, PiPipeconf pipeconf)
378 throws P4InfoBrowser.NotFoundException, EncodeException {
379 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
380 P4InfoOuterClass.Table tableInfo = browser.tables().getById(tableEntryMsg.getTableId());
Carmelo Cascone4256bde2018-03-23 18:02:15 -0700381 if (tableEntryMsg.getMatchCount() == 0) {
382 return PiMatchKey.EMPTY;
383 } else {
384 return decodeFieldMatchMsgs(tableEntryMsg.getMatchList(), tableInfo, browser);
385 }
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200386 }
387
Carmelo Casconee44592f2018-09-12 02:24:47 -0700388 private static PiMatchKey decodeFieldMatchMsgs(List<FieldMatch> fieldMatchs, P4InfoOuterClass.Table tableInfo,
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200389 P4InfoBrowser browser)
390 throws P4InfoBrowser.NotFoundException, EncodeException {
391 // Match key for field matches.
392 PiMatchKey.Builder piMatchKeyBuilder = PiMatchKey.builder();
393 for (FieldMatch fieldMatchMsg : fieldMatchs) {
394 piMatchKeyBuilder.addFieldMatch(decodeFieldMatchMsg(fieldMatchMsg, tableInfo, browser));
395 }
396 return piMatchKeyBuilder.build();
397 }
398
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400399 private static PiFieldMatch decodeFieldMatchMsg(FieldMatch fieldMatchMsg, P4InfoOuterClass.Table tableInfo,
400 P4InfoBrowser browser)
401 throws P4InfoBrowser.NotFoundException, EncodeException {
402
403 int tableId = tableInfo.getPreamble().getId();
404 String fieldMatchName = browser.matchFields(tableId).getById(fieldMatchMsg.getFieldId()).getName();
Carmelo Cascone87892e22017-11-13 16:01:29 -0800405 PiMatchFieldId headerFieldId = PiMatchFieldId.of(fieldMatchName);
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400406
407 FieldMatch.FieldMatchTypeCase typeCase = fieldMatchMsg.getFieldMatchTypeCase();
408
409 switch (typeCase) {
410 case EXACT:
411 FieldMatch.Exact exactFieldMatch = fieldMatchMsg.getExact();
412 ImmutableByteSequence exactValue = copyFrom(exactFieldMatch.getValue().asReadOnlyByteBuffer());
413 return new PiExactFieldMatch(headerFieldId, exactValue);
414 case TERNARY:
415 FieldMatch.Ternary ternaryFieldMatch = fieldMatchMsg.getTernary();
416 ImmutableByteSequence ternaryValue = copyFrom(ternaryFieldMatch.getValue().asReadOnlyByteBuffer());
417 ImmutableByteSequence ternaryMask = copyFrom(ternaryFieldMatch.getMask().asReadOnlyByteBuffer());
418 return new PiTernaryFieldMatch(headerFieldId, ternaryValue, ternaryMask);
419 case LPM:
420 FieldMatch.LPM lpmFieldMatch = fieldMatchMsg.getLpm();
421 ImmutableByteSequence lpmValue = copyFrom(lpmFieldMatch.getValue().asReadOnlyByteBuffer());
422 int lpmPrefixLen = lpmFieldMatch.getPrefixLen();
423 return new PiLpmFieldMatch(headerFieldId, lpmValue, lpmPrefixLen);
424 case RANGE:
425 FieldMatch.Range rangeFieldMatch = fieldMatchMsg.getRange();
426 ImmutableByteSequence rangeHighValue = copyFrom(rangeFieldMatch.getHigh().asReadOnlyByteBuffer());
427 ImmutableByteSequence rangeLowValue = copyFrom(rangeFieldMatch.getLow().asReadOnlyByteBuffer());
428 return new PiRangeFieldMatch(headerFieldId, rangeLowValue, rangeHighValue);
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400429 default:
430 throw new EncodeException(format(
431 "Decoding of field match type '%s' not implemented", typeCase.name()));
432 }
433 }
434
Yi Tseng82512da2017-08-16 19:46:36 -0700435 static TableAction encodePiTableAction(PiTableAction piTableAction, P4InfoBrowser browser)
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400436 throws P4InfoBrowser.NotFoundException, EncodeException {
Yi Tsengd28936e2018-02-23 22:11:11 +0100437 checkNotNull(piTableAction, "Cannot encode null PiTableAction");
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400438 TableAction.Builder tableActionMsgBuilder = TableAction.newBuilder();
439
440 switch (piTableAction.type()) {
441 case ACTION:
442 PiAction piAction = (PiAction) piTableAction;
Yi Tseng82512da2017-08-16 19:46:36 -0700443 Action theAction = encodePiAction(piAction, browser);
444 tableActionMsgBuilder.setAction(theAction);
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400445 break;
Yi Tseng82512da2017-08-16 19:46:36 -0700446 case ACTION_GROUP_ID:
447 PiActionGroupId actionGroupId = (PiActionGroupId) piTableAction;
448 tableActionMsgBuilder.setActionProfileGroupId(actionGroupId.id());
449 break;
450 case GROUP_MEMBER_ID:
451 PiActionGroupMemberId actionGroupMemberId = (PiActionGroupMemberId) piTableAction;
452 tableActionMsgBuilder.setActionProfileMemberId(actionGroupMemberId.id());
453 break;
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400454 default:
455 throw new EncodeException(
456 format("Building of table action type %s not implemented", piTableAction.type()));
457 }
458
459 return tableActionMsgBuilder.build();
460 }
461
Yi Tseng82512da2017-08-16 19:46:36 -0700462 static PiTableAction decodeTableActionMsg(TableAction tableActionMsg, P4InfoBrowser browser)
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400463 throws P4InfoBrowser.NotFoundException, EncodeException {
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400464 TableAction.TypeCase typeCase = tableActionMsg.getTypeCase();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400465 switch (typeCase) {
466 case ACTION:
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400467 Action actionMsg = tableActionMsg.getAction();
Yi Tseng82512da2017-08-16 19:46:36 -0700468 return decodeActionMsg(actionMsg, browser);
Yi Tseng95390822018-01-22 17:57:22 -0800469 case ACTION_PROFILE_GROUP_ID:
470 return PiActionGroupId.of(tableActionMsg.getActionProfileGroupId());
471 case ACTION_PROFILE_MEMBER_ID:
472 return PiActionGroupMemberId.of(tableActionMsg.getActionProfileMemberId());
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400473 default:
474 throw new EncodeException(
475 format("Decoding of table action type %s not implemented", typeCase.name()));
476 }
477 }
478
Yi Tseng82512da2017-08-16 19:46:36 -0700479 static Action encodePiAction(PiAction piAction, P4InfoBrowser browser)
480 throws P4InfoBrowser.NotFoundException, EncodeException {
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400481
Carmelo Cascone87892e22017-11-13 16:01:29 -0800482 int actionId = browser.actions().getByName(piAction.id().toString()).getPreamble().getId();
Yi Tseng82512da2017-08-16 19:46:36 -0700483
484 Action.Builder actionMsgBuilder =
485 Action.newBuilder().setActionId(actionId);
486
487 for (PiActionParam p : piAction.parameters()) {
Carmelo Cascone87892e22017-11-13 16:01:29 -0800488 P4InfoOuterClass.Action.Param paramInfo = browser.actionParams(actionId).getByName(p.id().toString());
Yi Tseng82512da2017-08-16 19:46:36 -0700489 ByteString paramValue = ByteString.copyFrom(p.value().asReadOnlyBuffer());
490 assertSize(format("param '%s' of action '%s'", p.id(), piAction.id()),
491 paramValue, paramInfo.getBitwidth());
492 actionMsgBuilder.addParams(Action.Param.newBuilder()
493 .setParamId(paramInfo.getId())
494 .setValue(paramValue)
495 .build());
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400496 }
Yi Tseng82512da2017-08-16 19:46:36 -0700497
498 return actionMsgBuilder.build();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400499 }
500
Yi Tseng82512da2017-08-16 19:46:36 -0700501 static PiAction decodeActionMsg(Action action, P4InfoBrowser browser)
502 throws P4InfoBrowser.NotFoundException {
503 P4InfoBrowser.EntityBrowser<P4InfoOuterClass.Action.Param> paramInfo =
504 browser.actionParams(action.getActionId());
505 String actionName = browser.actions()
506 .getById(action.getActionId())
507 .getPreamble().getName();
508 PiActionId id = PiActionId.of(actionName);
509 List<PiActionParam> params = Lists.newArrayList();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400510
Yi Tseng82512da2017-08-16 19:46:36 -0700511 for (Action.Param p : action.getParamsList()) {
512 String paramName = paramInfo.getById(p.getParamId()).getName();
513 ImmutableByteSequence value = ImmutableByteSequence.copyFrom(p.getValue().toByteArray());
514 params.add(new PiActionParam(PiActionParamId.of(paramName), value));
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400515 }
Yi Tseng82512da2017-08-16 19:46:36 -0700516 return PiAction.builder().withId(id).withParameters(params).build();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400517 }
steven308017632e152018-10-20 00:51:08 +0800518
519 static CounterData encodeCounter(PiCounterCellData piCounterCellData) {
520 return CounterData.newBuilder().setPacketCount(piCounterCellData.packets())
521 .setByteCount(piCounterCellData.bytes()).build();
522 }
523
524 static PiCounterCellData decodeCounter(CounterData counterData) {
525 return new PiCounterCellData(counterData.getPacketCount(), counterData.getByteCount());
526 }
527}