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/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());