Various improvements to PI group handling
- Moved group translation logic to core service
- Removed dependency on KRYO
- Fixed bug where tratments with PI instructions where not supported if
an interpreter was present
- Fixed bug where action profile name was not found during protobuf
encoding (always perform P4Info lookup by name and alias)
- Improved reading of members by issuing one big request for all
groups
Change-Id: Ifcf8380b09293e70be15cf4999bd2845caf5d01e
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 3b7f3d3..b2743ac 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
@@ -18,12 +18,11 @@
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.runtime.PiActionProfileId;
import org.onosproject.net.pi.runtime.PiCounterCellData;
import org.onosproject.net.pi.runtime.PiCounterCellId;
import org.onosproject.net.pi.runtime.PiCounterId;
-import org.onosproject.net.pi.runtime.PiActionGroup;
-import org.onosproject.net.pi.runtime.PiActionGroupMember;
import org.onosproject.net.pi.runtime.PiPacketOperation;
import org.onosproject.net.pi.runtime.PiTableEntry;
import org.onosproject.net.pi.runtime.PiTableId;
@@ -121,13 +120,11 @@
* Performs the given write operation for the given action group members and pipeconf.
*
* @param group action group
- * @param members the collection of action group members
* @param opType write operation type
* @param pipeconf the pipeconf currently deployed on the device
* @return true if the operation was successful, false otherwise
*/
CompletableFuture<Boolean> writeActionGroupMembers(PiActionGroup group,
- Collection<PiActionGroupMember> members,
WriteOperationType opType,
PiPipeconf pipeconf);
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ActionProfileGroupEncoder.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ActionProfileGroupEncoder.java
index 472bf8e..c3783c1 100644
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ActionProfileGroupEncoder.java
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ActionProfileGroupEncoder.java
@@ -18,9 +18,9 @@
import com.google.common.collect.Maps;
import org.onosproject.net.pi.model.PiPipeconf;
-import org.onosproject.net.pi.runtime.PiActionProfileId;
import org.onosproject.net.pi.runtime.PiActionGroup;
import org.onosproject.net.pi.runtime.PiActionGroupId;
+import org.onosproject.net.pi.runtime.PiActionProfileId;
import p4.P4RuntimeOuterClass.ActionProfileGroup;
import p4.P4RuntimeOuterClass.ActionProfileGroup.Member;
import p4.P4RuntimeOuterClass.ActionProfileMember;
@@ -57,12 +57,10 @@
}
PiActionProfileId piActionProfileId = piActionGroup.actionProfileId();
- int actionProfileId;
- P4InfoOuterClass.ActionProfile actionProfile =
- browser.actionProfiles().getByName(piActionProfileId.id());
- actionProfileId = actionProfile.getPreamble().getId();
- ActionProfileGroup.Builder actionProfileGroupBuilder =
- ActionProfileGroup.newBuilder()
+ P4InfoOuterClass.ActionProfile actionProfile = browser.actionProfiles()
+ .getByNameOrAlias(piActionProfileId.id());
+ int actionProfileId = actionProfile.getPreamble().getId();
+ ActionProfileGroup.Builder actionProfileGroupBuilder = ActionProfileGroup.newBuilder()
.setGroupId(piActionGroup.id().id())
.setActionProfileId(actionProfileId);
@@ -71,8 +69,7 @@
actionProfileGroupBuilder.setType(ActionProfileGroup.Type.SELECT);
break;
default:
- throw new EncodeException(format("Unsupported pi action group type %s",
- piActionGroup.type()));
+ throw new EncodeException(format("PI action group type %s not supported", piActionGroup.type()));
}
piActionGroup.members().forEach(m -> {
@@ -84,6 +81,8 @@
actionProfileGroupBuilder.addMembers(member);
});
+ actionProfileGroupBuilder.setMaxSize(piActionGroup.members().size());
+
return actionProfileGroupBuilder.build();
}
@@ -98,8 +97,8 @@
* @throws EncodeException if can't find P4Info from pipeconf
*/
static PiActionGroup decode(ActionProfileGroup actionProfileGroup,
- Collection<ActionProfileMember> members,
- PiPipeconf pipeconf)
+ Collection<ActionProfileMember> members,
+ PiPipeconf pipeconf)
throws P4InfoBrowser.NotFoundException, EncodeException {
P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
if (browser == null) {
@@ -110,15 +109,19 @@
P4InfoOuterClass.ActionProfile actionProfile = browser.actionProfiles()
.getById(actionProfileGroup.getActionProfileId());
PiActionProfileId piActionProfileId = PiActionProfileId.of(actionProfile.getPreamble().getName());
- piActionGroupBuilder.withActionProfileId(piActionProfileId)
+
+ piActionGroupBuilder
+ .withActionProfileId(piActionProfileId)
.withId(PiActionGroupId.of(actionProfileGroup.getGroupId()));
switch (actionProfileGroup.getType()) {
+ case UNSPECIFIED:
+ // FIXME: PI returns unspecified for select groups. Remove this case when PI bug will be fixed.
case SELECT:
piActionGroupBuilder.withType(PiActionGroup.Type.SELECT);
break;
default:
- throw new EncodeException(format("Unsupported action profile type %s",
+ throw new EncodeException(format("Action profile type %s is not supported",
actionProfileGroup.getType()));
}
@@ -134,9 +137,12 @@
});
for (ActionProfileMember member : members) {
+ if (!memberWeights.containsKey(member.getMemberId())) {
+ // Not a member of this group, ignore.
+ continue;
+ }
int weight = memberWeights.get(member.getMemberId());
- piActionGroupBuilder
- .addMember(ActionProfileMemberEncoder.decode(member, weight, pipeconf));
+ piActionGroupBuilder.addMember(ActionProfileMemberEncoder.decode(member, weight, pipeconf));
}
return piActionGroupBuilder.build();
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ActionProfileMemberEncoder.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ActionProfileMemberEncoder.java
index 2f08a59..878ede6 100644
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ActionProfileMemberEncoder.java
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ActionProfileMemberEncoder.java
@@ -73,7 +73,7 @@
// action profile id
P4InfoOuterClass.ActionProfile actionProfile =
- browser.actionProfiles().getByName(group.actionProfileId().id());
+ browser.actionProfiles().getByNameOrAlias(group.actionProfileId().id());
int actionProfileId = actionProfile.getPreamble().getId();
actionProfileMemberBuilder.setActionProfileId(actionProfileId);
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4InfoBrowser.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4InfoBrowser.java
index 609d2d2..177c381 100644
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4InfoBrowser.java
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4InfoBrowser.java
@@ -303,20 +303,6 @@
}
/**
- * Returns the entity identified by the given name, if present, otherwise, throws an exception.
- *
- * @param name entity name
- * @return entity message
- * @throws NotFoundException if the entity cannot be found
- */
- T getByName(String name) throws NotFoundException {
- if (!hasName(name)) {
- throw new NotFoundException(entityName, name);
- }
- return names.get(name);
- }
-
- /**
* Returns the entity identified by the given name or alias, if present, otherwise, throws an exception.
*
* @param name entity name or alias
@@ -344,20 +330,6 @@
}
/**
- * Returns the entity identified by the given alias, if present, otherwise, throws an exception.
- *
- * @param alias entity alias
- * @return entity message
- * @throws NotFoundException if the entity cannot be found
- */
- T getByAlias(String alias) throws NotFoundException {
- if (!hasName(alias)) {
- throw new NotFoundException(entityName, alias);
- }
- return aliases.get(alias);
- }
-
- /**
* Returns true if the P4Info defines an entity with such id, false otherwise.
*
* @param id entity id
@@ -388,7 +360,7 @@
public static final class NotFoundException extends Exception {
NotFoundException(String entityName, String key) {
- super(format("No such %s in P4Info with name/alias '%s'", entityName, key));
+ super(format("No such %s in P4Info with %name or alias '%s'", entityName, key));
}
NotFoundException(String entityName, int id) {
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 7f22e79..a579e36 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
@@ -16,10 +16,10 @@
package org.onosproject.p4runtime.ctl;
+import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
-import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import com.google.protobuf.ByteString;
@@ -32,14 +32,14 @@
import org.onlab.util.Tools;
import org.onosproject.net.DeviceId;
import org.onosproject.net.pi.model.PiPipeconf;
+import org.onosproject.net.pi.runtime.PiActionGroup;
+import org.onosproject.net.pi.runtime.PiActionGroupMember;
import org.onosproject.net.pi.runtime.PiActionProfileId;
import org.onosproject.net.pi.runtime.PiCounterCellData;
import org.onosproject.net.pi.runtime.PiCounterCellId;
import org.onosproject.net.pi.runtime.PiCounterId;
import org.onosproject.net.pi.runtime.PiDirectCounterCellId;
import org.onosproject.net.pi.runtime.PiIndirectCounterCellId;
-import org.onosproject.net.pi.runtime.PiActionGroup;
-import org.onosproject.net.pi.runtime.PiActionGroupMember;
import org.onosproject.net.pi.runtime.PiPacketOperation;
import org.onosproject.net.pi.runtime.PiPipeconfService;
import org.onosproject.net.pi.runtime.PiTableEntry;
@@ -62,7 +62,6 @@
import p4.P4RuntimeOuterClass.TableEntry;
import p4.P4RuntimeOuterClass.Update;
import p4.P4RuntimeOuterClass.WriteRequest;
-import p4.config.P4InfoOuterClass;
import p4.config.P4InfoOuterClass.P4Info;
import p4.tmp.P4Config;
@@ -73,14 +72,13 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Supplier;
@@ -90,9 +88,7 @@
import static org.onlab.util.Tools.groupedThreads;
import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType;
import static org.slf4j.LoggerFactory.getLogger;
-import static p4.P4RuntimeOuterClass.Entity.EntityCase.ACTION_PROFILE_GROUP;
-import static p4.P4RuntimeOuterClass.Entity.EntityCase.ACTION_PROFILE_MEMBER;
-import static p4.P4RuntimeOuterClass.Entity.EntityCase.TABLE_ENTRY;
+import static p4.P4RuntimeOuterClass.Entity.EntityCase.*;
import static p4.P4RuntimeOuterClass.PacketOut;
import static p4.P4RuntimeOuterClass.SetForwardingPipelineConfigRequest.Action.VERIFY_AND_COMMIT;
@@ -123,9 +119,9 @@
/**
* Default constructor.
*
- * @param deviceId the ONOS device id
+ * @param deviceId the ONOS device id
* @param p4DeviceId the P4 device id
- * @param channel gRPC channel
+ * @param channel gRPC channel
* @param controller runtime client controller
*/
P4RuntimeClientImpl(DeviceId deviceId, long p4DeviceId, ManagedChannel channel,
@@ -239,10 +235,9 @@
@Override
public CompletableFuture<Boolean> writeActionGroupMembers(PiActionGroup group,
- Collection<PiActionGroupMember> members,
WriteOperationType opType,
PiPipeconf pipeconf) {
- return supplyInContext(() -> doWriteActionGroupMembers(group, members, opType, pipeconf),
+ return supplyInContext(() -> doWriteActionGroupMembers(group, opType, pipeconf),
"writeActionGroupMembers-" + opType.name());
}
@@ -394,7 +389,7 @@
P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
int tableId;
try {
- tableId = browser.tables().getByName(piTableId.id()).getPreamble().getId();
+ tableId = browser.tables().getByNameOrAlias(piTableId.id()).getPreamble().getId();
} catch (P4InfoBrowser.NotFoundException e) {
log.warn("Unable to dump table: {}", e.getMessage());
return Collections.emptyList();
@@ -509,23 +504,19 @@
return CounterEntryCodec.decodeCounterEntities(entities, counterIdMap, pipeconf);
}
- private boolean doWriteActionGroupMembers(PiActionGroup group, Collection<PiActionGroupMember> members,
- WriteOperationType opType, PiPipeconf pipeconf) {
- WriteRequest.Builder writeRequestBuilder = WriteRequest.newBuilder();
+ private boolean doWriteActionGroupMembers(PiActionGroup group, WriteOperationType opType, PiPipeconf pipeconf) {
- Collection<ActionProfileMember> actionProfileMembers = Lists.newArrayList();
+ final Collection<ActionProfileMember> actionProfileMembers = Lists.newArrayList();
try {
- for (PiActionGroupMember member : members) {
- actionProfileMembers.add(
- ActionProfileMemberEncoder.encode(group, member, pipeconf)
- );
+ for (PiActionGroupMember member : group.members()) {
+ actionProfileMembers.add(ActionProfileMemberEncoder.encode(group, member, pipeconf));
}
} catch (EncodeException | P4InfoBrowser.NotFoundException e) {
- log.warn("Can't encode group member {} due to {}", members, e.getMessage());
+ log.warn("Unable to write ({}) group members: {}", opType, e.getMessage());
return false;
}
- Collection<Update> updateMsgs = actionProfileMembers.stream()
+ final Collection<Update> updateMsgs = actionProfileMembers.stream()
.map(actionProfileMember ->
Update.newBuilder()
.setEntity(Entity.newBuilder()
@@ -536,18 +527,19 @@
.collect(Collectors.toList());
if (updateMsgs.size() == 0) {
- // Nothing to update
+ // Nothing to update.
return true;
}
- writeRequestBuilder
+ WriteRequest writeRequestMsg = WriteRequest.newBuilder()
.setDeviceId(p4DeviceId)
- .addAllUpdates(updateMsgs);
+ .addAllUpdates(updateMsgs)
+ .build();
try {
- blockingStub.write(writeRequestBuilder.build());
+ blockingStub.write(writeRequestMsg);
return true;
} catch (StatusRuntimeException e) {
- log.warn("Unable to write table entries ({}): {}", opType, e.getMessage());
+ log.warn("Unable to write ({}) group members: {}", opType, e.getMessage());
return false;
}
}
@@ -555,141 +547,149 @@
private Collection<PiActionGroup> doDumpGroups(PiActionProfileId piActionProfileId, PiPipeconf pipeconf) {
log.debug("Dumping groups from action profile {} from {} (pipeconf {})...",
piActionProfileId.id(), deviceId, pipeconf.id());
- P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
+
+ final P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
if (browser == null) {
- log.warn("Unable to get a P4Info browser for pipeconf {}, skipping dump action profile {}",
- pipeconf, piActionProfileId);
+ log.warn("Unable to get a P4Info browser for pipeconf {}, aborting dump action profile", pipeconf);
return Collections.emptySet();
}
- int actionProfileId;
+ final int actionProfileId;
try {
- P4InfoOuterClass.ActionProfile actionProfile =
- browser.actionProfiles().getByName(piActionProfileId.id());
- actionProfileId = actionProfile.getPreamble().getId();
+ actionProfileId = browser
+ .actionProfiles()
+ .getByNameOrAlias(piActionProfileId.id())
+ .getPreamble()
+ .getId();
} catch (P4InfoBrowser.NotFoundException e) {
- log.warn("Can't find action profile {} from p4info", piActionProfileId);
+ log.warn("Unable to dump groups: {}", e.getMessage());
return Collections.emptySet();
}
- ActionProfileGroup actionProfileGroup =
- ActionProfileGroup.newBuilder()
- .setActionProfileId(actionProfileId)
- .build();
-
- ReadRequest requestMsg = ReadRequest.newBuilder()
+ // Prepare read request to read all groups from the given action profile.
+ final ReadRequest groupRequestMsg = ReadRequest.newBuilder()
.setDeviceId(p4DeviceId)
.addEntities(Entity.newBuilder()
- .setActionProfileGroup(actionProfileGroup)
+ .setActionProfileGroup(
+ ActionProfileGroup.newBuilder()
+ .setActionProfileId(actionProfileId)
+ .build())
.build())
.build();
- Iterator<ReadResponse> responses;
+ // Read groups.
+ final Iterator<ReadResponse> groupResponses;
try {
- responses = blockingStub.read(requestMsg);
+ groupResponses = blockingStub.read(groupRequestMsg);
} catch (StatusRuntimeException e) {
- log.warn("Unable to read action profile {} due to {}", piActionProfileId, e.getMessage());
+ log.warn("Unable dump groups from action profile '{}': {}", piActionProfileId.id(), e.getMessage());
return Collections.emptySet();
}
- List<ActionProfileGroup> actionProfileGroups =
- Tools.stream(() -> responses)
- .map(ReadResponse::getEntitiesList)
- .flatMap(List::stream)
- .filter(entity -> entity.getEntityCase() == ACTION_PROFILE_GROUP)
- .map(Entity::getActionProfileGroup)
- .collect(Collectors.toList());
+ final List<ActionProfileGroup> groupMsgs = Tools.stream(() -> groupResponses)
+ .map(ReadResponse::getEntitiesList)
+ .flatMap(List::stream)
+ .filter(entity -> entity.getEntityCase() == ACTION_PROFILE_GROUP)
+ .map(Entity::getActionProfileGroup)
+ .collect(Collectors.toList());
log.debug("Retrieved {} groups from action profile {} on {}...",
- actionProfileGroups.size(), piActionProfileId.id(), deviceId);
+ groupMsgs.size(), piActionProfileId.id(), deviceId);
- // group id -> members
- Multimap<Integer, ActionProfileMember> actionProfileMemberMap = HashMultimap.create();
- AtomicLong memberCount = new AtomicLong(0);
- AtomicBoolean success = new AtomicBoolean(true);
- actionProfileGroups.forEach(actProfGrp -> {
- actProfGrp.getMembersList().forEach(member -> {
- ActionProfileMember actProfMember =
- ActionProfileMember.newBuilder()
- .setActionProfileId(actProfGrp.getActionProfileId())
- .setMemberId(member.getMemberId())
- .build();
- Entity entity = Entity.newBuilder()
- .setActionProfileMember(actProfMember)
- .build();
+ // Returned groups contain only a minimal description of their members.
+ // We need to issue a new request to get the full description of each member.
- ReadRequest reqMsg = ReadRequest.newBuilder().setDeviceId(p4DeviceId)
- .addEntities(entity)
- .build();
+ // Keep a map of all member IDs for each group ID, will need it later.
+ final Multimap<Integer, Integer> groupIdToMemberIdsMap = HashMultimap.create();
+ groupMsgs.forEach(g -> groupIdToMemberIdsMap.putAll(
+ g.getGroupId(),
+ g.getMembersList().stream()
+ .map(ActionProfileGroup.Member::getMemberId)
+ .collect(Collectors.toList())));
- Iterator<ReadResponse> resps;
- try {
- resps = blockingStub.read(reqMsg);
- } catch (StatusRuntimeException e) {
- log.warn("Unable to read member {} from action profile {} due to {}",
- member, piActionProfileId, e.getMessage());
- success.set(false);
- return;
- }
- Tools.stream(() -> resps)
- .map(ReadResponse::getEntitiesList)
- .flatMap(List::stream)
- .filter(e -> e.getEntityCase() == ACTION_PROFILE_MEMBER)
- .map(Entity::getActionProfileMember)
- .forEach(m -> {
- actionProfileMemberMap.put(actProfGrp.getGroupId(), m);
- memberCount.incrementAndGet();
- });
- });
- });
+ // Prepare one big read request to read all members in one shot.
+ final Set<Entity> entityMsgs = groupMsgs.stream()
+ .flatMap(g -> g.getMembersList().stream())
+ .map(ActionProfileGroup.Member::getMemberId)
+ // Prevent issuing many read requests for the same member.
+ .distinct()
+ .map(id -> ActionProfileMember.newBuilder()
+ .setActionProfileId(actionProfileId)
+ .setMemberId(id)
+ .build())
+ .map(m -> Entity.newBuilder()
+ .setActionProfileMember(m)
+ .build())
+ .collect(Collectors.toSet());
+ final ReadRequest memberRequestMsg = ReadRequest.newBuilder().setDeviceId(p4DeviceId)
+ .addAllEntities(entityMsgs)
+ .build();
- if (!success.get()) {
- // Can't read members
- return Collections.emptySet();
- }
- log.info("Retrieved {} group members from action profile {} on {}...",
- memberCount.get(), piActionProfileId.id(), deviceId);
-
- Collection<PiActionGroup> piActionGroups = Sets.newHashSet();
-
- for (ActionProfileGroup apg : actionProfileGroups) {
- try {
- Collection<ActionProfileMember> members = actionProfileMemberMap.get(apg.getGroupId());
- PiActionGroup decodedGroup =
- ActionProfileGroupEncoder.decode(apg, members, pipeconf);
- piActionGroups.add(decodedGroup);
- } catch (EncodeException | P4InfoBrowser.NotFoundException e) {
- log.warn("Can't decode group {} due to {}", apg, e.getMessage());
- return Collections.emptySet();
- }
+ // Read members.
+ final Iterator<ReadResponse> memberResponses;
+ try {
+ memberResponses = blockingStub.read(memberRequestMsg);
+ } catch (StatusRuntimeException e) {
+ log.warn("Unable to read members from action profile {}: {}", piActionProfileId, e.getMessage());
+ return Collections.emptyList();
}
- return piActionGroups;
+ final Multimap<Integer, ActionProfileMember> groupIdToMembersMap = HashMultimap.create();
+ Tools.stream(() -> memberResponses)
+ .map(ReadResponse::getEntitiesList)
+ .flatMap(List::stream)
+ .filter(e -> e.getEntityCase() == ACTION_PROFILE_MEMBER)
+ .map(Entity::getActionProfileMember)
+ .forEach(member -> groupIdToMemberIdsMap.asMap()
+ // Get all group IDs that contain this member.
+ .entrySet()
+ .stream()
+ .filter(entry -> entry.getValue().contains(member.getMemberId()))
+ .map(Map.Entry::getKey)
+ .forEach(gid -> groupIdToMembersMap.put(gid, member)));
+
+ log.debug("Retrieved {} group members from action profile {} on {}...",
+ groupIdToMembersMap.size(), piActionProfileId.id(), deviceId);
+
+ return groupMsgs.stream()
+ .map(groupMsg -> {
+ try {
+ return ActionProfileGroupEncoder.decode(groupMsg,
+ groupIdToMembersMap.get(groupMsg.getGroupId()),
+ pipeconf);
+ } catch (P4InfoBrowser.NotFoundException | EncodeException e) {
+ log.warn("Unable to decode group: {}\n {}", e.getMessage(), groupMsg);
+ return null;
+ }
+ })
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
}
private boolean doWriteActionGroup(PiActionGroup group, WriteOperationType opType, PiPipeconf pipeconf) {
- WriteRequest.Builder writeRequestBuilder = WriteRequest.newBuilder();
- ActionProfileGroup actionProfileGroup;
+
+ final ActionProfileGroup actionProfileGroup;
try {
actionProfileGroup = ActionProfileGroupEncoder.encode(group, pipeconf);
} catch (EncodeException | P4InfoBrowser.NotFoundException e) {
- log.warn("Can't encode group {} due to {}", e.getMessage());
+ log.warn("Unable to encode group: {}", e.getMessage());
return false;
}
- Update updateMessage = Update.newBuilder()
- .setEntity(Entity.newBuilder()
- .setActionProfileGroup(actionProfileGroup)
- .build())
- .setType(UPDATE_TYPES.get(opType))
- .build();
- writeRequestBuilder
+
+ final WriteRequest writeRequestMsg = WriteRequest.newBuilder()
.setDeviceId(p4DeviceId)
- .addUpdates(updateMessage);
+ .addUpdates(Update.newBuilder()
+ .setEntity(Entity.newBuilder()
+ .setActionProfileGroup(actionProfileGroup)
+ .build())
+ .setType(UPDATE_TYPES.get(opType))
+ .build())
+ .build();
try {
- blockingStub.write(writeRequestBuilder.build());
+ blockingStub.write(writeRequestMsg);
return true;
} catch (StatusRuntimeException e) {
- log.warn("Unable to write table entries ({}): {}", opType, e.getMessage());
+ log.warn("Unable to write groups ({}): {}", opType, e.getMessage());
return false;
}
}
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/PacketIOCodec.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/PacketIOCodec.java
index 20219f3..2ffe31b 100644
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/PacketIOCodec.java
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/PacketIOCodec.java
@@ -33,9 +33,7 @@
import static org.onlab.util.ImmutableByteSequence.copyFrom;
import static org.onosproject.p4runtime.ctl.P4InfoBrowser.NotFoundException;
import static org.slf4j.LoggerFactory.getLogger;
-import static p4.P4RuntimeOuterClass.PacketIn;
-import static p4.P4RuntimeOuterClass.PacketMetadata;
-import static p4.P4RuntimeOuterClass.PacketOut;
+import static p4.P4RuntimeOuterClass.*;
/**
* Encoder of packet metadata, from ONOS Pi* format, to P4Runtime protobuf messages, and vice versa.
@@ -75,7 +73,7 @@
//Get the packet out controller packet metadata
P4InfoOuterClass.ControllerPacketMetadata controllerPacketMetadata =
- browser.controllerPacketMetadatas().getByName(PACKET_OUT);
+ browser.controllerPacketMetadatas().getByNameOrAlias(PACKET_OUT);
PacketOut.Builder packetOutBuilder = PacketOut.newBuilder();
//outer controller packet metadata id
@@ -96,7 +94,7 @@
try {
//get each metadata id
int metadataId = browser.packetMetadatas(controllerPacketMetadataId)
- .getByName(metadata.id().name()).getId();
+ .getByNameOrAlias(metadata.id().name()).getId();
//Add the metadata id and it's data the packet out
return PacketMetadata.newBuilder()
@@ -129,7 +127,7 @@
List<PiPacketMetadata> packetMetadatas;
try {
- int controllerPacketMetadataId = browser.controllerPacketMetadatas().getByName(PACKET_IN)
+ int controllerPacketMetadataId = browser.controllerPacketMetadatas().getByNameOrAlias(PACKET_IN)
.getPreamble().getId();
packetMetadatas = decodePacketMetadataIn(packetIn.getMetadataList(), browser,
controllerPacketMetadataId);
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/TableEntryEncoder.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/TableEntryEncoder.java
index 8278b3e..3890848 100644
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/TableEntryEncoder.java
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/TableEntryEncoder.java
@@ -39,10 +39,10 @@
import org.onosproject.net.pi.runtime.PiTernaryFieldMatch;
import org.onosproject.net.pi.runtime.PiValidFieldMatch;
import org.slf4j.Logger;
+import p4.P4RuntimeOuterClass.Action;
import p4.P4RuntimeOuterClass.FieldMatch;
import p4.P4RuntimeOuterClass.TableAction;
import p4.P4RuntimeOuterClass.TableEntry;
-import p4.P4RuntimeOuterClass.Action;
import p4.config.P4InfoOuterClass;
import java.util.Collection;
@@ -197,7 +197,7 @@
TableEntry.Builder tableEntryMsgBuilder = TableEntry.newBuilder();
//FIXME this throws some kind of NPE
- P4InfoOuterClass.Table tableInfo = browser.tables().getByName(tableId.id());
+ P4InfoOuterClass.Table tableInfo = browser.tables().getByNameOrAlias(tableId.id());
// Table id.
tableEntryMsgBuilder.setTableId(tableInfo.getPreamble().getId());
@@ -216,7 +216,7 @@
TableEntry.Builder tableEntryMsgBuilder = TableEntry.newBuilder();
//FIXME this throws some kind of NPE
- P4InfoOuterClass.Table tableInfo = browser.tables().getByName(piTableEntry.table().id());
+ P4InfoOuterClass.Table tableInfo = browser.tables().getByNameOrAlias(piTableEntry.table().id());
// Table id.
tableEntryMsgBuilder.setTableId(tableInfo.getPreamble().getId());
@@ -469,13 +469,13 @@
static Action encodePiAction(PiAction piAction, P4InfoBrowser browser)
throws P4InfoBrowser.NotFoundException, EncodeException {
- int actionId = browser.actions().getByName(piAction.id().name()).getPreamble().getId();
+ int actionId = browser.actions().getByNameOrAlias(piAction.id().name()).getPreamble().getId();
Action.Builder actionMsgBuilder =
Action.newBuilder().setActionId(actionId);
for (PiActionParam p : piAction.parameters()) {
- P4InfoOuterClass.Action.Param paramInfo = browser.actionParams(actionId).getByName(p.id().name());
+ P4InfoOuterClass.Action.Param paramInfo = browser.actionParams(actionId).getByNameOrAlias(p.id().name());
ByteString paramValue = ByteString.copyFrom(p.value().asReadOnlyBuffer());
assertSize(format("param '%s' of action '%s'", p.id(), piAction.id()),
paramValue, paramInfo.getBitwidth());
diff --git a/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/P4RuntimeGroupTest.java b/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/P4RuntimeGroupTest.java
index 8932a16..1c9c4ab 100644
--- a/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/P4RuntimeGroupTest.java
+++ b/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/P4RuntimeGroupTest.java
@@ -36,7 +36,6 @@
import org.onosproject.net.pi.model.PiPipeconf;
import org.onosproject.net.pi.model.PiPipeconfId;
import org.onosproject.net.pi.model.PiPipelineModel;
-import org.onosproject.net.pi.runtime.PiActionProfileId;
import org.onosproject.net.pi.runtime.PiAction;
import org.onosproject.net.pi.runtime.PiActionGroup;
import org.onosproject.net.pi.runtime.PiActionGroupId;
@@ -45,6 +44,7 @@
import org.onosproject.net.pi.runtime.PiActionId;
import org.onosproject.net.pi.runtime.PiActionParam;
import org.onosproject.net.pi.runtime.PiActionParamId;
+import org.onosproject.net.pi.runtime.PiActionProfileId;
import p4.P4RuntimeOuterClass.ActionProfileGroup;
import p4.P4RuntimeOuterClass.ActionProfileMember;
import p4.P4RuntimeOuterClass.Entity;
@@ -57,15 +57,15 @@
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
-import static org.easymock.EasyMock.*;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.easymock.EasyMock.niceMock;
+import static org.junit.Assert.*;
import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.P4_INFO_TEXT;
import static org.onosproject.net.pi.runtime.PiActionGroup.Type.SELECT;
import static org.onosproject.p4runtime.api.P4RuntimeClient.WriteOperationType.INSERT;
-import static p4.P4RuntimeOuterClass.*;
+import static p4.P4RuntimeOuterClass.Action;
+import static p4.P4RuntimeOuterClass.ReadResponse;
/**
* Tests for P4 Runtime Action Profile Group support.
@@ -98,7 +98,7 @@
private static final int P4_DEVICE_ID = 1;
private static final int SET_EGRESS_PORT_ID = 16794308;
private static final String GRPC_SERVER_NAME = "P4RuntimeGroupTest";
- private static final long DEFAULT_TIMEOUT_TIME = 5;
+ private static final long DEFAULT_TIMEOUT_TIME = 10;
private P4RuntimeClientImpl client;
private P4RuntimeControllerImpl controller;
@@ -187,7 +187,7 @@
@Test
public void testInsertPiActionMembers() throws Exception {
CompletableFuture<Void> complete = p4RuntimeServerImpl.expectRequests(1);
- client.writeActionGroupMembers(GROUP, GROUP_MEMBERS, INSERT, PIPECONF);
+ client.writeActionGroupMembers(GROUP, INSERT, PIPECONF);
complete.get(DEFAULT_TIMEOUT_TIME, TimeUnit.SECONDS);
WriteRequest result = p4RuntimeServerImpl.getWriteReqs().get(0);
assertEquals(1, result.getDeviceId());
@@ -240,7 +240,6 @@
.addParams(param)
.build();
-
ActionProfileMember actProfMember =
ActionProfileMember.newBuilder()
.setMemberId(id)
@@ -255,14 +254,14 @@
.build()
);
- members.forEach(m -> {
- responses.add(ReadResponse.newBuilder()
- .addEntities(Entity.newBuilder().setActionProfileMember(m))
- .build());
- });
+ responses.add(ReadResponse.newBuilder()
+ .addAllEntities(members.stream()
+ .map(m -> Entity.newBuilder().setActionProfileMember(m).build())
+ .collect(Collectors.toList()))
+ .build());
p4RuntimeServerImpl.willReturnReadResult(responses);
- CompletableFuture<Void> complete = p4RuntimeServerImpl.expectRequests(4);
+ CompletableFuture<Void> complete = p4RuntimeServerImpl.expectRequests(2);
CompletableFuture<Collection<PiActionGroup>> groupsComplete = client.dumpGroups(ACT_PROF_ID, PIPECONF);
complete.get(DEFAULT_TIMEOUT_TIME, TimeUnit.SECONDS);
diff --git a/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/TableEntryEncoderTest.java b/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/TableEntryEncoderTest.java
index b3e9a1e..b434b4d 100644
--- a/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/TableEntryEncoderTest.java
+++ b/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/TableEntryEncoderTest.java
@@ -44,9 +44,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
-import static org.onlab.util.ImmutableByteSequence.copyFrom;
-import static org.onlab.util.ImmutableByteSequence.fit;
-import static org.onlab.util.ImmutableByteSequence.ofOnes;
+import static org.onlab.util.ImmutableByteSequence.*;
import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.P4_INFO_TEXT;
import static org.onosproject.p4runtime.ctl.TableEntryEncoder.decode;
import static org.onosproject.p4runtime.ctl.TableEntryEncoder.encode;
@@ -114,8 +112,8 @@
assertThat(browser.tables().hasName(TABLE_0), is(true));
assertThat(browser.actions().hasName(SET_EGRESS_PORT), is(true));
- int tableId = browser.tables().getByName(TABLE_0).getPreamble().getId();
- int actionId = browser.actions().getByName(SET_EGRESS_PORT).getPreamble().getId();
+ int tableId = browser.tables().getByNameOrAlias(TABLE_0).getPreamble().getId();
+ int actionId = browser.actions().getByNameOrAlias(SET_EGRESS_PORT).getPreamble().getId();
assertThat(browser.matchFields(tableId).hasName(STANDARD_METADATA + "." + INGRESS_PORT), is(true));
assertThat(browser.actionParams(actionId).hasName(PORT), is(true));
@@ -141,7 +139,7 @@
.testEquals();
// Table ID.
- int p4InfoTableId = browser.tables().getByName(tableId.id()).getPreamble().getId();
+ int p4InfoTableId = browser.tables().getByNameOrAlias(tableId.id()).getPreamble().getId();
int encodedTableId = tableEntryMsg.getTableId();
assertThat(encodedTableId, is(p4InfoTableId));
@@ -152,12 +150,12 @@
Action actionMsg = tableEntryMsg.getAction().getAction();
// Action ID.
- int p4InfoActionId = browser.actions().getByName(outActionId.name()).getPreamble().getId();
+ int p4InfoActionId = browser.actions().getByNameOrAlias(outActionId.name()).getPreamble().getId();
int encodedActionId = actionMsg.getActionId();
assertThat(encodedActionId, is(p4InfoActionId));
// Action param ID.
- int p4InfoActionParamId = browser.actionParams(p4InfoActionId).getByName(portParamId.name()).getId();
+ int p4InfoActionParamId = browser.actionParams(p4InfoActionId).getByNameOrAlias(portParamId.name()).getId();
int encodedActionParamId = actionMsg.getParams(0).getParamId();
assertThat(encodedActionParamId, is(p4InfoActionParamId));