Adding command to add routes and to generate flows from them.

Enhanced FlowRuleStore and FlowRuleService with a new method.

Change-Id: I011371c1931294448e361fc1ceb120d89c14489d
diff --git a/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java b/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java
index a4cfdfd..0ade2ed 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java
@@ -43,6 +43,16 @@
     int getFlowRuleCount();
 
     /**
+     * Returns the number of flow rules for the given device.
+     *
+     * @param deviceId device identifier
+     * @return number of flow rules for the given device
+     */
+    default int getFlowRuleCount(DeviceId deviceId) {
+        return 0;
+    }
+
+    /**
      * Returns the collection of flow entries applied on the specified device.
      * This will include flow rules which may not yet have been applied to
      * the device.
diff --git a/core/api/src/main/java/org/onosproject/net/flow/FlowRuleStore.java b/core/api/src/main/java/org/onosproject/net/flow/FlowRuleStore.java
index ff0bbe1..449a1fd 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/FlowRuleStore.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/FlowRuleStore.java
@@ -15,26 +15,36 @@
  */
 package org.onosproject.net.flow;
 
-import java.util.List;
-
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.flow.oldbatch.FlowRuleBatchEvent;
 import org.onosproject.net.flow.oldbatch.FlowRuleBatchOperation;
 import org.onosproject.store.Store;
 
+import java.util.List;
+
 /**
  * Manages inventory of flow rules; not intended for direct use.
  */
 public interface FlowRuleStore extends Store<FlowRuleBatchEvent, FlowRuleStoreDelegate> {
 
     /**
-     * Returns the number of flow rule in the store.
+     * Returns the number of flow rules in the store.
      *
      * @return number of flow rules
      */
     int getFlowRuleCount();
 
     /**
+     * Returns the number of flow rules for the given device in the store.
+     *
+     * @param deviceId device identifier
+     * @return number of flow rules for the given device
+     */
+    default int getFlowRuleCount(DeviceId deviceId) {
+        return 0;
+    }
+
+    /**
      * Returns the stored flow.
      *
      * @param rule the rule to look for
diff --git a/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java b/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java
index 9c1a31a..ffcfe0b 100644
--- a/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java
+++ b/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java
@@ -101,6 +101,7 @@
                                                  FlowRuleProvider, FlowRuleProviderService>
         implements FlowRuleService, FlowRuleProviderRegistry {
 
+    public static final String DEVICE_ID_NULL = "Device ID cannot be null";
     private final Logger log = getLogger(getClass());
 
     public static final String FLOW_RULE_NULL = "FlowRule cannot be null";
@@ -233,8 +234,16 @@
     }
 
     @Override
+    public int getFlowRuleCount(DeviceId deviceId) {
+        checkPermission(FLOWRULE_READ);
+        checkNotNull(deviceId, "Device ID cannot be null");
+        return store.getFlowRuleCount(deviceId);
+    }
+
+    @Override
     public Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) {
         checkPermission(FLOWRULE_READ);
+        checkNotNull(deviceId, DEVICE_ID_NULL);
         return store.getFlowEntries(deviceId);
     }
 
@@ -252,6 +261,7 @@
     @Override
     public void purgeFlowRules(DeviceId deviceId) {
         checkPermission(FLOWRULE_WRITE);
+        checkNotNull(deviceId, DEVICE_ID_NULL);
         store.purgeFlowRule(deviceId);
     }
 
@@ -343,6 +353,7 @@
      */
     @Override
     protected synchronized FlowRuleProvider getProvider(DeviceId deviceId) {
+        checkNotNull(deviceId, DEVICE_ID_NULL);
         // if device supports FlowRuleProgrammable,
         // use FlowRuleProgrammable via FlowRuleDriverProvider
         return Optional.ofNullable(deviceService.getDevice(deviceId))
@@ -714,11 +725,13 @@
     @Override
     public Iterable<TableStatisticsEntry> getFlowTableStatistics(DeviceId deviceId) {
         checkPermission(FLOWRULE_READ);
+        checkNotNull(deviceId, DEVICE_ID_NULL);
         return store.getTableStatistics(deviceId);
     }
 
     @Override
     public long getActiveFlowRuleCount(DeviceId deviceId) {
+        checkNotNull(deviceId, DEVICE_ID_NULL);
         return store.getActiveFlowRuleCount(deviceId);
     }
 
diff --git a/core/store/dist/src/main/java/org/onosproject/store/flow/impl/ECFlowRuleStore.java b/core/store/dist/src/main/java/org/onosproject/store/flow/impl/ECFlowRuleStore.java
index 64c09cf..e1a8cff 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/flow/impl/ECFlowRuleStore.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/flow/impl/ECFlowRuleStore.java
@@ -186,6 +186,7 @@
             .register(KryoNamespaces.API)
             .register(MastershipBasedTimestamp.class);
 
+    private EventuallyConsistentMap<DeviceId, Integer> flowCounts;
 
     private IdGenerator idGenerator;
     private NodeId local;
@@ -212,6 +213,14 @@
                 backupPeriod,
                 TimeUnit.MILLISECONDS);
 
+        flowCounts = storageService.<DeviceId, Integer>eventuallyConsistentMapBuilder()
+                .withName("onos-flow-counts")
+                .withSerializer(serializerBuilder)
+                .withAntiEntropyPeriod(5, TimeUnit.SECONDS)
+                .withTimestampProvider((k, v) -> new WallClockTimestamp())
+                .withTombstonesDisabled()
+                .build();
+
         deviceTableStats = storageService.<DeviceId, List<TableStatisticsEntry>>eventuallyConsistentMapBuilder()
                 .withName("onos-flow-table-stats")
                 .withSerializer(serializerBuilder)
@@ -333,8 +342,14 @@
     @Override
     public int getFlowRuleCount() {
         return Streams.stream(deviceService.getDevices()).parallel()
-                        .mapToInt(device -> Iterables.size(getFlowEntries(device.id())))
-                        .sum();
+                .mapToInt(device -> getFlowRuleCount(device.id()))
+                .sum();
+    }
+
+    @Override
+    public int getFlowRuleCount(DeviceId deviceId) {
+        Integer count = flowCounts.get(deviceId);
+        return count != null ? count : 0;
     }
 
     @Override
@@ -703,7 +718,13 @@
             log.debug("Sending flowEntries for devices {} to {} for backup.", deviceIds, nodeId);
             Map<DeviceId, Map<FlowId, Map<StoredFlowEntry, StoredFlowEntry>>>
                     deviceFlowEntries = Maps.newConcurrentMap();
-            deviceIds.forEach(id -> deviceFlowEntries.put(id, getFlowTableCopy(id)));
+            deviceIds.forEach(id -> {
+                Map<FlowId, Map<StoredFlowEntry, StoredFlowEntry>> copy = getFlowTableCopy(id);
+                int flowCount = copy.entrySet().stream()
+                        .mapToInt(e -> e.getValue().values().size()).sum();
+                flowCounts.put(id, flowCount);
+                deviceFlowEntries.put(id, copy);
+            });
             clusterCommunicator.<Map<DeviceId,
                                  Map<FlowId, Map<StoredFlowEntry, StoredFlowEntry>>>,
                                  Set<DeviceId>>