[SDFAB-379] Optimize the resource usage of the L3 unicast groups

This is achieved by translating SIMPLE next objective into
INDIRECT groups. By default SELECT groups are always used
which has as side effect the creation of action profile groups
with the maxGroupSize derived from the action profile model.

Instead, PiGroupTranslator sets always to 1 the maxGroupSize
of action profile groups derived from a INDIRECT groups which
allows us to achieve a better scale for target devices pre-allocating
memory according to the maxGroupSize.

Change-Id: I7079a99ca9a7474eafae7f258da06770453b05f9
diff --git a/core/net/src/main/java/org/onosproject/net/pi/impl/PiGroupTranslatorImpl.java b/core/net/src/main/java/org/onosproject/net/pi/impl/PiGroupTranslatorImpl.java
index e06f54e..4bf4330 100644
--- a/core/net/src/main/java/org/onosproject/net/pi/impl/PiGroupTranslatorImpl.java
+++ b/core/net/src/main/java/org/onosproject/net/pi/impl/PiGroupTranslatorImpl.java
@@ -173,7 +173,10 @@
                     .withAction((PiAction) tableAction)
                     .build();
 
-            piActionGroupBuilder.addMember(member, bucket.weight());
+            // NOTE Indirect groups have weight set to -1 which is not supported
+            // by P4RT - setting to 1 to avoid problems with the p4rt server.
+            final int weight = group.type() == GroupDescription.Type.INDIRECT ? 1 : bucket.weight();
+            piActionGroupBuilder.addMember(member, weight);
         }
 
         return piActionGroupBuilder.build();
diff --git a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeGroupProgrammable.java b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeGroupProgrammable.java
index f38b504..80da11d 100644
--- a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeGroupProgrammable.java
+++ b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeGroupProgrammable.java
@@ -51,6 +51,7 @@
         final List<GroupOperation> preGroups = Lists.newArrayList();
         groupOps.operations().forEach(op -> {
             switch (op.groupType()) {
+                case INDIRECT:
                 case SELECT:
                     actionGroups.add(op);
                     break;
@@ -59,7 +60,6 @@
                     preGroups.add(op);
                     break;
                 case FAILOVER:
-                case INDIRECT:
                 default:
                     log.warn("{} group type not supported [{}]", op.groupType(), op);
             }
diff --git a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/NextObjectiveTranslator.java b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/NextObjectiveTranslator.java
index 47b7ef6..037e5dd 100644
--- a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/NextObjectiveTranslator.java
+++ b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/NextObjectiveTranslator.java
@@ -53,6 +53,7 @@
 import org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils;
 
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
@@ -268,8 +269,18 @@
             return;
         }
 
-        // Updated result builder with hashed group.
-        final int groupId = selectGroup(obj, resultBuilder);
+        // Updated result builder with hashed group or indirect group
+        // use indirect group allow us to optimize the resource in those
+        // devices that preallocate memory based on the maxGroupSize
+        final int groupId;
+        if (obj.type() == NextObjective.Type.HASHED) {
+            groupId = selectGroup(obj, resultBuilder);
+        } else if (obj.type() == NextObjective.Type.SIMPLE) {
+            groupId = indirectGroup(obj, resultBuilder);
+        } else {
+            throw new FabricPipelinerException("Cannot translate BROADCAST next objective" +
+                    "into hashedNext actions");
+        }
 
         if (isGroupModifyOp(obj) || obj.op() == Objective.Operation.VERIFY) {
             // No changes to flow rules.
@@ -505,6 +516,44 @@
         return groupId;
     }
 
+    private int indirectGroup(NextObjective obj,
+                              ObjectiveTranslation.Builder resultBuilder)
+            throws FabricPipelinerException {
+
+        if (isGroupModifyOp(obj)) {
+            throw new FabricPipelinerException("Simple next objective does not support" +
+                    "*_TO_EXISTING operations");
+        }
+
+        final PiTableId hashedTableId = FabricConstants.FABRIC_INGRESS_NEXT_HASHED;
+        final List<DefaultNextTreatment> defaultNextTreatments =
+                defaultNextTreatments(obj.nextTreatments(), true);
+
+        if (defaultNextTreatments.size() != 1) {
+            throw new FabricPipelinerException("Simple next objective must have a single" +
+                    " treatment");
+        }
+
+        final TrafficTreatment piTreatment;
+        final DefaultNextTreatment defaultNextTreatment = defaultNextTreatments.get(0);
+        piTreatment = mapTreatmentToPiIfNeeded(defaultNextTreatment.treatment(), hashedTableId);
+        handleEgress(obj, defaultNextTreatment.treatment(), resultBuilder, false);
+        final GroupBucket groupBucket = DefaultGroupBucket.createIndirectGroupBucket(piTreatment);
+
+        final int groupId = obj.id();
+        final PiGroupKey groupKey = (PiGroupKey) getGroupKey(obj);
+
+        resultBuilder.addGroup(new DefaultGroupDescription(
+                deviceId,
+                GroupDescription.Type.INDIRECT,
+                new GroupBuckets(Collections.singletonList(groupBucket)),
+                groupKey,
+                groupId,
+                obj.appId()));
+
+        return groupId;
+    }
+
     private List<DefaultNextTreatment> defaultNextTreatments(
             Collection<NextTreatment> nextTreatments, boolean strict)
             throws FabricPipelinerException {