Adding purgeOnDisconnect feature to delete meters and updating EAPOL trap
flows.

* Calling preSetProperty of componentConfigService for MeterManager
* Remove the meter from programmedMeters map when the device disconnects
* Adding vlanId match criteria to EAPOL trap flows
* Adding c-tag or default vlan to write-metadata instruction value for
EAPOL trap flows
* Change the ONOS dependency to 1.13.9-rc3
* Fixing disable-reenabling ONU issue
* Fixing reboot OLT issue

Change-Id: Icce73e8334925193fa2e63d558814eb3bc836f3d
diff --git a/app/src/main/java/org/opencord/olt/impl/Olt.java b/app/src/main/java/org/opencord/olt/impl/Olt.java
index 13bb9bb..60d9e5d 100644
--- a/app/src/main/java/org/opencord/olt/impl/Olt.java
+++ b/app/src/main/java/org/opencord/olt/impl/Olt.java
@@ -29,6 +29,7 @@
 import java.util.Dictionary;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Optional;
 import java.util.Properties;
 import java.util.Set;
@@ -36,6 +37,7 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
+import java.util.stream.Collectors;
 
 import com.google.common.collect.ImmutableSet;
 import org.apache.felix.scr.annotations.Activate;
@@ -121,6 +123,7 @@
     private static final String APP_NAME = "org.opencord.olt";
 
     private static final short DEFAULT_VLAN = 0;
+    private static final short EAPOL_DEFAULT_VLAN = 4091;
     private static final int DEFAULT_TP_ID = 64;
     private static final String DEFAULT_BP_ID = "Default";
     private static final String ADDITIONAL_VLANS = "additional-vlans";
@@ -225,6 +228,9 @@
         componentConfigService
                 .preSetProperty("org.onosproject.net.flow.impl.FlowRuleManager",
                         "purgeOnDisconnection", "true");
+        componentConfigService
+                .preSetProperty("org.onosproject.net.meter.impl.MeterManager",
+                        "purgeOnDisconnection", "true");
         componentConfigService.registerProperties(getClass());
         programmedSubs = Maps.newConcurrentMap();
         programmedMeters = ConcurrentHashMap.newKeySet();
@@ -340,7 +346,8 @@
 
         //delete Eapol authentication flow with default bandwidth
         //wait until Eapol rule with defaultBpId is removed to install subscriber-based rules
-        processEapolFilteringObjectives(deviceId, subscriberPortNo, defaultBpId, filterFuture, false);
+        processEapolFilteringObjectives(deviceId, subscriberPortNo, defaultBpId, filterFuture,
+                VlanId.vlanId(EAPOL_DEFAULT_VLAN), false);
         removeMeterIdFromBpMapping(deviceId, defaultBpId);
 
         //install subscriber flows
@@ -405,8 +412,9 @@
 
         //re-install eapol
         processEapolFilteringObjectives(deviceId, subscriberPortNo,
-                subscriber.upstreamBandwidthProfile(), null, false);
-        processEapolFilteringObjectives(deviceId, subscriberPortNo, defaultBpId, null, true);
+                subscriber.upstreamBandwidthProfile(), null, subscriber.cTag(), false);
+        processEapolFilteringObjectives(deviceId, subscriberPortNo, defaultBpId,
+                null, VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
 
         programmedSubs.remove(connectPoint);
         return true;
@@ -718,7 +726,7 @@
                 if (upstreamMeterId != null) {
                     //re-install Eapol authentication flow with the subscribers' upstream bandwidth profile
                     processEapolFilteringObjectives(deviceId, subscriberPort, sub.upstreamBandwidthProfile(),
-                            null, true);
+                            null, sub.cTag(), true);
 
                     processDhcpFilteringObjectives(deviceId, subscriberPort,
                             upstreamMeterId, sub.technologyProfileId(), true, true);
@@ -1050,13 +1058,18 @@
     }
 
     /**
-     * Returns the write metadata value including only tech profile reference.
+     * Returns the write metadata value including tech profile reference and innerVlan.
+     * For param cVlan, null can be sent
      *
+     * @param cVlan         c (customer) tag of one subscriber
      * @param techProfileId tech profile id of one subscriber
-     * @return the write metadata value including only tech profile reference
+     * @return the write metadata value including tech profile reference and innerVlan
      */
-    private Long createTechProfValueForWm(int techProfileId) {
-        return (long) techProfileId << 32;
+    private Long createTechProfValueForWm(VlanId cVlan, int techProfileId) {
+        if (cVlan == null) {
+            return (long) techProfileId << 32;
+        }
+        return ((long) (cVlan.id()) << 48 | (long) techProfileId << 32);
     }
 
     /**
@@ -1066,11 +1079,12 @@
      * @param portNumber   the port for which this trap flow is designated
      * @param bpId         bandwidth profile id to add the related meter to the flow
      * @param filterFuture completable future for this filtering objective operation
+     * @param vlanId       the default or customer tag for a subscriber
      * @param install      true to install the flow, false to remove the flow
      */
     private void processEapolFilteringObjectives(DeviceId devId, PortNumber portNumber, String bpId,
                                                  CompletableFuture<ObjectiveError> filterFuture,
-                                                 boolean install) {
+                                                 VlanId vlanId, boolean install) {
 
         if (!enableEapol) {
             log.debug("Eapol filtering is disabled.");
@@ -1107,8 +1121,9 @@
                 FilteringObjective eapol = (install ? builder.permit() : builder.deny())
                         .withKey(Criteria.matchInPort(portNumber))
                         .addCondition(Criteria.matchEthType(EthType.EtherType.EAPOL.ethType()))
+                        .addCondition(Criteria.matchVlanId(vlanId))
                         .withMeta(treatmentBuilder
-                                .writeMetadata(createTechProfValueForWm(techProfileId), 0)
+                                .writeMetadata(createTechProfValueForWm(vlanId, techProfileId), 0)
                                 .setOutput(PortNumber.CONTROLLER).build())
                         .fromApp(appId)
                         .withPriority(10000)
@@ -1258,7 +1273,7 @@
         }
 
         if (techProfileId != -1) {
-            treatmentBuilder.writeMetadata(createTechProfValueForWm(techProfileId), 0);
+            treatmentBuilder.writeMetadata(createTechProfValueForWm(null, techProfileId), 0);
         }
 
         FilteringObjective dhcpUpstream = (install ? builder.permit() : builder.deny())
@@ -1313,7 +1328,7 @@
         }
 
         if (techProfileId != -1) {
-            treatmentBuilder.writeMetadata(createTechProfValueForWm(techProfileId), 0);
+            treatmentBuilder.writeMetadata(createTechProfValueForWm(null, techProfileId), 0);
         }
 
         builder = install ? builder.permit() : builder.deny();
@@ -1363,7 +1378,8 @@
             // This is an OLT device as per Sadis, we create flows for UNI and NNI ports
             for (Port p : deviceService.getPorts(dev.id())) {
                 if (isUniPort(dev, p)) {
-                    processEapolFilteringObjectives(dev.id(), p.number(), defaultBpId, null, true);
+                    processEapolFilteringObjectives(dev.id(), p.number(), defaultBpId, null,
+                            VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
                 } else {
                     processNniFilteringObjectives(dev.id(), p.number(), true);
                 }
@@ -1519,7 +1535,7 @@
 
                             if (port.isEnabled()) {
                                 processEapolFilteringObjectives(devId, port.number(), defaultBpId,
-                                        null, true);
+                                        null, VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
                             }
                         } else {
                             checkAndCreateDeviceFlows(dev);
@@ -1528,10 +1544,6 @@
                     case PORT_REMOVED:
                         if (isUniPort(dev, port)) {
                             if (port.isEnabled()) {
-                                processEapolFilteringObjectives(devId, port.number(),
-                                        getCurrentBandwidthProfile(new ConnectPoint(devId, port.number())),
-                                        null, false);
-
                                 removeSubscriber(new ConnectPoint(devId, port.number()));
                             }
 
@@ -1544,15 +1556,20 @@
                             break;
                         }
 
+                        SubscriberAndDeviceInformation sub = programmedSubs
+                                .get(new ConnectPoint(devId, port.number()));
+                        VlanId vlanId = sub == null ? VlanId.vlanId(EAPOL_DEFAULT_VLAN) : sub.cTag();
+
+                        String bpId = getCurrentBandwidthProfile(new ConnectPoint(devId, port.number()));
+
                         if (port.isEnabled()) {
-                            processEapolFilteringObjectives(devId, port.number(), defaultBpId,
-                                    null, true);
+                            processEapolFilteringObjectives(devId, port.number(), bpId,
+                                    null, vlanId, true);
 
                             post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, port));
                         } else {
-                            processEapolFilteringObjectives(devId, port.number(),
-                                    getCurrentBandwidthProfile(new ConnectPoint(devId, port.number())),
-                                    null, false);
+                            processEapolFilteringObjectives(devId, port.number(), bpId,
+                                    null, vlanId, false);
                             post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, port));
                         }
                         break;
@@ -1576,6 +1593,7 @@
                                 .forEach(p -> post(new AccessDeviceEvent(
                                         AccessDeviceEvent.Type.UNI_REMOVED, devId, p)));
                         programmedDevices.remove(devId);
+                        removeAllSubscribers(devId);
                         post(new AccessDeviceEvent(
                                 AccessDeviceEvent.Type.DEVICE_DISCONNECTED, devId,
                                 null, null));
@@ -1585,10 +1603,11 @@
                             post(new AccessDeviceEvent(
                                     AccessDeviceEvent.Type.DEVICE_CONNECTED, devId,
                                     null, null));
-                        programmedDevices.add(devId);
+                            programmedDevices.add(devId);
                             checkAndCreateDeviceFlows(dev);
                         } else {
-                        programmedDevices.remove(devId);
+                            programmedDevices.remove(devId);
+                            removeAllSubscribers(devId);
                             post(new AccessDeviceEvent(
                                     AccessDeviceEvent.Type.DEVICE_DISCONNECTED, devId,
                                     null, null));
@@ -1610,6 +1629,14 @@
             }
             return defaultBpId;
         }
+
+        private void removeAllSubscribers(DeviceId deviceId) {
+            List<ConnectPoint> connectPoints = programmedSubs.keySet().stream()
+                    .filter(ks -> Objects.equals(ks.deviceId(), deviceId))
+                    .collect(Collectors.toList());
+
+            connectPoints.forEach(cp -> programmedSubs.remove(cp));
+        }
     }
 
     private class InternalMeterListener implements MeterListener {
@@ -1650,6 +1677,7 @@
                             && meterKey.meterId().equals(meter.id())).findFirst().
                             ifPresent(mk -> {
                                 meterKeys.remove(mk);
+                                programmedMeters.remove(mk);
                                 log.info("Deleted from the internal map. MeterKey {}", mk);
                                 log.info("Programmed meters {}", programmedMeters);
                             }));
diff --git a/pom.xml b/pom.xml
index d0574ec..8ea7eae 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.onosproject</groupId>
         <artifactId>onos-dependencies</artifactId>
-        <version>1.13.9-rc2</version>
+        <version>1.13.9-rc3</version>
         <relativePath></relativePath>
     </parent>
 
@@ -33,7 +33,7 @@
 
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-        <onos.version>1.13.9-rc2</onos.version>
+        <onos.version>1.13.9-rc3</onos.version>
     </properties>
 
     <modules>