blob: 609d2d2f5cd67daa24078f3a12bdbda0061db0a2 [file] [log] [blame]
Carmelo Cascone98dfdb72017-07-14 12:01:37 -04001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Carmelo Cascone98dfdb72017-07-14 12:01:37 -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
19
20import com.google.common.collect.Maps;
21import com.google.protobuf.Message;
22import p4.config.P4InfoOuterClass.Action;
23import p4.config.P4InfoOuterClass.ActionProfile;
24import p4.config.P4InfoOuterClass.ControllerPacketMetadata;
25import p4.config.P4InfoOuterClass.Counter;
26import p4.config.P4InfoOuterClass.DirectCounter;
27import p4.config.P4InfoOuterClass.DirectMeter;
28import p4.config.P4InfoOuterClass.MatchField;
29import p4.config.P4InfoOuterClass.Meter;
30import p4.config.P4InfoOuterClass.P4Info;
31import p4.config.P4InfoOuterClass.Preamble;
32import p4.config.P4InfoOuterClass.Table;
33
34import java.util.Map;
35
Carmelo Cascone8d99b172017-07-18 17:26:31 -040036import static com.google.common.base.Preconditions.checkArgument;
37import static com.google.common.base.Preconditions.checkNotNull;
Carmelo Cascone98dfdb72017-07-14 12:01:37 -040038import static java.lang.String.format;
39
40/**
41 * Utility class to easily retrieve information from a P4Info protobuf message.
42 */
43final class P4InfoBrowser {
44
45 private final EntityBrowser<Table> tables = new EntityBrowser<>("table");
46 private final EntityBrowser<Action> actions = new EntityBrowser<>("action");
47 private final EntityBrowser<ActionProfile> actionProfiles = new EntityBrowser<>("action profile");
48 private final EntityBrowser<Counter> counters = new EntityBrowser<>("counter");
49 private final EntityBrowser<DirectCounter> directCounters = new EntityBrowser<>("direct counter");
50 private final EntityBrowser<Meter> meters = new EntityBrowser<>("meter");
51 private final EntityBrowser<DirectMeter> directMeters = new EntityBrowser<>("direct meter");
52 private final EntityBrowser<ControllerPacketMetadata> ctrlPktMetadatas =
53 new EntityBrowser<>("controller packet metadata");
54 private final Map<Integer, EntityBrowser<Action.Param>> actionParams = Maps.newHashMap();
55 private final Map<Integer, EntityBrowser<MatchField>> matchFields = Maps.newHashMap();
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020056 private final Map<Integer, EntityBrowser<ControllerPacketMetadata.Metadata>> ctrlPktMetadatasMetadata =
57 Maps.newHashMap();
Carmelo Cascone98dfdb72017-07-14 12:01:37 -040058
59 /**
60 * Creates a new browser for the given P4Info.
61 *
62 * @param p4info P4Info protobuf message
63 */
64 P4InfoBrowser(P4Info p4info) {
65 parseP4Info(p4info);
66 }
67
68 private void parseP4Info(P4Info p4info) {
69 p4info.getTablesList().forEach(
70 entity -> {
71 tables.addWithPreamble(entity.getPreamble(), entity);
72 // Index match fields.
73 int tableId = entity.getPreamble().getId();
74 String tableName = entity.getPreamble().getName();
75 EntityBrowser<MatchField> matchFieldBrowser = new EntityBrowser<>(format(
76 "match field for table '%s'", tableName));
Carmelo Cascone8d99b172017-07-18 17:26:31 -040077 entity.getMatchFieldsList().forEach(m -> {
78 String alias = extractMatchFieldSimpleName(m.getName());
79 matchFieldBrowser.add(m.getName(), alias, m.getId(), m);
80 });
Carmelo Cascone98dfdb72017-07-14 12:01:37 -040081 matchFields.put(tableId, matchFieldBrowser);
82 });
83
84 p4info.getActionsList().forEach(
85 entity -> {
86 actions.addWithPreamble(entity.getPreamble(), entity);
87 // Index action params.
88 int actionId = entity.getPreamble().getId();
89 String actionName = entity.getPreamble().getName();
90 EntityBrowser<Action.Param> paramBrowser = new EntityBrowser<>(format(
91 "param for action '%s'", actionName));
Carmelo Cascone8d99b172017-07-18 17:26:31 -040092 entity.getParamsList().forEach(p -> paramBrowser.add(p.getName(), null, p.getId(), p));
Carmelo Cascone98dfdb72017-07-14 12:01:37 -040093 actionParams.put(actionId, paramBrowser);
94 });
95
96 p4info.getActionProfilesList().forEach(
97 entity -> actionProfiles.addWithPreamble(entity.getPreamble(), entity));
98
99 p4info.getCountersList().forEach(
100 entity -> counters.addWithPreamble(entity.getPreamble(), entity));
101
102 p4info.getDirectCountersList().forEach(
103 entity -> directCounters.addWithPreamble(entity.getPreamble(), entity));
104
105 p4info.getMetersList().forEach(
106 entity -> meters.addWithPreamble(entity.getPreamble(), entity));
107
108 p4info.getDirectMetersList().forEach(
109 entity -> directMeters.addWithPreamble(entity.getPreamble(), entity));
110
111 p4info.getControllerPacketMetadataList().forEach(
Andrea Campanellafc1d34c2017-07-18 17:01:41 +0200112 entity -> {
113 ctrlPktMetadatas.addWithPreamble(entity.getPreamble(), entity);
114 // Index control packet metadata metadata.
115 int ctrlPktMetadataId = entity.getPreamble().getId();
116 String ctrlPktMetadataName = entity.getPreamble().getName();
117 EntityBrowser<ControllerPacketMetadata.Metadata> metadataBrowser = new EntityBrowser<>(format(
118 "metadata field for controller packet metadata '%s'", ctrlPktMetadataName));
119 entity.getMetadataList().forEach(m -> metadataBrowser.add(m.getName(), null, m.getId(), m));
120 ctrlPktMetadatasMetadata.put(ctrlPktMetadataId, metadataBrowser);
121 });
Carmelo Cascone98dfdb72017-07-14 12:01:37 -0400122 }
123
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400124 private String extractMatchFieldSimpleName(String name) {
125 // Removes the leading "hdr." or other scope identifier.
126 // E.g.: "hdr.ethernet.etherType" becomes "ethernet.etherType"
127 String[] pieces = name.split("\\.");
128 if (pieces.length == 3) {
129 return pieces[1] + "." + pieces[2];
130 } else if (pieces.length == 2) {
131 return name;
132 } else {
133 throw new UnsupportedOperationException("Invalid match field name: " + name);
134 }
135 }
136
Carmelo Cascone98dfdb72017-07-14 12:01:37 -0400137 /**
138 * Returns a browser for tables.
139 *
140 * @return table browser
141 */
142 EntityBrowser<Table> tables() {
143 return tables;
144 }
145
146 /**
147 * Returns a browser for actions.
148 *
149 * @return action browser
150 */
151 EntityBrowser<Action> actions() {
152 return actions;
153 }
154
155 /**
156 * Returns a browser for action profiles.
157 *
158 * @return action profile browser
159 */
160 EntityBrowser<ActionProfile> actionProfiles() {
161 return actionProfiles;
162 }
163
164 /**
165 * Returns a browser for counters.
166 *
167 * @return counter browser
168 */
169 EntityBrowser<Counter> counters() {
170 return counters;
171 }
172
173 /**
174 * Returns a browser for direct counters.
175 *
176 * @return direct counter browser
177 */
178 EntityBrowser<DirectCounter> directCounters() {
179 return directCounters;
180 }
181
182 /**
183 * Returns a browser for meters.
184 *
185 * @return meter browser
186 */
187 EntityBrowser<Meter> meters() {
188 return meters;
189 }
190
191 /**
192 * Returns a browser for direct meters.
193 *
194 * @return table browser
195 */
196 EntityBrowser<DirectMeter> directMeters() {
197 return directMeters;
198 }
199
200 /**
201 * Returns a browser for controller packet metadata.
202 *
203 * @return controller packet metadata browser
204 */
205 EntityBrowser<ControllerPacketMetadata> controllerPacketMetadatas() {
206 return ctrlPktMetadatas;
207 }
208
209 /**
210 * Returns a browser for params of the given action.
211 *
212 * @param actionId action identifier
213 * @return action params browser
214 * @throws NotFoundException if the action cannot be found
215 */
216 EntityBrowser<Action.Param> actionParams(int actionId) throws NotFoundException {
217 // Throws exception if action id is not found.
218 actions.getById(actionId);
219 return actionParams.get(actionId);
220 }
221
222 /**
223 * Returns a browser for match fields of the given table.
224 *
225 * @param tableId table identifier
Andrea Campanellafc1d34c2017-07-18 17:01:41 +0200226 * @return match field browser
Carmelo Cascone98dfdb72017-07-14 12:01:37 -0400227 * @throws NotFoundException if the table cannot be found
228 */
229 EntityBrowser<MatchField> matchFields(int tableId) throws NotFoundException {
230 // Throws exception if action id is not found.
231 tables.getById(tableId);
232 return matchFields.get(tableId);
233 }
234
235 /**
Andrea Campanellafc1d34c2017-07-18 17:01:41 +0200236 * Returns a browser for metadata fields of the controller packet metadata.
237 *
238 * @param controllerPacketMetadataId controller packet metadata identifier
239 * @return metadata browser
Frank Wang3a98e0a2017-08-11 11:09:30 +0800240 * @throws NotFoundException controller packet metadata cannot be found
Andrea Campanellafc1d34c2017-07-18 17:01:41 +0200241 */
242 EntityBrowser<ControllerPacketMetadata.Metadata> packetMetadatas(int controllerPacketMetadataId)
243 throws NotFoundException {
244 // Throws exception if controller packet metadata id is not found.
245 ctrlPktMetadatas.getById(controllerPacketMetadataId);
246 return ctrlPktMetadatasMetadata.get(controllerPacketMetadataId);
247 }
248
249 /**
Carmelo Cascone98dfdb72017-07-14 12:01:37 -0400250 * Browser of P4Info entities.
251 *
252 * @param <T> protobuf message type
253 */
254 static final class EntityBrowser<T extends Message> {
255
256 private String entityName;
257 private final Map<String, T> names = Maps.newHashMap();
258 private final Map<String, T> aliases = Maps.newHashMap();
259 private final Map<Integer, T> ids = Maps.newHashMap();
260
261 private EntityBrowser(String entityName) {
262 this.entityName = entityName;
263 }
264
265 /**
Carmelo Cascone04d09392017-07-19 08:49:08 -0400266 * Adds the given entity identified by the given name, alias (nullable) and id.
Carmelo Cascone98dfdb72017-07-14 12:01:37 -0400267 *
268 * @param name entity name
Carmelo Cascone04d09392017-07-19 08:49:08 -0400269 * @param alias entity alias or null
Carmelo Cascone98dfdb72017-07-14 12:01:37 -0400270 * @param id entity id
271 * @param entity entity message
272 */
Carmelo Cascone04d09392017-07-19 08:49:08 -0400273 void add(String name, String alias, int id, T entity) {
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400274 checkNotNull(name);
275 checkArgument(!name.isEmpty(), "Name cannot be empty");
276 checkNotNull(entity);
Carmelo Cascone98dfdb72017-07-14 12:01:37 -0400277 names.put(name, entity);
278 ids.put(id, entity);
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400279 if (alias != null && !alias.isEmpty()) {
280 aliases.put(alias, entity);
281 }
Carmelo Cascone98dfdb72017-07-14 12:01:37 -0400282 }
283
284 /**
285 * Adds the given entity identified by the given P4Info preamble.
286 *
287 * @param preamble P4Info preamble protobuf message
288 * @param entity entity message
289 */
290 void addWithPreamble(Preamble preamble, T entity) {
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400291 checkNotNull(preamble);
292 add(preamble.getName(), preamble.getAlias(), preamble.getId(), entity);
Carmelo Cascone98dfdb72017-07-14 12:01:37 -0400293 }
294
295 /**
296 * Returns true if the P4Info defines an entity with such name, false otherwise.
297 *
298 * @param name entity name
299 * @return boolean
300 */
301 boolean hasName(String name) {
302 return names.containsKey(name);
303 }
304
305 /**
306 * Returns the entity identified by the given name, if present, otherwise, throws an exception.
307 *
308 * @param name entity name
309 * @return entity message
310 * @throws NotFoundException if the entity cannot be found
311 */
312 T getByName(String name) throws NotFoundException {
313 if (!hasName(name)) {
314 throw new NotFoundException(entityName, name);
315 }
316 return names.get(name);
317 }
318
319 /**
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400320 * Returns the entity identified by the given name or alias, if present, otherwise, throws an exception.
321 *
322 * @param name entity name or alias
323 * @return entity message
324 * @throws NotFoundException if the entity cannot be found
325 */
326 T getByNameOrAlias(String name) throws NotFoundException {
327 if (hasName(name)) {
328 return names.get(name);
329 } else if (hasAlias(name)) {
330 return aliases.get(name);
331 } else {
332 throw new NotFoundException(entityName, name);
333 }
334 }
335
336 /**
Carmelo Cascone98dfdb72017-07-14 12:01:37 -0400337 * Returns true if the P4Info defines an entity with such alias, false otherwise.
338 *
339 * @param alias entity alias
340 * @return boolean
341 */
342 boolean hasAlias(String alias) {
343 return aliases.containsKey(alias);
344 }
345
346 /**
347 * Returns the entity identified by the given alias, if present, otherwise, throws an exception.
348 *
349 * @param alias entity alias
350 * @return entity message
351 * @throws NotFoundException if the entity cannot be found
352 */
353 T getByAlias(String alias) throws NotFoundException {
354 if (!hasName(alias)) {
355 throw new NotFoundException(entityName, alias);
356 }
357 return aliases.get(alias);
358 }
359
360 /**
361 * Returns true if the P4Info defines an entity with such id, false otherwise.
362 *
363 * @param id entity id
364 * @return boolean
365 */
366 boolean hasId(int id) {
367 return ids.containsKey(id);
368 }
369
370 /**
371 * Returns the entity identified by the given id, if present, otherwise, throws an exception.
372 *
373 * @param id entity id
374 * @return entity message
375 * @throws NotFoundException if the entity cannot be found
376 */
377 T getById(int id) throws NotFoundException {
378 if (!hasId(id)) {
379 throw new NotFoundException(entityName, id);
380 }
381 return ids.get(id);
382 }
383 }
384
385 /**
386 * Signals tha an entity cannot be found in the P4Info.
387 */
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400388 public static final class NotFoundException extends Exception {
Carmelo Cascone98dfdb72017-07-14 12:01:37 -0400389
390 NotFoundException(String entityName, String key) {
391 super(format("No such %s in P4Info with name/alias '%s'", entityName, key));
392 }
393
394 NotFoundException(String entityName, int id) {
395 super(format("No such %s in P4Info with id '%d'", entityName, id));
396 }
397 }
398}