[ONOS-7438][ONOS-7439] Supports table counters and some properties

Change-Id: Ifc0a0e89c14d2e5c17e11e5cef02a0de8cf5d00c
diff --git a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricConstants.java b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricConstants.java
index c29b599..8759f96 100644
--- a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricConstants.java
+++ b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricConstants.java
@@ -115,6 +115,14 @@
             PiCounterId.of("port_counters_control.ingress_port_counter");
 
     // Direct Counter IDs
+    public static final PiCounterId CNT_UNICAST_V4_COUNTER_ID = PiCounterId.of("forwarding.unicast_v4_counter");
+    public static final PiCounterId CNT_INGRESS_PORT_VLAN_COUNTER_ID =
+            PiCounterId.of("filtering.ingress_port_vlan_counter");
+    public static final PiCounterId CNT_FWD_CLASSIFIER_COUNTER_ID = PiCounterId.of("filtering.fwd_classifier_counter");
+    public static final PiCounterId CNT_BRIDGING_COUNTER_ID = PiCounterId.of("forwarding.bridging_counter");
+    public static final PiCounterId CNT_SIMPLE_COUNTER_ID = PiCounterId.of("next.simple_counter");
+    public static final PiCounterId CNT_HASHED_COUNTER_ID = PiCounterId.of("next.hashed_counter");
+    public static final PiCounterId CNT_MPLS_COUNTER_ID = PiCounterId.of("forwarding.mpls_counter");
 
     // Action IDs
     public static final PiActionId ACT_NEXT_SET_MCAST_GROUP_ID =
diff --git a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricInterpreter.java b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricInterpreter.java
index f407065..29e3a48 100644
--- a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricInterpreter.java
+++ b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricInterpreter.java
@@ -29,6 +29,7 @@
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.net.driver.Driver;
 import org.onosproject.net.flow.TrafficTreatment;
 import org.onosproject.net.flow.criteria.Criterion;
 import org.onosproject.net.flow.instructions.Instructions;
@@ -94,9 +95,6 @@
                                                                          FabricConstants.TBL_HASHED_ID,
                                                                          FabricConstants.TBL_BROADCAST_ID);
 
-    private static final ImmutableBiMap<PiTableId, PiCounterId> TABLE_COUNTER_MAP =
-            ImmutableBiMap.<PiTableId, PiCounterId>builder()
-                    .build();
     private static final ImmutableMap<Criterion.Type, PiMatchFieldId> CRITERION_MAP =
             ImmutableMap.<Criterion.Type, PiMatchFieldId>builder()
                     .put(Criterion.Type.IN_PORT, FabricConstants.HF_STANDARD_METADATA_INGRESS_PORT_ID)
@@ -136,6 +134,18 @@
                     .put(FabricConstants.HF_ICMP_ICMP_CODE_ID, Criterion.Type.ICMPV6_CODE)
                     .build();
 
+    private static final ImmutableBiMap<PiTableId, PiCounterId> TABLE_COUNTER_MAP =
+            ImmutableBiMap.<PiTableId, PiCounterId>builder()
+                    .put(FabricConstants.TBL_FWD_CLASSIFIER_ID, FabricConstants.CNT_FWD_CLASSIFIER_COUNTER_ID)
+                    .put(FabricConstants.TBL_HASHED_ID, FabricConstants.CNT_HASHED_COUNTER_ID)
+                    .put(FabricConstants.TBL_INGRESS_PORT_VLAN_ID, FabricConstants.CNT_INGRESS_PORT_VLAN_COUNTER_ID)
+                    .put(FabricConstants.TBL_SIMPLE_ID, FabricConstants.CNT_SIMPLE_COUNTER_ID)
+                    .put(FabricConstants.TBL_BRIDGING_ID, FabricConstants.CNT_BRIDGING_COUNTER_ID)
+                    .put(FabricConstants.TBL_UNICAST_V4_ID, FabricConstants.CNT_UNICAST_V4_COUNTER_ID)
+                    .put(FabricConstants.TBL_MPLS_ID, FabricConstants.CNT_MPLS_COUNTER_ID)
+                    .build();
+    private static final String SUPPORT_TABLE_COUNTERS_PROP = "supportTableCounters";
+
     @Override
     public Optional<PiMatchFieldId> mapCriterionType(Criterion.Type type) {
         return Optional.ofNullable(CRITERION_MAP.get(type));
@@ -173,7 +183,14 @@
 
     @Override
     public Optional<PiCounterId> mapTableCounter(PiTableId piTableId) {
-        return Optional.ofNullable(TABLE_COUNTER_MAP.get(piTableId));
+        Driver driver = handler().driver();
+        boolean supportTableCounters = Boolean.parseBoolean(driver.getProperty(SUPPORT_TABLE_COUNTERS_PROP));
+
+        if (supportTableCounters) {
+            return Optional.ofNullable(TABLE_COUNTER_MAP.get(piTableId));
+        } else {
+            return Optional.empty();
+        }
     }
 
     private PiPacketOperation createPiPacketOperation(DeviceId deviceId, ByteBuffer data, long portNumber)
diff --git a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricTreatmentInterpreter.java b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricTreatmentInterpreter.java
index 5ae2e9b..badb38c 100644
--- a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricTreatmentInterpreter.java
+++ b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricTreatmentInterpreter.java
@@ -190,6 +190,8 @@
                         case MPLS_LABEL:
                             modMplsInst = (ModMplsLabelInstruction) l2Inst;
                             break;
+                        case VLAN_PUSH:
+                            break;
                         default:
                             log.warn("Unsupported l2 instruction sub type: {}", l2Inst.subtype());
                             break;
diff --git a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/PipeconfLoader.java b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/PipeconfLoader.java
index 86c2908..030d2ff 100644
--- a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/PipeconfLoader.java
+++ b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/PipeconfLoader.java
@@ -77,6 +77,7 @@
         final URL jsonUrl = PipeconfLoader.class.getResource(FABRIC_JSON_PATH);
         final URL p4InfoUrl = PipeconfLoader.class.getResource(FABRIC_P4INFO_PATH);
         final PiPipelineModel model = parseP4Info(p4InfoUrl);
+        // TODO: add properties to pipeconf instead of adding it to driver
         return DefaultPiPipeconf.builder()
                 .withId(FABRIC_PIPECONF_ID)
                 .withPipelineModel(model)
diff --git a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricNextPipeliner.java b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricNextPipeliner.java
index 9177237..0047bd6 100644
--- a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricNextPipeliner.java
+++ b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricNextPipeliner.java
@@ -17,6 +17,7 @@
 package org.onosproject.pipelines.fabric.pipeliner;
 
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.driver.Driver;
 import org.onosproject.net.flow.DefaultFlowRule;
 import org.onosproject.net.flow.DefaultTrafficSelector;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
@@ -25,6 +26,7 @@
 import org.onosproject.net.flow.criteria.PiCriterion;
 import org.onosproject.net.flow.instructions.Instruction;
 import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
+import org.onosproject.net.flowobjective.DefaultNextObjective;
 import org.onosproject.net.flowobjective.NextObjective;
 import org.onosproject.net.flowobjective.ObjectiveError;
 import org.onosproject.net.group.DefaultGroupBucket;
@@ -50,11 +52,14 @@
  */
 public class FabricNextPipeliner {
     private static final Logger log = getLogger(FabricNextPipeliner.class);
+    private static final String NO_HASHED_TABLE = "noHashedTable";
 
     protected DeviceId deviceId;
+    protected Driver driver;
 
-    public FabricNextPipeliner(DeviceId deviceId) {
+    public FabricNextPipeliner(DeviceId deviceId, Driver driver) {
         this.deviceId = deviceId;
+        this.driver = driver;
     }
 
     public PipelinerTranslationResult next(NextObjective nextObjective) {
@@ -111,6 +116,32 @@
     }
 
     private void processHashedNext(NextObjective nextObjective, PipelinerTranslationResult.Builder resultBuilder) {
+        boolean noHashedTable = Boolean.parseBoolean(driver.getProperty(NO_HASHED_TABLE));
+
+        if (noHashedTable) {
+            if (nextObjective.next().isEmpty()) {
+                return;
+            }
+            // use first action if not support hashed group
+            TrafficTreatment treatment = nextObjective.next().iterator().next();
+
+            NextObjective.Builder simpleNext = DefaultNextObjective.builder()
+                    .addTreatment(treatment)
+                    .withId(nextObjective.id())
+                    .fromApp(nextObjective.appId())
+                    .makePermanent()
+                    .withMeta(nextObjective.meta())
+                    .withPriority(nextObjective.priority())
+                    .withType(NextObjective.Type.SIMPLE);
+
+            if (nextObjective.context().isPresent()) {
+                processSimpleNext(simpleNext.add(nextObjective.context().get()), resultBuilder);
+            } else {
+                processSimpleNext(simpleNext.add(), resultBuilder);
+            }
+            return;
+        }
+
         // create hash groups
         int groupId = nextObjective.id();
         List<GroupBucket> bucketList = nextObjective.next().stream()
diff --git a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricPipeliner.java b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricPipeliner.java
index eac586a..93f53db 100644
--- a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricPipeliner.java
+++ b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricPipeliner.java
@@ -26,6 +26,7 @@
 import org.onosproject.net.behaviour.Pipeliner;
 import org.onosproject.net.behaviour.PipelinerContext;
 import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.net.driver.Driver;
 import org.onosproject.net.flow.FlowRule;
 import org.onosproject.net.flow.FlowRuleOperations;
 import org.onosproject.net.flow.FlowRuleOperationsContext;
@@ -91,13 +92,14 @@
 
     @Override
     public void init(DeviceId deviceId, PipelinerContext context) {
+        Driver driver = handler().driver();
         this.deviceId = deviceId;
         this.flowRuleService = context.directory().get(FlowRuleService.class);
         this.groupService = context.directory().get(GroupService.class);
         this.flowObjectiveStore = context.directory().get(FlowObjectiveStore.class);
         this.pipelinerFilter = new FabricFilteringPipeliner(deviceId);
         this.pipelinerForward = new FabricForwardingPipeliner(deviceId);
-        this.pipelinerNext = new FabricNextPipeliner(deviceId);
+        this.pipelinerNext = new FabricNextPipeliner(deviceId, driver);
     }
 
     @Override
diff --git a/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricPipelinerTest.java b/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricPipelinerTest.java
index fb92bf9..a7b6dce 100644
--- a/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricPipelinerTest.java
+++ b/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricPipelinerTest.java
@@ -17,6 +17,7 @@
 package org.onosproject.pipelines.fabric.pipeliner;
 
 import org.junit.Before;
+import org.onlab.junit.TestUtils;
 import org.onlab.osgi.ServiceDirectory;
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
@@ -27,6 +28,8 @@
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.behaviour.PipelinerContext;
+import org.onosproject.net.driver.Driver;
+import org.onosproject.net.driver.DriverHandler;
 import org.onosproject.net.flow.criteria.PiCriterion;
 import org.onosproject.pipelines.fabric.FabricConstants;
 import org.onosproject.pipelines.fabric.FabricInterpreter;
@@ -81,8 +84,14 @@
 
         ServiceDirectory serviceDirectory = createNiceMock(ServiceDirectory.class);
         PipelinerContext pipelinerContext = createNiceMock(PipelinerContext.class);
+        DriverHandler driverHandler = createNiceMock(DriverHandler.class);
+        Driver mockDriver = createNiceMock(Driver.class);
+        expect(mockDriver.getProperty("supportTableCounters")).andReturn("true").anyTimes();
+        expect(mockDriver.getProperty("noHashedTable")).andReturn("false").anyTimes();
+        expect(driverHandler.driver()).andReturn(mockDriver).anyTimes();
         expect(pipelinerContext.directory()).andReturn(serviceDirectory).anyTimes();
-        replay(serviceDirectory, pipelinerContext);
+        replay(serviceDirectory, pipelinerContext, driverHandler, mockDriver);
+        TestUtils.setField(pipeliner, "handler", driverHandler);
 
         pipeliner.init(DEVICE_ID, pipelinerContext);
         interpreter = new FabricInterpreter();