Fixed removal of doubletagged hosts

Change-Id: I3e5fa5da4745f15ab6c84c899f80e7e622ce3583
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
index d00a258..794e68a 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
@@ -93,6 +93,10 @@
     private SegmentRoutingManager srManager;
     private DeviceConfiguration config;
 
+    // used for signalling the driver to remove vlan table and tmac entry also
+    private static final long CLEANUP_DOUBLE_TAGGED_HOST_ENTRIES = 1;
+    private static final long DOUBLE_TAGGED_METADATA_MASK = 0xffffffffffffffffL;
+
     /**
      * Creates a RoutingRulePopulator object.
      *
@@ -1089,7 +1093,7 @@
      */
     void processDoubleTaggedFilter(DeviceId deviceId, PortNumber portNum, VlanId outerVlan,
                                    VlanId innerVlan, boolean install) {
-        FilteringObjective.Builder fob = buildDoubleTaggedFilteringObj(deviceId, portNum, outerVlan, innerVlan);
+        FilteringObjective.Builder fob = buildDoubleTaggedFilteringObj(deviceId, portNum, outerVlan, innerVlan, false);
         if (fob == null) {
             // error encountered during build
             return;
@@ -1109,7 +1113,8 @@
     }
 
     private FilteringObjective.Builder buildDoubleTaggedFilteringObj(DeviceId deviceId, PortNumber portNum,
-                                                                     VlanId outerVlan, VlanId innerVlan) {
+                                                                     VlanId outerVlan, VlanId innerVlan,
+                                                                     boolean cleanupDoubleTaggedRules) {
         MacAddress deviceMac;
         try {
             deviceMac = config.getDeviceMac(deviceId);
@@ -1129,6 +1134,13 @@
         // Pop outer vlan
         tBuilder.popVlan();
 
+        // special metadata for driver
+        if (cleanupDoubleTaggedRules) {
+            tBuilder.writeMetadata(CLEANUP_DOUBLE_TAGGED_HOST_ENTRIES, DOUBLE_TAGGED_METADATA_MASK);
+        } else {
+            tBuilder.writeMetadata(0, DOUBLE_TAGGED_METADATA_MASK);
+        }
+
         // NOTE: Some switch hardware share the same filtering flow among different ports.
         //       We use this metadata to let the driver know that there is no more enabled port
         //       within the same VLAN on this device.
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa3Pipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa3Pipeline.java
index 13fe2b1..39604ae 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa3Pipeline.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa3Pipeline.java
@@ -38,6 +38,7 @@
 import org.onosproject.net.flow.FlowRule;
 import org.onosproject.net.flow.FlowRuleOperations;
 import org.onosproject.net.flow.FlowRuleOperationsContext;
+import org.onosproject.net.flow.IndexTableId;
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
 import org.onosproject.net.flow.criteria.Criteria;
@@ -47,6 +48,7 @@
 import org.onosproject.net.flow.criteria.TunnelIdCriterion;
 import org.onosproject.net.flow.criteria.VlanIdCriterion;
 import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.Instructions;
 import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
 import org.onosproject.net.flow.instructions.L2ModificationInstruction;
 import org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType;
@@ -242,6 +244,18 @@
     }
 
     /**
+     *
+     * @param meta The metadata instruction of this treatment
+     * @return True if we should remove both VLAN and Mac Termination flow entries.
+     *         This is only used for double tagged hosts.
+     */
+    public boolean shouldRemoveDoubleTagged(Instruction meta) {
+
+        Instructions.MetadataInstruction metadataInstruction = (Instructions.MetadataInstruction) meta;
+        return ((metadataInstruction.metadata() & metadataInstruction.metadataMask()) == 1);
+    }
+
+    /**
      * Configure filtering rules of outer and inner VLAN IDs, and a MAC address.
      * Filtering happens in three tables (VLAN_TABLE, VLAN_1_TABLE, TMAC_TABLE).
      *
@@ -257,6 +271,12 @@
         VlanIdCriterion innervidCriterion = null;
         VlanIdCriterion outerVidCriterion = null;
         boolean popVlan = false;
+        boolean removeDoubleTagged = true;
+        if (filteringObjective.meta().writeMetadata() != null) {
+            removeDoubleTagged = shouldRemoveDoubleTagged(filteringObjective.meta().writeMetadata());
+        }
+        log.info("HERE , removeDoubleTagged {}", removeDoubleTagged);
+
         TrafficTreatment meta = filteringObjective.meta();
         if (!filteringObjective.key().equals(Criteria.dummy()) &&
                 filteringObjective.key().type() == Criterion.Type.IN_PORT) {
@@ -336,7 +356,14 @@
                         if (matchInPortTmacTable()
                                 || (filteringObjective.meta() != null
                                 && filteringObjective.meta().clearedDeferred())) {
-                            ops = ops.remove(flowRule);
+
+                            // if metadata instruction not null and not removeDoubleTagged move on.
+                            if ((filteringObjective.meta().writeMetadata() != null) && (!removeDoubleTagged)) {
+                                log.info("Skipping removal of tmac rule for device {}", deviceId);
+                                continue;
+                            } else {
+                                ops = ops.remove(flowRule);
+                            }
                         } else {
                             log.debug("Abort TMAC flow removal on {}. Some other ports still share this TMAC flow");
                         }
@@ -351,6 +378,12 @@
         for (FlowRule flowRule : rules) {
             log.trace("{} flow rule in VLAN table: {} for dev: {}",
                       (install) ? "adding" : "removing", flowRule, deviceId);
+            // if context is remove, table is vlan_1 and removeDoubleTagged is false, continue.
+            if (flowRule.table().equals(IndexTableId.of(VLAN_TABLE)) &&
+                    !removeDoubleTagged && !install) {
+                log.info("Skipping removal of vlan table rule for now!");
+                continue;
+            }
             ops = install ? ops.add(flowRule) : ops.remove(flowRule);
         }