VOL-4736 : oltapp unable to remove fttb flows on port down as learnt mac address is lost

Change-Id: Ibfc704af33d134538512b250c719727ec6a19522
diff --git a/impl/src/main/java/org/opencord/olt/impl/OltFlowService.java b/impl/src/main/java/org/opencord/olt/impl/OltFlowService.java
index 04ea492..7a1cdc7 100644
--- a/impl/src/main/java/org/opencord/olt/impl/OltFlowService.java
+++ b/impl/src/main/java/org/opencord/olt/impl/OltFlowService.java
@@ -231,6 +231,13 @@
     private final Lock provisionedSubscribersReadLock = provisionedSubscribersLock.readLock();
 
     /**
+     * For storing the mapping of ConnectPoints to FTTB DPU MAC addresses.
+     */
+    protected Map<ConnectPoint, MacAddress> fttbMacAddresses;
+    private final ReentrantReadWriteLock fttbMacAddressesLock = new ReentrantReadWriteLock();
+    private final Lock fttbMacAddressesWriteLock = fttbMacAddressesLock.writeLock();
+
+    /**
      * Create DHCP trap flow on NNI port(s).
      */
     protected boolean enableDhcpOnNni = ENABLE_DHCP_ON_NNI_DEFAULT;
@@ -305,6 +312,18 @@
                 .withSerializer(Serializer.using(serializer))
                 .build().asJavaMap();
 
+        KryoNamespace fttbMacSerializer = KryoNamespace.newBuilder()
+                .register(KryoNamespaces.API)
+                .register(ConnectPoint.class)
+                .register(MacAddress.class)
+                .build();
+
+        fttbMacAddresses = storageService.<ConnectPoint, MacAddress>consistentMapBuilder()
+                .withName("fttb-mac-addresses")
+                .withApplicationId(appId)
+                .withSerializer(Serializer.using(fttbMacSerializer))
+                .build().asJavaMap();
+
         flowRuleService.addListener(internalFlowListener);
 
         log.info("Started");
@@ -1824,8 +1843,10 @@
         VlanId innerVlan = null;
         treatmentBuilder.setOutput(nniPort.number());
         if (serviceName.equals(FTTB_SERVICE_DPU_MGMT_TRAFFIC) || serviceName.equals(FTTB_SERVICE_DPU_ANCP_TRAFFIC)) {
+            fttbMacAddressesWriteLock.lock();
             MacAddress mac = FttbUtils.getMacAddressFromDhcpEnabledUti(
-                    hostService, si, deviceId, port);
+                    hostService, si, deviceId, port, fttbMacAddresses);
+            fttbMacAddressesWriteLock.unlock();
 
             if (mac == null) {
                 log.error("Mac address not found port:{}, vlan:{}, service:{}",
@@ -1884,8 +1905,10 @@
         VlanId innerVlan = null;
 
         if (serviceName.equals(FTTB_SERVICE_DPU_MGMT_TRAFFIC) || serviceName.equals(FTTB_SERVICE_DPU_ANCP_TRAFFIC)) {
+            fttbMacAddressesWriteLock.lock();
             MacAddress mac = FttbUtils.getMacAddressFromDhcpEnabledUti(
-                    hostService, si, deviceId, port);
+                    hostService, si, deviceId, port, fttbMacAddresses);
+            fttbMacAddressesWriteLock.unlock();
 
             if (mac == null) {
                 log.error("Mac address not found port:{}, vlan:{}, service:{}",
@@ -1951,4 +1974,4 @@
             flowObjectiveService.forward(deviceId, flow);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/impl/src/main/java/org/opencord/olt/impl/fttb/FttbUtils.java b/impl/src/main/java/org/opencord/olt/impl/fttb/FttbUtils.java
index 1ffb732..9ce0181 100644
--- a/impl/src/main/java/org/opencord/olt/impl/fttb/FttbUtils.java
+++ b/impl/src/main/java/org/opencord/olt/impl/fttb/FttbUtils.java
@@ -31,6 +31,7 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.Map;
 import java.util.Optional;
 
 /**
@@ -158,24 +159,36 @@
     /**
      * Returns mac address from the Dhcp Enabled UniTagInformation for a FTTB service.
      *
-     * @param hostService   Service for interacting with the inventory of end-station hosts
-     * @param si            Information about a subscriber
-     * @param deviceId      Device id for mac lookup.
-     * @param port          Uni port on the device for mac lookup.
+     * @param hostService    Service for interacting with the inventory of end-station hosts
+     * @param si             Information about a subscriber
+     * @param deviceId       Device id for mac lookup.
+     * @param port           Uni port on the device for mac lookup.
+     * @param localAddresses Map of the addresses that this app has locally
      * @return Mac address of the subscriber.
      */
     public static MacAddress getMacAddressFromDhcpEnabledUti(HostService hostService,
                                                              SubscriberAndDeviceInformation si,
                                                              DeviceId deviceId,
-                                                             Port port) {
+                                                             Port port,
+                                                             Map<ConnectPoint, MacAddress> localAddresses) {
         for (UniTagInformation uniTagInfo : si.uniTagList()) {
             boolean isMacLearningEnabled = uniTagInfo.getEnableMacLearning();
             if (isMacLearningEnabled) {
-                Optional<Host> optHost = hostService.getConnectedHosts(new ConnectPoint(deviceId, port.number()))
+                ConnectPoint cp = new ConnectPoint(deviceId, port.number());
+                Optional<Host> optHost = hostService.getConnectedHosts(cp)
                         .stream().filter(host -> host.vlan().equals(uniTagInfo.getPonSTag())).findFirst();
                 if (optHost.isPresent()) {
-                    if (optHost.get().mac() != null) {
-                        return optHost.get().mac();
+                    MacAddress learntMac = optHost.get().mac();
+                    if (learntMac != null) {
+                        localAddresses.put(cp, learntMac);
+                        log.info("Stored mac {} locally for connectPoint {}", learntMac, cp);
+                        return learntMac;
+                    }
+                } else {
+                    MacAddress localMac = localAddresses.get(new ConnectPoint(deviceId, port.number()));
+                    if (localMac != null) {
+                        log.debug("Returning local mac {} for connectPoint {}", localMac, cp);
+                        return localMac;
                     }
                 }
             } else if (uniTagInfo.getConfiguredMacAddress() != null &&