FlowEntryBuilder: optmize calls to DriverService

The "FlowEntryBuilder" object calls "getDriver()" twice during a
"build()". These are very expensive calls, they can represent most of the
CPU time from an OF event. Since every instance from "FlowEntryBuilder"
has an unique "DeviceId", move the creation of the DriverHandler to
"OpenFlowRuleProvider".

Change-Id: I378f840b1e971d3b141c1a4fcbcbed62e956b578
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFAgentVirtualFlowEntryBuilder.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFAgentVirtualFlowEntryBuilder.java
index e3cb9e3..9ed3a83 100644
--- a/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFAgentVirtualFlowEntryBuilder.java
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFAgentVirtualFlowEntryBuilder.java
@@ -33,14 +33,14 @@
     private static final Logger log = LoggerFactory.getLogger(OFAgentVirtualFlowEntryBuilder.class);
     private static final String DRIVER_NAME = "ovs";
 
-    private final DriverService driverService;
+    private final DriverHandler driverHandler;
 
     public OFAgentVirtualFlowEntryBuilder(DeviceId deviceId, OFFlowMod fm, DriverService driverService) {
         super(deviceId, fm, driverService);
-        this.driverService = driverService;
+        this.driverHandler = getDriver(deviceId, driverService);
     }
 
-    protected DriverHandler getDriver(DeviceId devId) {
+    protected static DriverHandler getDriver(DeviceId devId, DriverService driverService) {
         log.debug("calling getDriver for {}", devId);
         Driver driver = driverService.getDriver(DRIVER_NAME);
         DriverHandler handler = new DefaultDriverHandler(new DefaultDriverData(driver, devId));
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java
index 7f472ad..47c49bc 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java
@@ -36,6 +36,10 @@
 import org.onosproject.cfg.ComponentConfigService;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.driver.DefaultDriverData;
+import org.onosproject.net.driver.DefaultDriverHandler;
+import org.onosproject.net.driver.Driver;
+import org.onosproject.net.driver.DriverHandler;
 import org.onosproject.net.driver.DriverService;
 import org.onosproject.net.flow.CompletedBatchOperation;
 import org.onosproject.net.flow.DefaultTableStatisticsEntry;
@@ -435,12 +439,12 @@
                 case FLOW_REMOVED:
                     OFFlowRemoved removed = (OFFlowRemoved) msg;
 
-                    FlowEntry fr = new FlowEntryBuilder(deviceId, removed, driverService).build();
+                    FlowEntry fr = new FlowEntryBuilder(deviceId, removed, getDriver(deviceId)).build();
                     providerService.flowRemoved(fr);
                     break;
                 case STATS_REPLY:
                     if (((OFStatsReply) msg).getStatsType() == OFStatsType.FLOW) {
-                        pushFlowMetrics(dpid, (OFFlowStatsReply) msg);
+                        pushFlowMetrics(dpid, (OFFlowStatsReply) msg, getDriver(deviceId));
                     } else if (((OFStatsReply) msg).getStatsType() == OFStatsType.TABLE) {
                         pushTableStatistics(dpid, (OFTableStatsReply) msg);
                     } else if (((OFStatsReply) msg).getStatsType() == OFStatsType.FLOW_LIGHTWEIGHT) {
@@ -515,7 +519,7 @@
 
                     if (entry != null)  {
                         OFFlowMod ofFlowMod = (OFFlowMod) ofMessage;
-                        entry.appendFailure(new FlowEntryBuilder(deviceId, ofFlowMod, driverService).build());
+                        entry.appendFailure(new FlowEntryBuilder(deviceId, ofFlowMod, getDriver(deviceId)).build());
                     } else {
                       log.error("No matching batch for this error: {}", error);
                     }
@@ -611,14 +615,20 @@
             // Do nothing here for now.
         }
 
-        private void pushFlowMetrics(Dpid dpid, OFFlowStatsReply replies) {
+        private DriverHandler getDriver(DeviceId devId) {
+            Driver driver = driverService.getDriver(devId);
+            DriverHandler handler = new DefaultDriverHandler(new DefaultDriverData(driver, devId));
+            return handler;
+        }
+
+        private void pushFlowMetrics(Dpid dpid, OFFlowStatsReply replies, DriverHandler handler) {
 
             DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
             NewAdaptiveFlowStatsCollector afsc = afsCollectors.get(dpid);
 
             if (adaptiveFlowSampling && afsc != null)  {
                 List<FlowEntry> flowEntries = replies.getEntries().stream()
-                        .map(entry -> new FlowEntryBuilder(did, entry, driverService).withSetAfsc(afsc).build())
+                        .map(entry -> new FlowEntryBuilder(did, entry, handler).withSetAfsc(afsc).build())
                         .collect(Collectors.toList());
 
                 // Check that OFFlowStatsReply Xid is same with the one of OFFlowStatsRequest?
@@ -639,7 +649,7 @@
                 }
             } else {
                 List<FlowEntry> flowEntries = replies.getEntries().stream()
-                        .map(entry -> new FlowEntryBuilder(did, entry, driverService).build())
+                        .map(entry -> new FlowEntryBuilder(did, entry, handler).build())
                         .collect(Collectors.toList());
 
                 // call existing entire flow stats update with flowMissing synchronization
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/util/FlowEntryBuilder.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/util/FlowEntryBuilder.java
index dee9455..a71d440 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/util/FlowEntryBuilder.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/util/FlowEntryBuilder.java
@@ -141,13 +141,13 @@
 
     private final FlowType type;
 
-    private final DriverService driverService;
+    private DriverHandler driverHandler;
 
     // NewAdaptiveFlowStatsCollector for AdaptiveFlowSampling mode,
     // null is not AFM mode, namely SimpleStatsCollector mode
     private NewAdaptiveFlowStatsCollector afsc;
 
-    public FlowEntryBuilder(DeviceId deviceId, OFFlowStatsEntry entry, DriverService driverService) {
+    public FlowEntryBuilder(DeviceId deviceId, OFFlowStatsEntry entry, DriverHandler driverHandler) {
         this.stat = entry;
         this.match = entry.getMatch();
         this.instructions = getInstructions(entry);
@@ -155,7 +155,7 @@
         this.removed = null;
         this.flowMod = null;
         this.type = FlowType.STAT;
-        this.driverService = driverService;
+        this.driverHandler = driverHandler;
         this.afsc = null;
         this.lightWeightStat = null;
     }
@@ -169,12 +169,12 @@
         this.removed = null;
         this.flowMod = null;
         this.type = FlowType.LIGHTWEIGHT_STAT;
-        this.driverService = driverService;
+        this.driverHandler = getDriver(deviceId, driverService);
         this.afsc = null;
         this.lightWeightStat = lightWeightStat;
     }
 
-    public FlowEntryBuilder(DeviceId deviceId, OFFlowRemoved removed, DriverService driverService) {
+    public FlowEntryBuilder(DeviceId deviceId, OFFlowRemoved removed, DriverHandler driverHandler) {
         this.match = removed.getMatch();
         this.removed = removed;
         this.deviceId = deviceId;
@@ -182,12 +182,12 @@
         this.stat = null;
         this.flowMod = null;
         this.type = FlowType.REMOVED;
-        this.driverService = driverService;
+        this.driverHandler = driverHandler;
         this.afsc = null;
         this.lightWeightStat = null;
     }
 
-    public FlowEntryBuilder(DeviceId deviceId, OFFlowMod fm, DriverService driverService) {
+    public FlowEntryBuilder(DeviceId deviceId, OFFlowMod fm, DriverHandler driverHandler) {
         this.match = fm.getMatch();
         this.deviceId = deviceId;
         this.instructions = getInstructions(fm);
@@ -195,11 +195,23 @@
         this.flowMod = fm;
         this.stat = null;
         this.removed = null;
-        this.driverService = driverService;
+        this.driverHandler = driverHandler;
         this.afsc = null;
         this.lightWeightStat = null;
     }
 
+    public FlowEntryBuilder(DeviceId deviceId, OFFlowStatsEntry entry, DriverService driverService) {
+        this(deviceId, entry, getDriver(deviceId, driverService));
+    }
+
+    public FlowEntryBuilder(DeviceId deviceId, OFFlowRemoved removed, DriverService driverService) {
+        this(deviceId, removed, getDriver(deviceId, driverService));
+    }
+
+    public FlowEntryBuilder(DeviceId deviceId, OFFlowMod fm, DriverService driverService) {
+        this(deviceId, fm, getDriver(deviceId, driverService));
+    }
+
     public FlowEntryBuilder withSetAfsc(NewAdaptiveFlowStatsCollector afsc) {
         this.afsc = afsc;
         return this;
@@ -631,8 +643,6 @@
 
     private TrafficTreatment.Builder buildActions(List<OFAction> actions,
                                                   TrafficTreatment.Builder builder) {
-        DriverHandler driverHandler = getDriver(deviceId);
-
         return configureTreatmentBuilder(actions, builder, driverHandler, deviceId);
     }
 
@@ -858,7 +868,6 @@
         Ip6Prefix ip6Prefix;
         Ip4Address ip;
 
-        DriverHandler driverHandler = getDriver(deviceId);
         ExtensionSelectorInterpreter selectorInterpreter;
         if (driverHandler.hasBehaviour(ExtensionSelectorInterpreter.class)) {
             selectorInterpreter = driverHandler.behaviour(ExtensionSelectorInterpreter.class);
@@ -1288,9 +1297,10 @@
      * Retrieves the driver handler for the specified device.
      *
      * @param deviceId device identifier
+     * @param driverService service handle for the driver service
      * @return driver handler
      */
-    protected DriverHandler getDriver(DeviceId deviceId) {
+    protected static DriverHandler getDriver(DeviceId deviceId, DriverService driverService) {
         Driver driver = driverService.getDriver(deviceId);
         DriverHandler handler = new DefaultDriverHandler(new DefaultDriverData(driver, deviceId));
         return handler;