blob: 357e41d5175f8795ab284a047f780ffec89d9aa5 [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;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040029import org.onosproject.net.pi.runtime.PiActionParam;
Carmelo Casconecb4327a2018-09-11 15:17:23 -070030import org.onosproject.net.pi.runtime.PiActionProfileGroupId;
31import org.onosproject.net.pi.runtime.PiActionProfileMemberId;
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
Carmelo Cascone8d99b172017-07-18 17:26:31 -040049import 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 Cascone99c59db2019-01-17 15:39:35 -080084 * @throws CodecException if a PI table entry cannot be encoded
Carmelo Cascone8d99b172017-07-18 17:26:31 -040085 */
Carmelo Casconee44592f2018-09-12 02:24:47 -070086 static List<TableEntry> encode(List<PiTableEntry> piTableEntries,
Carmelo Cascone5bc7e102018-02-18 18:27:55 -080087 PiPipeconf pipeconf)
Carmelo Cascone99c59db2019-01-17 15:39:35 -080088 throws CodecException {
Carmelo Cascone8d99b172017-07-18 17:26:31 -040089
90 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
91
92 if (browser == null) {
Carmelo Cascone99c59db2019-01-17 15:39:35 -080093 throw new CodecException(format(
Carmelo Cascone5bc7e102018-02-18 18:27:55 -080094 "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) {
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800103 throw new CodecException(e.getMessage());
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400104 }
105 }
106
107 return tableEntryMsgListBuilder.build();
108 }
109
110 /**
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700111 * Same as {@link #encode(List, PiPipeconf)} but encodes only one entry.
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200112 *
113 * @param piTableEntry table entry
114 * @param pipeconf pipeconf
115 * @return encoded table entry message
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800116 * @throws CodecException if entry cannot be encoded
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200117 * @throws P4InfoBrowser.NotFoundException if the required information cannot be find in the pipeconf's P4info
118 */
119 static TableEntry encode(PiTableEntry piTableEntry, PiPipeconf pipeconf)
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800120 throws CodecException, P4InfoBrowser.NotFoundException {
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200121
122 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
123 if (browser == null) {
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800124 throw new CodecException(format("Unable to get a P4Info browser for pipeconf %s", pipeconf.id()));
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200125 }
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 */
Carmelo Casconee44592f2018-09-12 02:24:47 -0700141 static List<PiTableEntry> decode(List<TableEntry> tableEntryMsgs, PiPipeconf pipeconf) {
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400142
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));
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800155 } catch (P4InfoBrowser.NotFoundException | CodecException e) {
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400156 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 /**
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700164 * Same as {@link #decode(List, PiPipeconf)} but decodes only one entry.
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200165 *
166 * @param tableEntryMsg table entry message
167 * @param pipeconf pipeconf
168 * @return decoded PI table entry
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800169 * @throws CodecException if message cannot be decoded
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200170 * @throws P4InfoBrowser.NotFoundException if the required information cannot be find in the pipeconf's P4info
171 */
172 static PiTableEntry decode(TableEntry tableEntryMsg, PiPipeconf pipeconf)
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800173 throws CodecException, P4InfoBrowser.NotFoundException {
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200174
175 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
176 if (browser == null) {
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800177 throw new CodecException(format("Unable to get a P4Info browser for pipeconf %s", pipeconf.id()));
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200178 }
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
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800191 * @throws CodecException if message cannot be encoded
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200192 * @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)
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800195 throws CodecException, P4InfoBrowser.NotFoundException {
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200196
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)
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800218 throws P4InfoBrowser.NotFoundException, CodecException {
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400219
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
steven308017632e152018-10-20 00:51:08 +0800253 // Counter.
254 if (piTableEntry.counter() != null) {
255 tableEntryMsgBuilder.setCounterData(encodeCounter(piTableEntry.counter()));
256 }
257
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400258 return tableEntryMsgBuilder.build();
259 }
260
261 private static PiTableEntry decodeTableEntryMsg(TableEntry tableEntryMsg, P4InfoBrowser browser)
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800262 throws P4InfoBrowser.NotFoundException, CodecException {
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400263
264 PiTableEntry.Builder piTableEntryBuilder = PiTableEntry.builder();
265
266 P4InfoOuterClass.Table tableInfo = browser.tables().getById(tableEntryMsg.getTableId());
267
268 // Table id.
269 piTableEntryBuilder.forTable(PiTableId.of(tableInfo.getPreamble().getName()));
270
271 // Priority.
Carmelo Cascone50d195f2018-09-11 13:26:38 -0700272 if (tableEntryMsg.getPriority() > 0) {
273 piTableEntryBuilder.withPriority(tableEntryMsg.getPriority());
274 }
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400275
276 // Controller metadata (cookie)
277 piTableEntryBuilder.withCookie(tableEntryMsg.getControllerMetadata());
278
279 // Table action.
Yi Tsengd28936e2018-02-23 22:11:11 +0100280 if (tableEntryMsg.hasAction()) {
281 piTableEntryBuilder.withAction(decodeTableActionMsg(tableEntryMsg.getAction(), browser));
282 }
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400283
284 // Timeout.
285 // FIXME: how to decode table entry messages with timeout, given that the timeout value is lost after encoding?
286
Carmelo Cascone0e896a02017-07-31 07:22:27 +0200287 // Match key for field matches.
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200288 piTableEntryBuilder.withMatchKey(decodeFieldMatchMsgs(tableEntryMsg.getMatchList(), tableInfo, browser));
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400289
steven308017632e152018-10-20 00:51:08 +0800290 // Counter.
291 piTableEntryBuilder.withCounterCellData(decodeCounter(tableEntryMsg.getCounterData()));
292
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400293 return piTableEntryBuilder.build();
294 }
295
296 private static FieldMatch encodePiFieldMatch(PiFieldMatch piFieldMatch, P4InfoOuterClass.Table tableInfo,
297 P4InfoBrowser browser)
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800298 throws P4InfoBrowser.NotFoundException, CodecException {
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400299
300 FieldMatch.Builder fieldMatchMsgBuilder = FieldMatch.newBuilder();
301
302 // FIXME: check how field names for stacked headers are constructed in P4Runtime.
303 String fieldName = piFieldMatch.fieldId().id();
304 int tableId = tableInfo.getPreamble().getId();
Carmelo Casconecb0a49c2017-10-03 14:32:23 +0200305 P4InfoOuterClass.MatchField matchFieldInfo = browser.matchFields(tableId).getByName(fieldName);
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400306 String entityName = format("field match '%s' of table '%s'",
307 matchFieldInfo.getName(), tableInfo.getPreamble().getName());
308 int fieldId = matchFieldInfo.getId();
309 int fieldBitwidth = matchFieldInfo.getBitwidth();
310
311 fieldMatchMsgBuilder.setFieldId(fieldId);
312
313 switch (piFieldMatch.type()) {
314 case EXACT:
315 PiExactFieldMatch fieldMatch = (PiExactFieldMatch) piFieldMatch;
316 ByteString exactValue = ByteString.copyFrom(fieldMatch.value().asReadOnlyBuffer());
317 assertSize(VALUE_OF_PREFIX + entityName, exactValue, fieldBitwidth);
318 return fieldMatchMsgBuilder.setExact(
319 FieldMatch.Exact
320 .newBuilder()
321 .setValue(exactValue)
322 .build())
323 .build();
324 case TERNARY:
325 PiTernaryFieldMatch ternaryMatch = (PiTernaryFieldMatch) piFieldMatch;
326 ByteString ternaryValue = ByteString.copyFrom(ternaryMatch.value().asReadOnlyBuffer());
327 ByteString ternaryMask = ByteString.copyFrom(ternaryMatch.mask().asReadOnlyBuffer());
328 assertSize(VALUE_OF_PREFIX + entityName, ternaryValue, fieldBitwidth);
329 assertSize(MASK_OF_PREFIX + entityName, ternaryMask, fieldBitwidth);
330 return fieldMatchMsgBuilder.setTernary(
331 FieldMatch.Ternary
332 .newBuilder()
333 .setValue(ternaryValue)
334 .setMask(ternaryMask)
335 .build())
336 .build();
337 case LPM:
338 PiLpmFieldMatch lpmMatch = (PiLpmFieldMatch) piFieldMatch;
339 ByteString lpmValue = ByteString.copyFrom(lpmMatch.value().asReadOnlyBuffer());
340 int lpmPrefixLen = lpmMatch.prefixLength();
341 assertSize(VALUE_OF_PREFIX + entityName, lpmValue, fieldBitwidth);
342 assertPrefixLen(entityName, lpmPrefixLen, fieldBitwidth);
343 return fieldMatchMsgBuilder.setLpm(
344 FieldMatch.LPM.newBuilder()
345 .setValue(lpmValue)
346 .setPrefixLen(lpmPrefixLen)
347 .build())
348 .build();
349 case RANGE:
350 PiRangeFieldMatch rangeMatch = (PiRangeFieldMatch) piFieldMatch;
351 ByteString rangeHighValue = ByteString.copyFrom(rangeMatch.highValue().asReadOnlyBuffer());
352 ByteString rangeLowValue = ByteString.copyFrom(rangeMatch.lowValue().asReadOnlyBuffer());
353 assertSize(HIGH_RANGE_VALUE_OF_PREFIX + entityName, rangeHighValue, fieldBitwidth);
354 assertSize(LOW_RANGE_VALUE_OF_PREFIX + entityName, rangeLowValue, fieldBitwidth);
355 return fieldMatchMsgBuilder.setRange(
356 FieldMatch.Range.newBuilder()
357 .setHigh(rangeHighValue)
358 .setLow(rangeLowValue)
359 .build())
360 .build();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400361 default:
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800362 throw new CodecException(format(
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400363 "Building of match type %s not implemented", piFieldMatch.type()));
364 }
365 }
366
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200367 /**
368 * Returns a PI match key, decoded from the given table entry protobuf message, for the given pipeconf.
369 *
370 * @param tableEntryMsg table entry message
371 * @param pipeconf pipeconf
372 * @return PI match key
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800373 * @throws CodecException if message cannot be decoded
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200374 * @throws P4InfoBrowser.NotFoundException if the required information cannot be find in the pipeconf's P4info
375 */
376 static PiMatchKey decodeMatchKey(TableEntry tableEntryMsg, PiPipeconf pipeconf)
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800377 throws P4InfoBrowser.NotFoundException, CodecException {
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200378 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
379 P4InfoOuterClass.Table tableInfo = browser.tables().getById(tableEntryMsg.getTableId());
Carmelo Cascone4256bde2018-03-23 18:02:15 -0700380 if (tableEntryMsg.getMatchCount() == 0) {
381 return PiMatchKey.EMPTY;
382 } else {
383 return decodeFieldMatchMsgs(tableEntryMsg.getMatchList(), tableInfo, browser);
384 }
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200385 }
386
Carmelo Casconee44592f2018-09-12 02:24:47 -0700387 private static PiMatchKey decodeFieldMatchMsgs(List<FieldMatch> fieldMatchs, P4InfoOuterClass.Table tableInfo,
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200388 P4InfoBrowser browser)
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800389 throws P4InfoBrowser.NotFoundException, CodecException {
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200390 // Match key for field matches.
391 PiMatchKey.Builder piMatchKeyBuilder = PiMatchKey.builder();
392 for (FieldMatch fieldMatchMsg : fieldMatchs) {
393 piMatchKeyBuilder.addFieldMatch(decodeFieldMatchMsg(fieldMatchMsg, tableInfo, browser));
394 }
395 return piMatchKeyBuilder.build();
396 }
397
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400398 private static PiFieldMatch decodeFieldMatchMsg(FieldMatch fieldMatchMsg, P4InfoOuterClass.Table tableInfo,
399 P4InfoBrowser browser)
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800400 throws P4InfoBrowser.NotFoundException, CodecException {
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400401
402 int tableId = tableInfo.getPreamble().getId();
403 String fieldMatchName = browser.matchFields(tableId).getById(fieldMatchMsg.getFieldId()).getName();
Carmelo Cascone87892e22017-11-13 16:01:29 -0800404 PiMatchFieldId headerFieldId = PiMatchFieldId.of(fieldMatchName);
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400405
406 FieldMatch.FieldMatchTypeCase typeCase = fieldMatchMsg.getFieldMatchTypeCase();
407
408 switch (typeCase) {
409 case EXACT:
410 FieldMatch.Exact exactFieldMatch = fieldMatchMsg.getExact();
411 ImmutableByteSequence exactValue = copyFrom(exactFieldMatch.getValue().asReadOnlyByteBuffer());
412 return new PiExactFieldMatch(headerFieldId, exactValue);
413 case TERNARY:
414 FieldMatch.Ternary ternaryFieldMatch = fieldMatchMsg.getTernary();
415 ImmutableByteSequence ternaryValue = copyFrom(ternaryFieldMatch.getValue().asReadOnlyByteBuffer());
416 ImmutableByteSequence ternaryMask = copyFrom(ternaryFieldMatch.getMask().asReadOnlyByteBuffer());
417 return new PiTernaryFieldMatch(headerFieldId, ternaryValue, ternaryMask);
418 case LPM:
419 FieldMatch.LPM lpmFieldMatch = fieldMatchMsg.getLpm();
420 ImmutableByteSequence lpmValue = copyFrom(lpmFieldMatch.getValue().asReadOnlyByteBuffer());
421 int lpmPrefixLen = lpmFieldMatch.getPrefixLen();
422 return new PiLpmFieldMatch(headerFieldId, lpmValue, lpmPrefixLen);
423 case RANGE:
424 FieldMatch.Range rangeFieldMatch = fieldMatchMsg.getRange();
425 ImmutableByteSequence rangeHighValue = copyFrom(rangeFieldMatch.getHigh().asReadOnlyByteBuffer());
426 ImmutableByteSequence rangeLowValue = copyFrom(rangeFieldMatch.getLow().asReadOnlyByteBuffer());
427 return new PiRangeFieldMatch(headerFieldId, rangeLowValue, rangeHighValue);
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400428 default:
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800429 throw new CodecException(format(
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400430 "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 Cascone99c59db2019-01-17 15:39:35 -0800435 throws P4InfoBrowser.NotFoundException, CodecException {
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;
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700445 case ACTION_PROFILE_GROUP_ID:
446 PiActionProfileGroupId actionGroupId = (PiActionProfileGroupId) piTableAction;
Yi Tseng82512da2017-08-16 19:46:36 -0700447 tableActionMsgBuilder.setActionProfileGroupId(actionGroupId.id());
448 break;
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700449 case ACTION_PROFILE_MEMBER_ID:
450 PiActionProfileMemberId actionProfileMemberId = (PiActionProfileMemberId) piTableAction;
451 tableActionMsgBuilder.setActionProfileMemberId(actionProfileMemberId.id());
Yi Tseng82512da2017-08-16 19:46:36 -0700452 break;
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400453 default:
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800454 throw new CodecException(
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400455 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 Cascone99c59db2019-01-17 15:39:35 -0800462 throws P4InfoBrowser.NotFoundException, CodecException {
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:
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700469 return PiActionProfileGroupId.of(tableActionMsg.getActionProfileGroupId());
Yi Tseng95390822018-01-22 17:57:22 -0800470 case ACTION_PROFILE_MEMBER_ID:
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700471 return PiActionProfileMemberId.of(tableActionMsg.getActionProfileMemberId());
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400472 default:
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800473 throw new CodecException(
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400474 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)
Carmelo Cascone99c59db2019-01-17 15:39:35 -0800479 throws P4InfoBrowser.NotFoundException, CodecException {
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 }
steven308017632e152018-10-20 00:51:08 +0800517
518 static CounterData encodeCounter(PiCounterCellData piCounterCellData) {
519 return CounterData.newBuilder().setPacketCount(piCounterCellData.packets())
520 .setByteCount(piCounterCellData.bytes()).build();
521 }
522
523 static PiCounterCellData decodeCounter(CounterData counterData) {
524 return new PiCounterCellData(counterData.getPacketCount(), counterData.getByteCount());
525 }
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700526}