blob: 17bff76c4dc4fb29f4b31823320d69958b200e11 [file] [log] [blame]
Carmelo Cascone7f75be42017-09-07 14:37:02 +02001/*
2 * Copyright 2017-present Open Networking Foundation
3 *
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
Carmelo Cascone87892e22017-11-13 16:01:29 -080019import org.onosproject.net.pi.model.PiCounterId;
20import org.onosproject.net.pi.model.PiCounterType;
Carmelo Cascone7f75be42017-09-07 14:37:02 +020021import org.onosproject.net.pi.model.PiPipeconf;
Carmelo Cascone81929aa2018-04-07 01:38:55 -070022import org.onosproject.net.pi.model.PiTableId;
Carmelo Cascone7f75be42017-09-07 14:37:02 +020023import org.onosproject.net.pi.runtime.PiCounterCellData;
24import org.onosproject.net.pi.runtime.PiCounterCellId;
Carmelo Cascone7f75be42017-09-07 14:37:02 +020025import org.onosproject.net.pi.runtime.PiTableEntry;
26import org.slf4j.Logger;
Carmelo Cascone81929aa2018-04-07 01:38:55 -070027import p4.P4RuntimeOuterClass;
Carmelo Cascone7f75be42017-09-07 14:37:02 +020028import p4.P4RuntimeOuterClass.CounterData;
29import p4.P4RuntimeOuterClass.CounterEntry;
30import p4.P4RuntimeOuterClass.DirectCounterEntry;
31import p4.P4RuntimeOuterClass.Entity;
32
33import java.util.Collection;
Carmelo Cascone81929aa2018-04-07 01:38:55 -070034import java.util.Collections;
Carmelo Cascone7f75be42017-09-07 14:37:02 +020035import java.util.Objects;
36import java.util.stream.Collectors;
37
38import static java.lang.String.format;
Carmelo Cascone81929aa2018-04-07 01:38:55 -070039import static org.onosproject.p4runtime.ctl.P4RuntimeUtils.indexMsg;
Carmelo Cascone7f75be42017-09-07 14:37:02 +020040import static org.slf4j.LoggerFactory.getLogger;
41import static p4.P4RuntimeOuterClass.Entity.EntityCase.COUNTER_ENTRY;
42import static p4.P4RuntimeOuterClass.Entity.EntityCase.DIRECT_COUNTER_ENTRY;
43
44/**
Carmelo Cascone81929aa2018-04-07 01:38:55 -070045 * Encoder/decoder of PI counter IDs to counter entry protobuf messages, and
46 * vice versa.
Carmelo Cascone7f75be42017-09-07 14:37:02 +020047 */
48final class CounterEntryCodec {
49
50 private static final Logger log = getLogger(CounterEntryCodec.class);
51
52 private CounterEntryCodec() {
53 // Hides constructor.
54 }
55
56 /**
Carmelo Cascone81929aa2018-04-07 01:38:55 -070057 * Returns a collection of P4Runtime entity protobuf messages describing
58 * both counter or direct counter entries, encoded from the given collection
59 * of PI counter cell identifiers, for the given pipeconf. If a PI counter
60 * cell identifier cannot be encoded, it is skipped, hence the returned
61 * collection might have different size than the input one.
Carmelo Cascone7f75be42017-09-07 14:37:02 +020062 *
Carmelo Cascone81929aa2018-04-07 01:38:55 -070063 * @param cellIds counter cell identifiers
64 * @param pipeconf pipeconf
65 * @return collection of entity messages describing both counter or direct
66 * counter entries
Carmelo Cascone7f75be42017-09-07 14:37:02 +020067 */
68 static Collection<Entity> encodePiCounterCellIds(Collection<PiCounterCellId> cellIds,
Carmelo Cascone7f75be42017-09-07 14:37:02 +020069 PiPipeconf pipeconf) {
Carmelo Cascone81929aa2018-04-07 01:38:55 -070070
71 final P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
72
73 if (browser == null) {
74 log.error("Unable to get a P4Info browser for pipeconf {}", pipeconf.id());
75 return Collections.emptyList();
76 }
77
Carmelo Cascone7f75be42017-09-07 14:37:02 +020078 return cellIds
79 .stream()
80 .map(cellId -> {
81 try {
Carmelo Cascone81929aa2018-04-07 01:38:55 -070082 return encodePiCounterCellId(cellId, pipeconf, browser);
Carmelo Cascone7f75be42017-09-07 14:37:02 +020083 } catch (P4InfoBrowser.NotFoundException | EncodeException e) {
84 log.warn("Unable to encode PI counter cell id: {}", e.getMessage());
85 return null;
86 }
87 })
88 .filter(Objects::nonNull)
89 .collect(Collectors.toList());
90 }
91
92 /**
Carmelo Cascone81929aa2018-04-07 01:38:55 -070093 * Returns a collection of P4Runtime entity protobuf messages to be used in
94 * requests to read all cells from the given counter identifiers. Works for
95 * both indirect or direct counters. If a PI counter identifier cannot be
96 * encoded, it is skipped, hence the returned collection might have
97 * different size than the input one.
Carmelo Cascone7f75be42017-09-07 14:37:02 +020098 *
Carmelo Cascone81929aa2018-04-07 01:38:55 -070099 * @param counterIds counter identifiers
100 * @param pipeconf pipeconf
101 * @return collection of entity messages
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200102 */
Carmelo Cascone81929aa2018-04-07 01:38:55 -0700103 static Collection<Entity> readAllCellsEntities(Collection<PiCounterId> counterIds,
104 PiPipeconf pipeconf) {
105 final P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
106
107 if (browser == null) {
108 log.error("Unable to get a P4Info browser for pipeconf {}", pipeconf.id());
109 return Collections.emptyList();
110 }
111
112 return counterIds
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200113 .stream()
Carmelo Cascone81929aa2018-04-07 01:38:55 -0700114 .map(counterId -> {
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200115 try {
Carmelo Cascone81929aa2018-04-07 01:38:55 -0700116 return readAllCellsEntity(counterId, pipeconf, browser);
117 } catch (P4InfoBrowser.NotFoundException | EncodeException e) {
118 log.warn("Unable to encode counter ID to read-all-cells entity: {}",
119 e.getMessage());
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200120 return null;
121 }
122 })
123 .filter(Objects::nonNull)
124 .collect(Collectors.toList());
125 }
126
Carmelo Cascone81929aa2018-04-07 01:38:55 -0700127 /**
128 * Returns a collection of PI counter cell data, decoded from the given
129 * P4Runtime entity protobuf messages describing both counter or direct
130 * counter entries, and pipeconf. If an entity message cannot be encoded, it
131 * is skipped, hence the returned collection might have different size than
132 * the input one.
133 *
134 * @param entities P4Runtime entity messages
135 * @param pipeconf pipeconf
136 * @return collection of PI counter cell data
137 */
138 static Collection<PiCounterCellData> decodeCounterEntities(Collection<Entity> entities,
139 PiPipeconf pipeconf) {
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200140
141 final P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
142
Carmelo Cascone81929aa2018-04-07 01:38:55 -0700143 if (browser == null) {
144 log.error("Unable to get a P4Info browser for pipeconf {}", pipeconf.id());
145 return Collections.emptyList();
146 }
147
148 return entities
149 .stream()
150 .filter(entity -> entity.getEntityCase() == COUNTER_ENTRY ||
151 entity.getEntityCase() == DIRECT_COUNTER_ENTRY)
152 .map(entity -> {
153 try {
154 return decodeCounterEntity(entity, pipeconf, browser);
155 } catch (EncodeException | P4InfoBrowser.NotFoundException e) {
156 log.warn("Unable to decode counter entity message: {}",
157 e.getMessage());
158 return null;
159 }
160 })
161 .filter(Objects::nonNull)
162 .collect(Collectors.toList());
163 }
164
165 private static Entity encodePiCounterCellId(PiCounterCellId cellId,
166 PiPipeconf pipeconf,
167 P4InfoBrowser browser)
168 throws P4InfoBrowser.NotFoundException, EncodeException {
169
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200170 int counterId;
171 Entity entity;
172 // Encode PI cell ID into entity message and add to read request.
Carmelo Cascone87892e22017-11-13 16:01:29 -0800173 switch (cellId.counterType()) {
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200174 case INDIRECT:
Carmelo Cascone81929aa2018-04-07 01:38:55 -0700175 counterId = browser.counters()
176 .getByName(cellId.counterId().id())
177 .getPreamble()
178 .getId();
179 entity = Entity.newBuilder()
180 .setCounterEntry(
181 CounterEntry.newBuilder()
182 .setCounterId(counterId)
183 .setIndex(indexMsg(cellId.index()))
184 .build())
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200185 .build();
186 break;
187 case DIRECT:
Carmelo Cascone81929aa2018-04-07 01:38:55 -0700188 DirectCounterEntry.Builder entryBuilder = DirectCounterEntry.newBuilder();
189 entryBuilder.setTableEntry(
190 TableEntryEncoder.encode(cellId.tableEntry(), pipeconf));
191 entity = Entity.newBuilder()
192 .setDirectCounterEntry(entryBuilder.build())
193 .build();
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200194 break;
195 default:
Carmelo Cascone81929aa2018-04-07 01:38:55 -0700196 throw new EncodeException(format(
197 "Unrecognized PI counter cell ID type '%s'",
198 cellId.counterType()));
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200199 }
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200200
201 return entity;
202 }
203
Carmelo Cascone81929aa2018-04-07 01:38:55 -0700204 private static Entity readAllCellsEntity(PiCounterId counterId,
205 PiPipeconf pipeconf,
206 P4InfoBrowser browser)
207 throws P4InfoBrowser.NotFoundException, EncodeException {
208
209 if (!pipeconf.pipelineModel().counter(counterId).isPresent()) {
210 throw new EncodeException(format(
211 "not such counter '%s' in pipeline model", counterId));
212 }
213 final PiCounterType counterType = pipeconf.pipelineModel()
214 .counter(counterId).get().counterType();
215
216 switch (counterType) {
217 case INDIRECT:
218 final int p4InfoCounterId = browser.counters()
219 .getByName(counterId.id())
220 .getPreamble().getId();
221 return Entity.newBuilder().setCounterEntry(
222 P4RuntimeOuterClass.CounterEntry.newBuilder()
223 // Index unset to read all cells
224 .setCounterId(p4InfoCounterId)
225 .build())
226 .build();
227 case DIRECT:
228 final PiTableId tableId = pipeconf.pipelineModel()
229 .counter(counterId).get().table();
230 if (tableId == null) {
231 throw new EncodeException(format(
232 "null table for direct counter '%s'", counterId));
233 }
234 final int p4TableId = browser.tables().getByName(tableId.id())
235 .getPreamble().getId();
236 return Entity.newBuilder().setDirectCounterEntry(
237 P4RuntimeOuterClass.DirectCounterEntry.newBuilder()
238 .setTableEntry(
239 // Match unset to read all cells
240 P4RuntimeOuterClass.TableEntry.newBuilder()
241 .setTableId(p4TableId)
242 .build())
243 .build())
244 .build();
245 default:
246 throw new EncodeException(format(
247 "unrecognized PI counter type '%s'", counterType));
248 }
249 }
250
251 private static PiCounterCellData decodeCounterEntity(Entity entity,
252 PiPipeconf pipeconf,
253 P4InfoBrowser browser)
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200254 throws EncodeException, P4InfoBrowser.NotFoundException {
255
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200256 CounterData counterData;
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200257 PiCounterCellId piCellId;
258
Carmelo Cascone81929aa2018-04-07 01:38:55 -0700259 if (entity.getEntityCase() == COUNTER_ENTRY) {
260 String counterName = browser.counters()
261 .getById(entity.getCounterEntry().getCounterId())
262 .getPreamble()
263 .getName();
264 piCellId = PiCounterCellId.ofIndirect(
265 PiCounterId.of(counterName),
266 entity.getCounterEntry().getIndex().getIndex());
267 counterData = entity.getCounterEntry().getData();
268 } else if (entity.getEntityCase() == DIRECT_COUNTER_ENTRY) {
269 PiTableEntry piTableEntry = TableEntryEncoder.decode(
270 entity.getDirectCounterEntry().getTableEntry(), pipeconf);
271 piCellId = PiCounterCellId.ofDirect(piTableEntry);
272 counterData = entity.getDirectCounterEntry().getData();
273 } else {
274 throw new EncodeException(format(
275 "Unrecognized entity type '%s' in P4Runtime message",
276 entity.getEntityCase().name()));
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200277 }
278
Carmelo Cascone81929aa2018-04-07 01:38:55 -0700279 return new PiCounterCellData(piCellId,
280 counterData.getPacketCount(),
281 counterData.getByteCount());
Carmelo Cascone7f75be42017-09-07 14:37:02 +0200282 }
283}