Postpones the installation of the table miss flow rule.

This will happen after the installation  of the group
that punts the packets to the controller (0xc0000000).

Prevents hosts being learned with the assigned vlan.

Change-Id: I46d880309c75430ebbb76f289b371955dd68af2d
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/OvsOfdpaPipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/OvsOfdpaPipeline.java
index 47f8612..c269412 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/OvsOfdpaPipeline.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/OvsOfdpaPipeline.java
@@ -1232,18 +1232,6 @@
                 .forTable(PUNT_TABLE).build();
         ops.add(bbdpRule);
 
-        // Add table miss flow rule
-        TrafficSelector.Builder defaultSelector = DefaultTrafficSelector.builder();
-        FlowRule defaultRule = DefaultFlowRule.builder()
-                .forDevice(deviceId)
-                .withSelector(defaultSelector.build())
-                .withTreatment(treatment)
-                .withPriority(LOWEST_PRIORITY)
-                .fromApp(driverId)
-                .makePermanent()
-                .forTable(PUNT_TABLE).build();
-        ops.add(defaultRule);
-
         flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
             @Override
             public void onSuccess(FlowRuleOperations ops) {
@@ -1326,12 +1314,46 @@
                     // this signifies that the group is created and now
                     // flow rules can be installed directly
                     flowRuleQueue = null;
-                    // shutdown the group checker gracefully
-                    groupChecker.shutdown();
+                    // Schedule with an initial delay the miss table flow rule installation
+                    // the delay is to make sure the queued flows are all installed before
+                    // pushing the table miss flow rule
+                    // TODO it can be further optimized by using context and completable future
+                    groupChecker.schedule(new TableMissFlowInstaller(), 5000, TimeUnit.MILLISECONDS);
                 }
             } finally {
                 groupCheckerLock.unlock();
             }
         }
     }
+
+    private class TableMissFlowInstaller implements Runnable {
+        @Override
+        public void run() {
+            // Add table miss flow rule
+            FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
+            TrafficSelector.Builder defaultSelector = DefaultTrafficSelector.builder();
+            TrafficTreatment treatment =  DefaultTrafficTreatment.builder().punt().build();
+            FlowRule defaultRule = DefaultFlowRule.builder()
+                    .forDevice(deviceId)
+                    .withSelector(defaultSelector.build())
+                    .withTreatment(treatment)
+                    .withPriority(LOWEST_PRIORITY)
+                    .fromApp(driverId)
+                    .makePermanent()
+                    .forTable(PUNT_TABLE).build();
+            ops.add(defaultRule);
+            flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
+                @Override
+                public void onSuccess(FlowRuleOperations ops) {
+                    log.info("Initialized table miss flow rule {} on {}", PUNT_TABLE, deviceId);
+                }
+                @Override
+                public void onError(FlowRuleOperations ops) {
+                    log.warn("Failed to initialize table miss flow rule {} on {}", PUNT_TABLE, deviceId);
+                }
+            }));
+            // shutdown the group checker gracefully
+            groupChecker.shutdown();
+        }
+    }
 }