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 19e76e3..2c6b208 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
@@ -92,6 +92,10 @@
     private DeviceConfiguration config;
     private RouteSimplifierUtils routeSimplifierUtils;
 
+    // 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.
      *
@@ -1135,7 +1139,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;
@@ -1155,7 +1159,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);
@@ -1175,6 +1180,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 dbf1280..2ab8a18 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;
@@ -243,6 +245,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).
      *
@@ -258,6 +272,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) {
@@ -337,7 +357,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");
                         }
@@ -352,6 +379,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);
         }