Enabling opportunity to store in ONOS Flow Rules already installed on the device. This option should be activated via following Cli command: 'cfg set org.onosproject.net.flow.impl.FlowRuleManager allowExtraneousRules true'.

Change-Id: Ie603bff643d6d2aa16002c16861628e1417bd84d
diff --git a/core/net/src/main/java/org/onosproject/net/OsgiPropertyConstants.java b/core/net/src/main/java/org/onosproject/net/OsgiPropertyConstants.java
index bcf9d2f..fe6ac63 100644
--- a/core/net/src/main/java/org/onosproject/net/OsgiPropertyConstants.java
+++ b/core/net/src/main/java/org/onosproject/net/OsgiPropertyConstants.java
@@ -38,6 +38,9 @@
     public static final String ALLOW_EXTRANEOUS_RULES = "allowExtraneousRules";
     public static final boolean ALLOW_EXTRANEOUS_RULES_DEFAULT = false;
 
+    public static final String IMPORT_EXTRANEOUS_RULES = "importExtraneousRules";
+    public static final boolean IMPORT_EXTRANEOUS_RULES_DEFAULT = false;
+
     public static final String PURGE_ON_DISCONNECTION = "purgeOnDisconnection";
     public static final boolean PURGE_ON_DISCONNECTION_DEFAULT = false;
 
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 a35d7a7..bdc48ac 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
@@ -82,6 +82,8 @@
 import static org.onlab.util.Tools.groupedThreads;
 import static org.onosproject.net.OsgiPropertyConstants.ALLOW_EXTRANEOUS_RULES;
 import static org.onosproject.net.OsgiPropertyConstants.ALLOW_EXTRANEOUS_RULES_DEFAULT;
+import static org.onosproject.net.OsgiPropertyConstants.IMPORT_EXTRANEOUS_RULES;
+import static org.onosproject.net.OsgiPropertyConstants.IMPORT_EXTRANEOUS_RULES_DEFAULT;
 import static org.onosproject.net.OsgiPropertyConstants.POLL_FREQUENCY;
 import static org.onosproject.net.OsgiPropertyConstants.POLL_FREQUENCY_DEFAULT;
 import static org.onosproject.net.OsgiPropertyConstants.PURGE_ON_DISCONNECTION;
@@ -97,20 +99,21 @@
  * Provides implementation of the flow NB & SB APIs.
  */
 @Component(
-    immediate = true,
-    service = {
-        FlowRuleService.class,
-        FlowRuleProviderRegistry.class
-    },
-    property = {
-        ALLOW_EXTRANEOUS_RULES + ":Boolean=" + ALLOW_EXTRANEOUS_RULES_DEFAULT,
-        PURGE_ON_DISCONNECTION + ":Boolean=" + PURGE_ON_DISCONNECTION_DEFAULT,
-        POLL_FREQUENCY + ":Integer=" + POLL_FREQUENCY_DEFAULT
-    }
+        immediate = true,
+        service = {
+                FlowRuleService.class,
+                FlowRuleProviderRegistry.class
+        },
+        property = {
+                ALLOW_EXTRANEOUS_RULES + ":Boolean=" + ALLOW_EXTRANEOUS_RULES_DEFAULT,
+                IMPORT_EXTRANEOUS_RULES + ":Boolean=" + IMPORT_EXTRANEOUS_RULES_DEFAULT,
+                PURGE_ON_DISCONNECTION + ":Boolean=" + PURGE_ON_DISCONNECTION_DEFAULT,
+                POLL_FREQUENCY + ":Integer=" + POLL_FREQUENCY_DEFAULT
+        }
 )
 public class FlowRuleManager
         extends AbstractListenerProviderRegistry<FlowRuleEvent, FlowRuleListener,
-                                                 FlowRuleProvider, FlowRuleProviderService>
+        FlowRuleProvider, FlowRuleProviderService>
         implements FlowRuleService, FlowRuleProviderRegistry {
 
     private final Logger log = getLogger(getClass());
@@ -121,6 +124,9 @@
     /** Allow flow rules in switch not installed by ONOS. */
     private boolean allowExtraneousRules = ALLOW_EXTRANEOUS_RULES_DEFAULT;
 
+    /** Allow to import flow rules in switch not installed by ONOS. */
+    private boolean importExtraneousRules = IMPORT_EXTRANEOUS_RULES_DEFAULT;
+
     /** Purge entries associated with a device when the device goes offline. */
     private boolean purgeOnDisconnection = PURGE_ON_DISCONNECTION_DEFAULT;
 
@@ -189,7 +195,7 @@
             readComponentConfiguration(context);
         }
         driverProvider.init(new InternalFlowRuleProviderService(driverProvider),
-                             deviceService, mastershipService, fallbackFlowPollFrequency);
+                            deviceService, mastershipService, fallbackFlowPollFrequency);
     }
 
     @Override
@@ -209,21 +215,31 @@
         flag = Tools.isPropertyEnabled(properties, ALLOW_EXTRANEOUS_RULES);
         if (flag == null) {
             log.info("AllowExtraneousRules is not configured, " +
-                    "using current value of {}", allowExtraneousRules);
+                             "using current value of {}", allowExtraneousRules);
         } else {
             allowExtraneousRules = flag;
             log.info("Configured. AllowExtraneousRules is {}",
-                    allowExtraneousRules ? "enabled" : "disabled");
+                     allowExtraneousRules ? "enabled" : "disabled");
+        }
+
+        flag = Tools.isPropertyEnabled(properties, IMPORT_EXTRANEOUS_RULES);
+        if (flag == null) {
+            log.info("ImportExtraneousRules is not configured, " +
+                             "using current value of {}", importExtraneousRules);
+        } else {
+            importExtraneousRules = flag;
+            log.info("Configured. importExtraneousRules is {}",
+                     importExtraneousRules ? "enabled" : "disabled");
         }
 
         flag = Tools.isPropertyEnabled(properties, PURGE_ON_DISCONNECTION);
         if (flag == null) {
             log.info("PurgeOnDisconnection is not configured, " +
-                    "using current value of {}", purgeOnDisconnection);
+                             "using current value of {}", purgeOnDisconnection);
         } else {
             purgeOnDisconnection = flag;
             log.info("Configured. PurgeOnDisconnection is {}",
-                    purgeOnDisconnection ? "enabled" : "disabled");
+                     purgeOnDisconnection ? "enabled" : "disabled");
         }
 
         String s = get(properties, POLL_FREQUENCY);
@@ -374,9 +390,9 @@
         // if device supports FlowRuleProgrammable,
         // use FlowRuleProgrammable via FlowRuleDriverProvider
         return Optional.ofNullable(deviceService.getDevice(deviceId))
-                        .filter(dev -> dev.is(FlowRuleProgrammable.class))
-                        .<FlowRuleProvider>map(x -> driverProvider)
-                        .orElseGet(() -> super.getProvider(deviceId));
+                .filter(dev -> dev.is(FlowRuleProgrammable.class))
+                .<FlowRuleProvider>map(x -> driverProvider)
+                .orElseGet(() -> super.getProvider(deviceId));
     }
 
     private class InternalFlowRuleProviderService
@@ -567,6 +583,8 @@
                         // the device has a rule the store does not have
                         if (!allowExtraneousRules) {
                             extraneousFlow(rule);
+                        } else if (importExtraneousRules) { // Stores the rule, if so is indicated
+                            store.addOrUpdateFlowRule(rule);
                         }
                     }
                 } catch (Exception e) {
@@ -599,7 +617,7 @@
 
         @Override
         public void pushTableStatistics(DeviceId deviceId,
-                                          List<TableStatisticsEntry> tableStats) {
+                                        List<TableStatisticsEntry> tableStats) {
             store.updateTableStatistics(deviceId, tableStats);
         }
     }
@@ -614,54 +632,54 @@
         public void notify(FlowRuleBatchEvent event) {
             final FlowRuleBatchRequest request = event.subject();
             switch (event.type()) {
-            case BATCH_OPERATION_REQUESTED:
-                // Request has been forwarded to MASTER Node, and was
-                request.ops().forEach(
-                        op -> {
-                            switch (op.operator()) {
-                                case ADD:
-                                    post(new FlowRuleEvent(RULE_ADD_REQUESTED, op.target()));
-                                    break;
-                                case REMOVE:
-                                    post(new FlowRuleEvent(RULE_REMOVE_REQUESTED, op.target()));
-                                    break;
-                                case MODIFY:
-                                    //TODO: do something here when the time comes.
-                                    break;
-                                default:
-                                    log.warn("Unknown flow operation operator: {}", op.operator());
+                case BATCH_OPERATION_REQUESTED:
+                    // Request has been forwarded to MASTER Node, and was
+                    request.ops().forEach(
+                            op -> {
+                                switch (op.operator()) {
+                                    case ADD:
+                                        post(new FlowRuleEvent(RULE_ADD_REQUESTED, op.target()));
+                                        break;
+                                    case REMOVE:
+                                        post(new FlowRuleEvent(RULE_REMOVE_REQUESTED, op.target()));
+                                        break;
+                                    case MODIFY:
+                                        //TODO: do something here when the time comes.
+                                        break;
+                                    default:
+                                        log.warn("Unknown flow operation operator: {}", op.operator());
+                                }
                             }
-                        }
-                );
+                    );
 
-                DeviceId deviceId = event.deviceId();
-                FlowRuleBatchOperation batchOperation = request.asBatchOperation(deviceId);
-                // getProvider is customized to favor driverProvider
-                FlowRuleProvider flowRuleProvider = getProvider(deviceId);
-                if (flowRuleProvider != null) {
-                    log.trace("Sending {} flow rules to {}", batchOperation.size(), deviceId);
-                    flowRuleProvider.executeBatch(batchOperation);
-                }
-
-                break;
-
-            case BATCH_OPERATION_COMPLETED:
-                // Operation completed, let's retrieve the processor and trigger the callback
-                FlowOperationsProcessor fops = pendingFlowOperations.remove(
-                        event.subject().batchId());
-                if (fops != null) {
-                    if (event.result().isSuccess()) {
-                        fops.satisfy(event.deviceId());
-                    } else {
-                        fops.fail(event.deviceId(), event.result().failedItems());
+                    DeviceId deviceId = event.deviceId();
+                    FlowRuleBatchOperation batchOperation = request.asBatchOperation(deviceId);
+                    // getProvider is customized to favor driverProvider
+                    FlowRuleProvider flowRuleProvider = getProvider(deviceId);
+                    if (flowRuleProvider != null) {
+                        log.trace("Sending {} flow rules to {}", batchOperation.size(), deviceId);
+                        flowRuleProvider.executeBatch(batchOperation);
                     }
-                } else {
-                    log.warn("Unable to find flow operations processor for batch: {}", event.subject().batchId());
-                }
-                break;
 
-            default:
-                break;
+                    break;
+
+                case BATCH_OPERATION_COMPLETED:
+                    // Operation completed, let's retrieve the processor and trigger the callback
+                    FlowOperationsProcessor fops = pendingFlowOperations.remove(
+                            event.subject().batchId());
+                    if (fops != null) {
+                        if (event.result().isSuccess()) {
+                            fops.satisfy(event.deviceId());
+                        } else {
+                            fops.fail(event.deviceId(), event.result().failedItems());
+                        }
+                    } else {
+                        log.warn("Unable to find flow operations processor for batch: {}", event.subject().batchId());
+                    }
+                    break;
+
+                default:
+                    break;
             }
         }
     }
@@ -707,14 +725,14 @@
 
             for (FlowRuleOperation op : ops) {
                 perDeviceBatches.put(op.rule().deviceId(),
-                        new FlowRuleBatchEntry(mapOperationType(op.type()), op.rule()));
+                                     new FlowRuleBatchEntry(mapOperationType(op.type()), op.rule()));
             }
             pendingDevices.addAll(perDeviceBatches.keySet());
 
             for (DeviceId deviceId : perDeviceBatches.keySet()) {
                 long id = idGenerator.getNewId();
                 final FlowRuleBatchOperation b = new FlowRuleBatchOperation(perDeviceBatches.get(deviceId),
-                                               deviceId, id);
+                                                                            deviceId, id);
                 pendingFlowOperations.put(id, this);
                 deviceInstallers.execute(() -> store.storeBatch(b));
             }