Bumped supported commit of P4Runtime and BMv2
Includes fixes for:
- ONOS-7593: Support for indirect resource Index type
- ONOS-7595: Removed ID from direct resources
- P4Runtime requires unset bits to be 0 in ternary field matches
- Incorrect parsing of flow rule byte counters
- Full entity names in P4Info with top-level control block (fixed only
for basic.p4, other programs need to be re-compiled and PI IDs in
respective pipeconf changed)
Change-Id: Ia19aa949c02e363a550e692915c6d6516a2d13d7
diff --git a/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeClient.java b/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeClient.java
index 91254cf..67f9fcf 100644
--- a/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeClient.java
+++ b/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeClient.java
@@ -17,18 +17,18 @@
package org.onosproject.p4runtime.api;
import com.google.common.annotations.Beta;
-import org.onosproject.net.pi.model.PiPipeconf;
-import org.onosproject.net.pi.runtime.PiActionGroup;
import org.onosproject.net.pi.model.PiActionProfileId;
+import org.onosproject.net.pi.model.PiCounterId;
+import org.onosproject.net.pi.model.PiMeterId;
+import org.onosproject.net.pi.model.PiPipeconf;
+import org.onosproject.net.pi.model.PiTableId;
+import org.onosproject.net.pi.runtime.PiActionGroup;
import org.onosproject.net.pi.runtime.PiCounterCellData;
import org.onosproject.net.pi.runtime.PiCounterCellId;
-import org.onosproject.net.pi.model.PiCounterId;
import org.onosproject.net.pi.runtime.PiMeterCellConfig;
import org.onosproject.net.pi.runtime.PiMeterCellId;
-import org.onosproject.net.pi.model.PiMeterId;
import org.onosproject.net.pi.runtime.PiPacketOperation;
import org.onosproject.net.pi.runtime.PiTableEntry;
-import org.onosproject.net.pi.model.PiTableId;
import java.nio.ByteBuffer;
import java.util.Collection;
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/CounterEntryCodec.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/CounterEntryCodec.java
index df4e72f..17bff76 100644
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/CounterEntryCodec.java
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/CounterEntryCodec.java
@@ -19,27 +19,31 @@
import org.onosproject.net.pi.model.PiCounterId;
import org.onosproject.net.pi.model.PiCounterType;
import org.onosproject.net.pi.model.PiPipeconf;
+import org.onosproject.net.pi.model.PiTableId;
import org.onosproject.net.pi.runtime.PiCounterCellData;
import org.onosproject.net.pi.runtime.PiCounterCellId;
import org.onosproject.net.pi.runtime.PiTableEntry;
import org.slf4j.Logger;
+import p4.P4RuntimeOuterClass;
import p4.P4RuntimeOuterClass.CounterData;
import p4.P4RuntimeOuterClass.CounterEntry;
import p4.P4RuntimeOuterClass.DirectCounterEntry;
import p4.P4RuntimeOuterClass.Entity;
import java.util.Collection;
-import java.util.Map;
+import java.util.Collections;
import java.util.Objects;
import java.util.stream.Collectors;
import static java.lang.String.format;
+import static org.onosproject.p4runtime.ctl.P4RuntimeUtils.indexMsg;
import static org.slf4j.LoggerFactory.getLogger;
import static p4.P4RuntimeOuterClass.Entity.EntityCase.COUNTER_ENTRY;
import static p4.P4RuntimeOuterClass.Entity.EntityCase.DIRECT_COUNTER_ENTRY;
/**
- * Encoder/decoder of PI counter IDs to counter entry protobuf messages, and vice versa.
+ * Encoder/decoder of PI counter IDs to counter entry protobuf messages, and
+ * vice versa.
*/
final class CounterEntryCodec {
@@ -50,27 +54,32 @@
}
/**
- * Returns a collection of P4Runtime entity protobuf messages describing both counter or direct counter entries,
- * encoded from the given collection of PI counter cell identifiers, for the given pipeconf. If a PI counter cell
- * identifier cannot be encoded, it is skipped, hence the returned collection might have different size than the
- * input one.
- * <p>
- * This method takes as parameter also a map between numeric P4Info IDs and PI counter IDs, that will be populated
- * during the process and that is then needed to aid in the decode process.
+ * Returns a collection of P4Runtime entity protobuf messages describing
+ * both counter or direct counter entries, encoded from the given collection
+ * of PI counter cell identifiers, for the given pipeconf. If a PI counter
+ * cell identifier cannot be encoded, it is skipped, hence the returned
+ * collection might have different size than the input one.
*
- * @param cellIds counter cell identifiers
- * @param counterIdMap counter ID map (empty, it will be populated during this method execution)
- * @param pipeconf pipeconf
- * @return collection of entity messages describing both counter or direct counter entries
+ * @param cellIds counter cell identifiers
+ * @param pipeconf pipeconf
+ * @return collection of entity messages describing both counter or direct
+ * counter entries
*/
static Collection<Entity> encodePiCounterCellIds(Collection<PiCounterCellId> cellIds,
- Map<Integer, PiCounterId> counterIdMap,
PiPipeconf pipeconf) {
+
+ final P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
+
+ if (browser == null) {
+ log.error("Unable to get a P4Info browser for pipeconf {}", pipeconf.id());
+ return Collections.emptyList();
+ }
+
return cellIds
.stream()
.map(cellId -> {
try {
- return encodePiCounterCellId(cellId, counterIdMap, pipeconf);
+ return encodePiCounterCellId(cellId, pipeconf, browser);
} catch (P4InfoBrowser.NotFoundException | EncodeException e) {
log.warn("Unable to encode PI counter cell id: {}", e.getMessage());
return null;
@@ -81,28 +90,33 @@
}
/**
- * Returns a collection of PI counter cell data, decoded from the given P4Runtime entity protobuf messages
- * describing both counter or direct counter entries, for the given counter ID map (populated by {@link
- * #encodePiCounterCellIds(Collection, Map, PiPipeconf)}), and pipeconf. If an entity message cannot be encoded, it
- * is skipped, hence the returned collection might have different size than the input one.
+ * Returns a collection of P4Runtime entity protobuf messages to be used in
+ * requests to read all cells from the given counter identifiers. Works for
+ * both indirect or direct counters. If a PI counter identifier cannot be
+ * encoded, it is skipped, hence the returned collection might have
+ * different size than the input one.
*
- * @param entities P4Runtime entity messages
- * @param counterIdMap counter ID map (previously populated)
- * @param pipeconf pipeconf
- * @return collection of PI counter cell data
+ * @param counterIds counter identifiers
+ * @param pipeconf pipeconf
+ * @return collection of entity messages
*/
- static Collection<PiCounterCellData> decodeCounterEntities(Collection<Entity> entities,
- Map<Integer, PiCounterId> counterIdMap,
- PiPipeconf pipeconf) {
- return entities
+ static Collection<Entity> readAllCellsEntities(Collection<PiCounterId> counterIds,
+ PiPipeconf pipeconf) {
+ final P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
+
+ if (browser == null) {
+ log.error("Unable to get a P4Info browser for pipeconf {}", pipeconf.id());
+ return Collections.emptyList();
+ }
+
+ return counterIds
.stream()
- .filter(entity -> entity.getEntityCase() == COUNTER_ENTRY ||
- entity.getEntityCase() == DIRECT_COUNTER_ENTRY)
- .map(entity -> {
+ .map(counterId -> {
try {
- return decodeCounterEntity(entity, counterIdMap, pipeconf);
- } catch (EncodeException | P4InfoBrowser.NotFoundException e) {
- log.warn("Unable to decode counter entity message: {}", e.getMessage());
+ return readAllCellsEntity(counterId, pipeconf, browser);
+ } catch (P4InfoBrowser.NotFoundException | EncodeException e) {
+ log.warn("Unable to encode counter ID to read-all-cells entity: {}",
+ e.getMessage());
return null;
}
})
@@ -110,95 +124,160 @@
.collect(Collectors.toList());
}
- private static Entity encodePiCounterCellId(PiCounterCellId cellId, Map<Integer, PiCounterId> counterIdMap,
- PiPipeconf pipeconf)
- throws P4InfoBrowser.NotFoundException, EncodeException {
+ /**
+ * Returns a collection of PI counter cell data, decoded from the given
+ * P4Runtime entity protobuf messages describing both counter or direct
+ * counter entries, and pipeconf. If an entity message cannot be encoded, it
+ * is skipped, hence the returned collection might have different size than
+ * the input one.
+ *
+ * @param entities P4Runtime entity messages
+ * @param pipeconf pipeconf
+ * @return collection of PI counter cell data
+ */
+ static Collection<PiCounterCellData> decodeCounterEntities(Collection<Entity> entities,
+ PiPipeconf pipeconf) {
final P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
+ if (browser == null) {
+ log.error("Unable to get a P4Info browser for pipeconf {}", pipeconf.id());
+ return Collections.emptyList();
+ }
+
+ return entities
+ .stream()
+ .filter(entity -> entity.getEntityCase() == COUNTER_ENTRY ||
+ entity.getEntityCase() == DIRECT_COUNTER_ENTRY)
+ .map(entity -> {
+ try {
+ return decodeCounterEntity(entity, pipeconf, browser);
+ } catch (EncodeException | P4InfoBrowser.NotFoundException e) {
+ log.warn("Unable to decode counter entity message: {}",
+ e.getMessage());
+ return null;
+ }
+ })
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ }
+
+ private static Entity encodePiCounterCellId(PiCounterCellId cellId,
+ PiPipeconf pipeconf,
+ P4InfoBrowser browser)
+ throws P4InfoBrowser.NotFoundException, EncodeException {
+
int counterId;
Entity entity;
// Encode PI cell ID into entity message and add to read request.
switch (cellId.counterType()) {
case INDIRECT:
- counterId = browser.counters().getByName(cellId.counterId().id()).getPreamble().getId();
- entity = Entity.newBuilder().setCounterEntry(CounterEntry.newBuilder()
- .setCounterId(counterId)
- .setIndex(cellId.index())
- .build())
+ counterId = browser.counters()
+ .getByName(cellId.counterId().id())
+ .getPreamble()
+ .getId();
+ entity = Entity.newBuilder()
+ .setCounterEntry(
+ CounterEntry.newBuilder()
+ .setCounterId(counterId)
+ .setIndex(indexMsg(cellId.index()))
+ .build())
.build();
break;
case DIRECT:
- counterId = browser.directCounters().getByName(cellId.counterId().id()).getPreamble().getId();
- DirectCounterEntry.Builder entryBuilder = DirectCounterEntry.newBuilder().setCounterId(counterId);
- if (!cellId.tableEntry().equals(PiTableEntry.EMTPY)) {
- entryBuilder.setTableEntry(TableEntryEncoder.encode(cellId.tableEntry(), pipeconf));
- }
- entity = Entity.newBuilder().setDirectCounterEntry(entryBuilder.build()).build();
+ DirectCounterEntry.Builder entryBuilder = DirectCounterEntry.newBuilder();
+ entryBuilder.setTableEntry(
+ TableEntryEncoder.encode(cellId.tableEntry(), pipeconf));
+ entity = Entity.newBuilder()
+ .setDirectCounterEntry(entryBuilder.build())
+ .build();
break;
default:
- throw new EncodeException(format("Unrecognized PI counter cell ID type '%s'", cellId.counterType()));
+ throw new EncodeException(format(
+ "Unrecognized PI counter cell ID type '%s'",
+ cellId.counterType()));
}
- counterIdMap.put(counterId, cellId.counterId());
return entity;
}
- private static PiCounterCellData decodeCounterEntity(Entity entity, Map<Integer, PiCounterId> counterIdMap,
- PiPipeconf pipeconf)
+ private static Entity readAllCellsEntity(PiCounterId counterId,
+ PiPipeconf pipeconf,
+ P4InfoBrowser browser)
+ throws P4InfoBrowser.NotFoundException, EncodeException {
+
+ if (!pipeconf.pipelineModel().counter(counterId).isPresent()) {
+ throw new EncodeException(format(
+ "not such counter '%s' in pipeline model", counterId));
+ }
+ final PiCounterType counterType = pipeconf.pipelineModel()
+ .counter(counterId).get().counterType();
+
+ switch (counterType) {
+ case INDIRECT:
+ final int p4InfoCounterId = browser.counters()
+ .getByName(counterId.id())
+ .getPreamble().getId();
+ return Entity.newBuilder().setCounterEntry(
+ P4RuntimeOuterClass.CounterEntry.newBuilder()
+ // Index unset to read all cells
+ .setCounterId(p4InfoCounterId)
+ .build())
+ .build();
+ case DIRECT:
+ final PiTableId tableId = pipeconf.pipelineModel()
+ .counter(counterId).get().table();
+ if (tableId == null) {
+ throw new EncodeException(format(
+ "null table for direct counter '%s'", counterId));
+ }
+ final int p4TableId = browser.tables().getByName(tableId.id())
+ .getPreamble().getId();
+ return Entity.newBuilder().setDirectCounterEntry(
+ P4RuntimeOuterClass.DirectCounterEntry.newBuilder()
+ .setTableEntry(
+ // Match unset to read all cells
+ P4RuntimeOuterClass.TableEntry.newBuilder()
+ .setTableId(p4TableId)
+ .build())
+ .build())
+ .build();
+ default:
+ throw new EncodeException(format(
+ "unrecognized PI counter type '%s'", counterType));
+ }
+ }
+
+ private static PiCounterCellData decodeCounterEntity(Entity entity,
+ PiPipeconf pipeconf,
+ P4InfoBrowser browser)
throws EncodeException, P4InfoBrowser.NotFoundException {
- int counterId;
CounterData counterData;
-
- if (entity.getEntityCase() == COUNTER_ENTRY) {
- counterId = entity.getCounterEntry().getCounterId();
- counterData = entity.getCounterEntry().getData();
- } else {
- counterId = entity.getDirectCounterEntry().getCounterId();
- counterData = entity.getDirectCounterEntry().getData();
- }
-
- // Process only counter IDs that were requested in the first place.
- if (!counterIdMap.containsKey(counterId)) {
- throw new EncodeException(format("Unrecognized counter ID '%s'", counterId));
- }
-
- PiCounterId piCounterId = counterIdMap.get(counterId);
-
- if (!pipeconf.pipelineModel().counter(piCounterId).isPresent()) {
- throw new EncodeException(format(
- "Unable to find counter '%s' in pipeline model", counterId));
- }
- PiCounterType piCounterType = pipeconf.pipelineModel().counter(piCounterId).get().counterType();
-
- // Compute PI cell ID.
PiCounterCellId piCellId;
- switch (piCounterType) {
- case INDIRECT:
- if (entity.getEntityCase() != COUNTER_ENTRY) {
- throw new EncodeException(format(
- "Counter ID '%s' is indirect, but processed entity is %s",
- piCounterId, entity.getEntityCase()));
- }
- piCellId = PiCounterCellId.ofIndirect(piCounterId,
- entity.getCounterEntry().getIndex());
- break;
- case DIRECT:
- if (entity.getEntityCase() != DIRECT_COUNTER_ENTRY) {
- throw new EncodeException(format(
- "Counter ID '%s' is direct, but processed entity is %s",
- piCounterId, entity.getEntityCase()));
- }
- PiTableEntry piTableEntry = TableEntryEncoder.decode(entity.getDirectCounterEntry().getTableEntry(),
- pipeconf);
- piCellId = PiCounterCellId.ofDirect(piCounterId, piTableEntry);
- break;
- default:
- throw new EncodeException(format("Unrecognized PI counter ID type '%s'", piCounterType));
+ if (entity.getEntityCase() == COUNTER_ENTRY) {
+ String counterName = browser.counters()
+ .getById(entity.getCounterEntry().getCounterId())
+ .getPreamble()
+ .getName();
+ piCellId = PiCounterCellId.ofIndirect(
+ PiCounterId.of(counterName),
+ entity.getCounterEntry().getIndex().getIndex());
+ counterData = entity.getCounterEntry().getData();
+ } else if (entity.getEntityCase() == DIRECT_COUNTER_ENTRY) {
+ PiTableEntry piTableEntry = TableEntryEncoder.decode(
+ entity.getDirectCounterEntry().getTableEntry(), pipeconf);
+ piCellId = PiCounterCellId.ofDirect(piTableEntry);
+ counterData = entity.getDirectCounterEntry().getData();
+ } else {
+ throw new EncodeException(format(
+ "Unrecognized entity type '%s' in P4Runtime message",
+ entity.getEntityCase().name()));
}
- return new PiCounterCellData(piCellId, counterData.getPacketCount(), counterData.getByteCount());
+ return new PiCounterCellData(piCellId,
+ counterData.getPacketCount(),
+ counterData.getByteCount());
}
}
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/MeterEntryCodec.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/MeterEntryCodec.java
index 9019613..fc60dcd 100644
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/MeterEntryCodec.java
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/MeterEntryCodec.java
@@ -16,30 +16,35 @@
package org.onosproject.p4runtime.ctl;
+import org.onosproject.net.pi.model.PiMeterId;
import org.onosproject.net.pi.model.PiMeterType;
import org.onosproject.net.pi.model.PiPipeconf;
+import org.onosproject.net.pi.model.PiTableId;
import org.onosproject.net.pi.runtime.PiMeterBand;
import org.onosproject.net.pi.runtime.PiMeterCellConfig;
import org.onosproject.net.pi.runtime.PiMeterCellId;
-import org.onosproject.net.pi.model.PiMeterId;
import org.onosproject.net.pi.runtime.PiTableEntry;
import org.slf4j.Logger;
-import p4.P4RuntimeOuterClass.MeterConfig;
-import p4.P4RuntimeOuterClass.MeterEntry;
+import p4.P4RuntimeOuterClass;
import p4.P4RuntimeOuterClass.DirectMeterEntry;
import p4.P4RuntimeOuterClass.Entity;
+import p4.P4RuntimeOuterClass.MeterConfig;
+import p4.P4RuntimeOuterClass.MeterEntry;
import java.util.Collection;
-import java.util.Map;
+import java.util.Collections;
import java.util.Objects;
import java.util.stream.Collectors;
import static java.lang.String.format;
+import static org.onosproject.p4runtime.ctl.P4RuntimeUtils.indexMsg;
import static org.slf4j.LoggerFactory.getLogger;
-import static p4.P4RuntimeOuterClass.Entity.EntityCase.*;
+import static p4.P4RuntimeOuterClass.Entity.EntityCase.DIRECT_METER_ENTRY;
+import static p4.P4RuntimeOuterClass.Entity.EntityCase.METER_ENTRY;
/**
- * Encoder/decoder of PI meter cell configurations to meter entry protobuf messages, and vice versa.
+ * Encoder/decoder of PI meter cell configurations to meter entry protobuf
+ * messages, and vice versa.
*/
final class MeterEntryCodec {
@@ -50,27 +55,31 @@
}
/**
- * Returns a collection of P4Runtime entity protobuf messages describing both meter or direct meter entries,
- * encoded from the given collection of PI meter cell configurations, for the given pipeconf. If a PI meter cell
- * configurations cannot be encoded, it is skipped, hence the returned collection might have different size than the
- * input one.
- * <p>
- * This method takes as parameter also a map between numeric P4Info IDs and PI meter IDs, that will be populated
- * during the process and that is then needed to aid in the decode process.
+ * Returns a collection of P4Runtime entity protobuf messages describing
+ * both meter or direct meter entries, encoded from the given collection of
+ * PI meter cell configurations, for the given pipeconf. If a PI meter cell
+ * configurations cannot be encoded, it is skipped, hence the returned
+ * collection might have different size than the input one.
*
- * @param cellConfigs meter cell configurations
- * @param meterIdMap meter ID map (empty, it will be populated during this method execution)
- * @param pipeconf pipeconf
- * @return collection of entity messages describing both meter or direct meter entries
+ * @param cellConfigs meter cell configurations
+ * @param pipeconf pipeconf
+ * @return collection of entity messages describing both meter or direct
+ * meter entries
*/
static Collection<Entity> encodePiMeterCellConfigs(Collection<PiMeterCellConfig> cellConfigs,
- Map<Integer, PiMeterId> meterIdMap,
PiPipeconf pipeconf) {
+ final P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
+
+ if (browser == null) {
+ log.error("Unable to get a P4Info browser for pipeconf {}", pipeconf.id());
+ return Collections.emptyList();
+ }
+
return cellConfigs
.stream()
.map(cellConfig -> {
try {
- return encodePiMeterCellConfig(cellConfig, meterIdMap, pipeconf);
+ return encodePiMeterCellConfig(cellConfig, pipeconf, browser);
} catch (P4InfoBrowser.NotFoundException | EncodeException e) {
log.warn("Unable to encode PI meter cell id: {}", e.getMessage());
log.debug("exception", e);
@@ -82,26 +91,67 @@
}
/**
- * Returns a collection of PI meter cell configurations, decoded from the given P4Runtime entity protobuf messages
- * describing both meter or direct meter entries, for the given meter ID map (populated by {@link
- * #encodePiMeterCellConfigs(Collection, Map, PiPipeconf)}), and pipeconf. If an entity message cannot be encoded,
- * it is skipped, hence the returned collection might have different size than the input one.
+ * Returns a collection of P4Runtime entity protobuf messages to be used in
+ * requests to read all cells from the given meter identifiers. Works for
+ * both indirect or direct meters. If a PI meter identifier cannot be
+ * encoded, it is skipped, hence the returned collection might have
+ * different size than the input one.
*
- * @param entities P4Runtime entity messages
- * @param meterIdMap meter ID map (previously populated)
- * @param pipeconf pipeconf
+ * @param meterIds meter identifiers
+ * @param pipeconf pipeconf
+ * @return collection of entity messages
+ */
+ static Collection<Entity> readAllCellsEntities(Collection<PiMeterId> meterIds,
+ PiPipeconf pipeconf) {
+ final P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
+
+ if (browser == null) {
+ log.error("Unable to get a P4Info browser for pipeconf {}", pipeconf.id());
+ return Collections.emptyList();
+ }
+
+ return meterIds
+ .stream()
+ .map(meterId -> {
+ try {
+ return readAllCellsEntity(meterId, pipeconf, browser);
+ } catch (P4InfoBrowser.NotFoundException | EncodeException e) {
+ log.warn("Unable to encode meter ID to read-all-cells entity: {}",
+ e.getMessage());
+ return null;
+ }
+ })
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Returns a collection of PI meter cell configurations, decoded from the
+ * given P4Runtime entity protobuf messages describing both meter or direct
+ * meter entries, and pipeconf. If an entity message cannot be encoded, it
+ * is skipped, hence the returned collection might have different size than
+ * the input one.
+ *
+ * @param entities P4Runtime entity messages
+ * @param pipeconf pipeconf
* @return collection of PI meter cell data
*/
static Collection<PiMeterCellConfig> decodeMeterEntities(Collection<Entity> entities,
- Map<Integer, PiMeterId> meterIdMap,
- PiPipeconf pipeconf) {
+ PiPipeconf pipeconf) {
+ final P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
+
+ if (browser == null) {
+ log.error("Unable to get a P4Info browser for pipeconf {}", pipeconf.id());
+ return Collections.emptyList();
+ }
+
return entities
.stream()
.filter(entity -> entity.getEntityCase() == METER_ENTRY ||
entity.getEntityCase() == DIRECT_METER_ENTRY)
.map(entity -> {
try {
- return decodeMeterEntity(entity, meterIdMap, pipeconf);
+ return decodeMeterEntity(entity, pipeconf, browser);
} catch (EncodeException | P4InfoBrowser.NotFoundException e) {
log.warn("Unable to decode meter entity message: {}", e.getMessage());
return null;
@@ -111,23 +161,23 @@
.collect(Collectors.toList());
}
- private static Entity encodePiMeterCellConfig(PiMeterCellConfig config, Map<Integer, PiMeterId> meterIdMap,
- PiPipeconf pipeconf)
+ private static Entity encodePiMeterCellConfig(PiMeterCellConfig config,
+ PiPipeconf pipeconf,
+ P4InfoBrowser browser)
throws P4InfoBrowser.NotFoundException, EncodeException {
- final P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
-
int meterId;
Entity entity;
- //The band with bigger burst is peak if rate of them is equal,
- //if bands are not specificed, using default value(0).
- long cir = 0;
- long cburst = 0;
- long pir = 0;
- long pburst = 0;
- PiMeterBand[] bands = config.meterBands().toArray(new PiMeterBand[config.meterBands().size()]);
+ MeterConfig meterConfig;
+
+ PiMeterBand[] bands = config.meterBands()
+ .toArray(new PiMeterBand[config.meterBands().size()]);
if (bands.length == 2) {
- if (bands[0].rate() > bands[1].rate()) {
+ long cir, cburst, pir, pburst;
+ // The band with bigger burst is peak if rate of them is equal.
+ if (bands[0].rate() > bands[1].rate() ||
+ (bands[0].rate() == bands[1].rate() &&
+ bands[0].burst() >= bands[1].burst())) {
cir = bands[1].rate();
cburst = bands[1].burst();
pir = bands[0].rate();
@@ -138,105 +188,133 @@
pir = bands[1].rate();
pburst = bands[1].burst();
}
+ meterConfig = MeterConfig.newBuilder()
+ .setCir(cir)
+ .setCburst(cburst)
+ .setPir(pir)
+ .setPburst(pburst)
+ .build();
+ } else if (bands.length == 0) {
+ // When reading meter cells.
+ meterConfig = null;
+ } else {
+ throw new EncodeException("number of meter bands should be either 2 or 0");
}
- // Encode PI cell ID into entity message and add to read request.
switch (config.cellId().meterType()) {
case INDIRECT:
- meterId = browser.meters().getByName(config.cellId().meterId().id()).getPreamble().getId();
- entity = Entity.newBuilder().setMeterEntry(MeterEntry
- .newBuilder().setMeterId(meterId)
- .setIndex(config.cellId().index())
- .setConfig(MeterConfig.newBuilder()
- .setCir(cir)
- .setCburst(cburst)
- .setPir(pir)
- .setPburst(pburst)
- .build())
- .build())
- .build();
+ meterId = browser.meters()
+ .getByName(config.cellId().meterId().id())
+ .getPreamble().getId();
+ MeterEntry.Builder indEntryBuilder = MeterEntry.newBuilder()
+ .setMeterId(meterId)
+ .setIndex(indexMsg(config.cellId().index()));
+ if (meterConfig != null) {
+ indEntryBuilder.setConfig(meterConfig);
+ }
+ entity = Entity.newBuilder()
+ .setMeterEntry(indEntryBuilder.build()).build();
break;
case DIRECT:
- meterId = browser.directMeters().getByName(config.cellId().meterId().id()).getPreamble().getId();
- DirectMeterEntry.Builder entryBuilder = DirectMeterEntry.newBuilder()
- .setMeterId(meterId)
- .setConfig(MeterConfig.newBuilder()
- .setCir(cir)
- .setCburst(cburst)
- .setPir(pir)
- .setPburst(pburst)
- .build());
-
- if (!config.cellId().tableEntry().equals(PiTableEntry.EMTPY)) {
- entryBuilder.setTableEntry(TableEntryEncoder.encode(config.cellId().tableEntry(), pipeconf));
+ DirectMeterEntry.Builder dirEntryBuilder = DirectMeterEntry.newBuilder()
+ .setTableEntry(TableEntryEncoder.encode(
+ config.cellId().tableEntry(), pipeconf));
+ if (meterConfig != null) {
+ dirEntryBuilder.setConfig(meterConfig);
}
- entity = Entity.newBuilder().setDirectMeterEntry(entryBuilder.build()).build();
+ entity = Entity.newBuilder()
+ .setDirectMeterEntry(dirEntryBuilder.build()).build();
break;
default:
- throw new EncodeException(format("Unrecognized PI meter cell ID type '%s'",
+ throw new EncodeException(format("unrecognized PI meter type '%s'",
config.cellId().meterType()));
}
- meterIdMap.put(meterId, config.cellId().meterId());
return entity;
}
- private static PiMeterCellConfig decodeMeterEntity(Entity entity, Map<Integer, PiMeterId> meterIdMap,
- PiPipeconf pipeconf)
+ private static Entity readAllCellsEntity(PiMeterId meterId,
+ PiPipeconf pipeconf,
+ P4InfoBrowser browser)
+ throws P4InfoBrowser.NotFoundException, EncodeException {
+
+ if (!pipeconf.pipelineModel().meter(meterId).isPresent()) {
+ throw new EncodeException(format(
+ "not such meter '%s' in pipeline model", meterId));
+ }
+ final PiMeterType meterType = pipeconf.pipelineModel()
+ .meter(meterId).get().meterType();
+
+ switch (meterType) {
+ case INDIRECT:
+ final int p4InfoMeterId = browser.meters()
+ .getByName(meterId.id())
+ .getPreamble().getId();
+ return Entity.newBuilder().setMeterEntry(
+ P4RuntimeOuterClass.MeterEntry.newBuilder()
+ // Index unset to read all cells
+ .setMeterId(p4InfoMeterId)
+ .build())
+ .build();
+ case DIRECT:
+ final PiTableId tableId = pipeconf.pipelineModel()
+ .meter(meterId).get().table();
+ if (tableId == null) {
+ throw new EncodeException(format(
+ "null table for direct meter '%s'", meterId));
+ }
+ final int p4TableId = browser.tables().getByName(tableId.id())
+ .getPreamble().getId();
+ return Entity.newBuilder().setDirectMeterEntry(
+ P4RuntimeOuterClass.DirectMeterEntry.newBuilder()
+ .setTableEntry(
+ // Match unset to read all cells
+ P4RuntimeOuterClass.TableEntry.newBuilder()
+ .setTableId(p4TableId)
+ .build())
+ .build())
+ .build();
+ default:
+ throw new EncodeException(format(
+ "unrecognized PI meter type '%s'", meterType));
+ }
+ }
+
+ private static PiMeterCellConfig decodeMeterEntity(Entity entity,
+ PiPipeconf pipeconf,
+ P4InfoBrowser browser)
throws EncodeException, P4InfoBrowser.NotFoundException {
- int meterId;
MeterConfig meterConfig;
-
- if (entity.getEntityCase() == METER_ENTRY) {
- meterId = entity.getMeterEntry().getMeterId();
- meterConfig = entity.getMeterEntry().getConfig();
- } else {
- meterId = entity.getDirectMeterEntry().getMeterId();
- meterConfig = entity.getDirectMeterEntry().getConfig();
- }
-
- // Process only meter IDs that were requested in the first place.
- if (!meterIdMap.containsKey(meterId)) {
- throw new EncodeException(format("Unrecognized meter ID '%s'", meterId));
- }
-
- PiMeterId piMeterId = meterIdMap.get(meterId);
- if (!pipeconf.pipelineModel().meter(piMeterId).isPresent()) {
- throw new EncodeException(format("Unable to find meter '%s' in pipeline model", meterId));
- }
-
- PiMeterType piMeterType = pipeconf.pipelineModel().meter(piMeterId).get().meterType();
- // Compute PI cell ID.
PiMeterCellId piCellId;
- switch (piMeterType) {
- case INDIRECT:
- if (entity.getEntityCase() != METER_ENTRY) {
- throw new EncodeException(format(
- "Meter ID '%s' is indirect, but processed entity is %s",
- piMeterId, entity.getEntityCase()));
- }
- piCellId = PiMeterCellId.ofIndirect(piMeterId, entity.getMeterEntry().getIndex());
- break;
- case DIRECT:
- if (entity.getEntityCase() != DIRECT_METER_ENTRY) {
- throw new EncodeException(format(
- "Meter ID '%s' is direct, but processed entity is %s",
- piMeterId, entity.getEntityCase()));
- }
- PiTableEntry piTableEntry = TableEntryEncoder.decode(entity.getDirectMeterEntry().getTableEntry(),
- pipeconf);
- piCellId = PiMeterCellId.ofDirect(piMeterId, piTableEntry);
- break;
- default:
- throw new EncodeException(format("Unrecognized PI meter ID type '%s'", piMeterType));
+ if (entity.getEntityCase() == METER_ENTRY) {
+ String meterName = browser.meters()
+ .getById(entity.getCounterEntry().getCounterId())
+ .getPreamble()
+ .getName();
+ piCellId = PiMeterCellId.ofIndirect(
+ PiMeterId.of(meterName),
+ entity.getMeterEntry().getIndex().getIndex());
+ meterConfig = entity.getMeterEntry().getConfig();
+ } else if (entity.getEntityCase() == DIRECT_METER_ENTRY) {
+ PiTableEntry piTableEntry = TableEntryEncoder.decode(
+ entity.getDirectMeterEntry().getTableEntry(),
+ pipeconf);
+ piCellId = PiMeterCellId.ofDirect(piTableEntry);
+ meterConfig = entity.getDirectMeterEntry().getConfig();
+ } else {
+ throw new EncodeException(format(
+ "unrecognized entity type '%s' in P4Runtime message",
+ entity.getEntityCase().name()));
}
- PiMeterCellConfig.Builder builder = PiMeterCellConfig.builder();
- builder.withMeterBand(new PiMeterBand(meterConfig.getCir(), meterConfig.getCburst()));
- builder.withMeterBand(new PiMeterBand(meterConfig.getPir(), meterConfig.getPburst()));
-
- return builder.withMeterCellId(piCellId).build();
+ return PiMeterCellConfig.builder()
+ .withMeterCellId(piCellId)
+ .withMeterBand(new PiMeterBand(meterConfig.getCir(),
+ meterConfig.getCburst()))
+ .withMeterBand(new PiMeterBand(meterConfig.getPir(),
+ meterConfig.getPburst()))
+ .build();
}
-}
\ No newline at end of file
+}
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeClientImpl.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeClientImpl.java
index 609c5c5..e8b4e21 100644
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeClientImpl.java
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeClientImpl.java
@@ -21,7 +21,6 @@
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
-import com.google.common.collect.Sets;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import io.grpc.Context;
@@ -36,7 +35,7 @@
import org.onosproject.net.MastershipRole;
import org.onosproject.net.pi.model.PiActionProfileId;
import org.onosproject.net.pi.model.PiCounterId;
-import org.onosproject.net.pi.model.PiCounterType;
+import org.onosproject.net.pi.model.PiMeterId;
import org.onosproject.net.pi.model.PiPipeconf;
import org.onosproject.net.pi.model.PiTableId;
import org.onosproject.net.pi.runtime.PiActionGroup;
@@ -46,8 +45,6 @@
import org.onosproject.net.pi.runtime.PiEntity;
import org.onosproject.net.pi.runtime.PiMeterCellConfig;
import org.onosproject.net.pi.runtime.PiMeterCellId;
-import org.onosproject.net.pi.model.PiMeterType;
-import org.onosproject.net.pi.model.PiMeterId;
import org.onosproject.net.pi.runtime.PiPacketOperation;
import org.onosproject.net.pi.runtime.PiTableEntry;
import org.onosproject.net.pi.service.PiPipeconfService;
@@ -131,8 +128,6 @@
private Map<Uint128, CompletableFuture<Boolean>> arbitrationUpdateMap = Maps.newConcurrentMap();
protected Uint128 p4RuntimeElectionId;
- private static final long DEFAULT_INDEX = 0;
-
/**
* Default constructor.
*
@@ -219,39 +214,8 @@
@Override
public CompletableFuture<Collection<PiCounterCellData>> readAllCounterCells(Set<PiCounterId> counterIds,
PiPipeconf pipeconf) {
-
- /*
- From p4runtime.proto, the scope of a ReadRequest is defined as follows:
- CounterEntry:
- - All counter cells for all meters if counter_id = 0 (default).
- - All counter cells for given counter_id if index = 0 (default).
- DirectCounterEntry:
- - All counter cells for all meters if counter_id = 0 (default).
- - All counter cells for given counter_id if table_entry.match is empty.
- */
-
- Set<PiCounterCellId> cellIds = Sets.newHashSet();
-
- for (PiCounterId counterId : counterIds) {
- if (!pipeconf.pipelineModel().counter(counterId).isPresent()) {
- log.warn("Unable to find counter '{}' in pipeline model", counterId);
- continue;
- }
- PiCounterType counterType = pipeconf.pipelineModel().counter(counterId).get().counterType();
- switch (counterType) {
- case INDIRECT:
- cellIds.add(PiCounterCellId.ofIndirect(counterId, 0));
- break;
- case DIRECT:
- cellIds.add(PiCounterCellId.ofDirect(counterId, PiTableEntry.EMTPY));
- break;
- default:
- log.warn("Unrecognized PI counter type '{}'", counterType);
- }
- }
-
- return supplyInContext(() -> doReadCounterCells(cellIds, pipeconf),
- "readAllCounterCells-" + cellIds.hashCode());
+ return supplyInContext(() -> doReadAllCounterCells(counterIds, pipeconf),
+ "readAllCounterCells-" + counterIds.hashCode());
}
@Override
@@ -297,34 +261,8 @@
@Override
public CompletableFuture<Collection<PiMeterCellConfig>> readAllMeterCells(Set<PiMeterId> meterIds,
PiPipeconf pipeconf) {
-
- /*
- From p4runtime.proto, the scope of a ReadRequest is defined as follows:
- MeterEntry:
- - All meter cells for all meters if meter_id = 0 (default).
- - All meter cells for given meter_id if index = 0 (default).
- DirectCounterEntry:
- - All meter cells for all meters if meter_id = 0 (default).
- - All meter cells for given meter_id if table_entry.match is empty.
- */
-
- Set<PiMeterCellId> cellIds = Sets.newHashSet();
- for (PiMeterId meterId : meterIds) {
- PiMeterType meterType = pipeconf.pipelineModel().meter(meterId).get().meterType();
- switch (meterType) {
- case INDIRECT:
- cellIds.add(PiMeterCellId.ofIndirect(meterId, DEFAULT_INDEX));
- break;
- case DIRECT:
- cellIds.add(PiMeterCellId.ofDirect(meterId, PiTableEntry.EMTPY));
- break;
- default:
- log.warn("Unrecognized PI meter type '{}'", meterType);
- }
- }
-
- return supplyInContext(() -> doReadMeterCells(cellIds, pipeconf),
- "readAllMeterCells-" + cellIds.hashCode());
+ return supplyInContext(() -> doReadAllMeterCells(meterIds, pipeconf),
+ "readAllMeterCells-" + meterIds.hashCode());
}
/* Blocking method implementations below */
@@ -416,7 +354,7 @@
return true;
}
- Collection<Update> updateMsgs = null;
+ Collection<Update> updateMsgs;
try {
updateMsgs = TableEntryEncoder.encode(piTableEntries, pipeconf)
.stream()
@@ -566,20 +504,32 @@
controller.postEvent(event);
}
- private Collection<PiCounterCellData> doReadCounterCells(Collection<PiCounterCellId> cellIds, PiPipeconf pipeconf) {
+ private Collection<PiCounterCellData> doReadAllCounterCells(
+ Collection<PiCounterId> counterIds, PiPipeconf pipeconf) {
+ return doReadCounterEntities(
+ CounterEntryCodec.readAllCellsEntities(counterIds, pipeconf),
+ pipeconf);
+ }
- // We use this map to remember the original PI counter IDs of the returned response.
- final Map<Integer, PiCounterId> counterIdMap = Maps.newHashMap();
+ private Collection<PiCounterCellData> doReadCounterCells(
+ Collection<PiCounterCellId> cellIds, PiPipeconf pipeconf) {
+ return doReadCounterEntities(
+ CounterEntryCodec.encodePiCounterCellIds(cellIds, pipeconf),
+ pipeconf);
+ }
+
+ private Collection<PiCounterCellData> doReadCounterEntities(
+ Collection<Entity> counterEntities, PiPipeconf pipeconf) {
+
+ if (counterEntities.size() == 0) {
+ return Collections.emptyList();
+ }
final ReadRequest request = ReadRequest.newBuilder()
.setDeviceId(p4DeviceId)
- .addAllEntities(CounterEntryCodec.encodePiCounterCellIds(cellIds, counterIdMap, pipeconf))
+ .addAllEntities(counterEntities)
.build();
- if (request.getEntitiesList().size() == 0) {
- return Collections.emptyList();
- }
-
final Iterable<ReadResponse> responses;
try {
responses = () -> blockingStub.read(request);
@@ -593,7 +543,7 @@
.flatMap(List::stream)
.collect(Collectors.toList());
- return CounterEntryCodec.decodeCounterEntities(entities, counterIdMap, pipeconf);
+ return CounterEntryCodec.decodeCounterEntities(entities, pipeconf);
}
private boolean doWriteActionGroupMembers(PiActionGroup group, WriteOperationType opType, PiPipeconf pipeconf) {
@@ -789,47 +739,60 @@
}
}
- private Collection<PiMeterCellConfig> doReadMeterCells(Collection<PiMeterCellId> cellIds, PiPipeconf pipeconf) {
+ private Collection<PiMeterCellConfig> doReadAllMeterCells(
+ Collection<PiMeterId> meterIds, PiPipeconf pipeconf) {
+ return doReadMeterEntities(MeterEntryCodec.readAllCellsEntities(
+ meterIds, pipeconf), pipeconf);
+ }
- // We use this map to remember the original PI meter IDs of the returned response.
- Map<Integer, PiMeterId> meterIdMap = Maps.newHashMap();
- Collection<PiMeterCellConfig> piMeterCellConfigs = cellIds.stream()
+ private Collection<PiMeterCellConfig> doReadMeterCells(
+ Collection<PiMeterCellId> cellIds, PiPipeconf pipeconf) {
+
+ final Collection<PiMeterCellConfig> piMeterCellConfigs = cellIds.stream()
.map(cellId -> PiMeterCellConfig.builder()
- .withMeterCellId(cellId).build())
+ .withMeterCellId(cellId)
+ .build())
.collect(Collectors.toList());
+ return doReadMeterEntities(MeterEntryCodec.encodePiMeterCellConfigs(
+ piMeterCellConfigs, pipeconf), pipeconf);
+ }
+
+ private Collection<PiMeterCellConfig> doReadMeterEntities(
+ Collection<Entity> entitiesToRead, PiPipeconf pipeconf) {
+
+ if (entitiesToRead.size() == 0) {
+ return Collections.emptyList();
+ }
+
final ReadRequest request = ReadRequest.newBuilder()
.setDeviceId(p4DeviceId)
- .addAllEntities(MeterEntryCodec.encodePiMeterCellConfigs(piMeterCellConfigs, meterIdMap, pipeconf))
+ .addAllEntities(entitiesToRead)
.build();
- if (request.getEntitiesList().size() == 0) {
- return Collections.emptyList();
- }
-
final Iterable<ReadResponse> responses;
try {
responses = () -> blockingStub.read(request);
} catch (StatusRuntimeException e) {
- log.warn("Unable to read meters config: {}", e.getMessage());
+ log.warn("Unable to read meter cells: {}", e.getMessage());
log.debug("exception", e);
return Collections.emptyList();
}
- List<Entity> entities = StreamSupport.stream(responses.spliterator(), false)
+ List<Entity> responseEntities = StreamSupport
+ .stream(responses.spliterator(), false)
.map(ReadResponse::getEntitiesList)
.flatMap(List::stream)
.collect(Collectors.toList());
- return MeterEntryCodec.decodeMeterEntities(entities, meterIdMap, pipeconf);
+ return MeterEntryCodec.decodeMeterEntities(responseEntities, pipeconf);
}
private boolean doWriteMeterCells(Collection<PiMeterCellConfig> cellIds, PiPipeconf pipeconf) {
- final Map<Integer, PiMeterId> meterIdMap = Maps.newHashMap();
WriteRequest.Builder writeRequestBuilder = WriteRequest.newBuilder();
- Collection<Update> updateMsgs = MeterEntryCodec.encodePiMeterCellConfigs(cellIds, meterIdMap, pipeconf)
+ Collection<Update> updateMsgs = MeterEntryCodec.encodePiMeterCellConfigs(cellIds, pipeconf)
.stream()
.map(meterEntryMsg ->
Update.newBuilder()
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeUtils.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeUtils.java
index 411e1fb..25ef153 100644
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeUtils.java
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeUtils.java
@@ -17,6 +17,7 @@
package org.onosproject.p4runtime.ctl;
import com.google.protobuf.ByteString;
+import p4.P4RuntimeOuterClass;
import static java.lang.String.format;
@@ -48,4 +49,8 @@
entityDescr, bitWidth, prefixLength));
}
}
+
+ static P4RuntimeOuterClass.Index indexMsg(long index) {
+ return P4RuntimeOuterClass.Index.newBuilder().setIndex(index).build();
+ }
}
diff --git a/protocols/p4runtime/proto/BUCK b/protocols/p4runtime/proto/BUCK
index 53db8a5..aa3d8d3 100644
--- a/protocols/p4runtime/proto/BUCK
+++ b/protocols/p4runtime/proto/BUCK
@@ -5,12 +5,13 @@
PROTOBUF_VER = '3.2.0'
GRPC_VER = '1.3.1'
-PI_COMMIT = '13d611a9c655938676ebcde2bd5653b461f46ca7'
+PI_COMMIT = '219b3d67299ec09b49f433d7341049256ab5f512'
PI_BASEURL = 'https://github.com/p4lang/PI.git'
# Wondering which .proto files to build? Check p4runtime's Makefile:
# https://github.com/p4lang/PI/blob/master/proto/Makefile.am
PROTO_SRCS = [
+ '/proto/p4/p4types.proto',
'/proto/p4/p4runtime.proto',
'/proto/p4/config/p4info.proto',
'/proto/google/rpc/status.proto',