Updated L2Gw changes in "neutronvpn", "elanmanager" and "dhcpservice" modules 32/38332/2
authorShashidhar R <shashidhar.raja@ericsson.com>
Tue, 3 May 2016 12:59:19 +0000 (18:29 +0530)
committerShashidhar R <shashidhar.raja@ericsson.com>
Wed, 4 May 2016 06:01:15 +0000 (11:31 +0530)
- Used entity ownership service to handle l2gw requests only in one cluster node.
- Registered for entity ownership for elan entity to process all the l2gw requests.
- Taken out the datastore jobcoordinator jobs into separate classes.
- Handled external tunnel state events.

Change-Id: I39a2a24c8927e48fc7d0299de008cfff9ca6d2b4
Signed-off-by: Shashidhar R <shashidhar.raja@ericsson.com>
53 files changed:
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpConfigListener.java
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpDesignatedDpnListener.java
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpExternalTunnelManager.java
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpInterfaceEventListener.java
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpL2GatewayConnectionListener.java
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpLogicalSwitchListener.java
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpServiceUtils.java
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpUCastMacListener.java
elanmanager/elanmanager-api/src/main/java/org/opendaylight/elanmanager/utils/ElanL2GwCacheUtils.java
elanmanager/elanmanager-impl/pom.xml
elanmanager/elanmanager-impl/src/main/config/default-config.xml
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/cli/l2gw/L2GwUtilsCacheCli.java
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanDpnInterfaceClusteredListener.java [new file with mode: 0644]
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInstanceManager.java
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceAddWorker.java [new file with mode: 0644]
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceManager.java
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceRemoveWorker.java [new file with mode: 0644]
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceStateChangeListener.java
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceStateClusteredListener.java [new file with mode: 0644]
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanPacketInHandler.java
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanServiceProvider.java
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/internal/ElanL2GatewayProvider.java
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/AssociateHwvtepToElanJob.java [new file with mode: 0644]
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/DeleteL2GwDeviceMacsFromElanJob.java [new file with mode: 0644]
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/DisAssociateHwvtepFromElanJob.java [new file with mode: 0644]
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/HwvtepDeviceMcastMacUpdateJob.java [new file with mode: 0644]
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/LogicalSwitchAddedJob.java [new file with mode: 0644]
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/LogicalSwitchDeletedJob.java [new file with mode: 0644]
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepLocalUcastMacListener.java
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepLogicalSwitchListener.java
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepNodeListener.java
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepPhysicalLocatorListener.java [new file with mode: 0644]
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepRemoteMcastMacListener.java
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/L2GatewayConnectionListener.java
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/utils/ElanL2GatewayMulticastUtils.java
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/utils/ElanL2GatewayUtils.java
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/utils/L2GatewayConnectionUtils.java
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/utils/ElanClusterUtils.java [new file with mode: 0644]
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/utils/ElanConstants.java
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/utils/ElanUtils.java
elanmanager/elanmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/elanservice/impl/rev150216/ElanServiceImplModule.java
elanmanager/elanmanager-impl/src/main/yang/elanservice-impl.yang
mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/clustering/ClusteringUtils.java
mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/clustering/EntityOwnerUtils.java [new file with mode: 0644]
mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/hwvtep/HwvtepSouthboundConstants.java
mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/hwvtep/HwvtepSouthboundUtils.java
mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/hwvtep/HwvtepUtils.java
neutronvpn/neutronvpn-impl/src/main/config/default-config.xml
neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/NeutronvpnProvider.java
neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/l2gw/L2GatewayListener.java
neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/l2gw/L2GatewayProvider.java
neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/neutronvpn/impl/rev150325/NeutronvpnImplModule.java
neutronvpn/neutronvpn-impl/src/main/yang/neutronvpn-impl.yang

index 2d187055ac88bcdb7d548941eb7e24dab6065c6e..2fa8448a9740d8f717b461961cd96551d43b0b6e 100644 (file)
@@ -8,17 +8,15 @@
 package org.opendaylight.vpnservice.dhcpservice;
 
 import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
-
-import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.dhcp.config.Configs;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
-import org.opendaylight.vpnservice.datastoreutils.AsyncDataChangeListenerBase;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.DhcpConfig;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
 import org.opendaylight.vpnservice.dhcpservice.api.DHCPMConstants;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.DhcpConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.dhcp.config.Configs;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
index 838cc46867863d5d2ddf30333f6254b3975b5ba4..27de14d789e00ce3ec1682b55b4d074fbc0a275e 100644 (file)
@@ -64,10 +64,10 @@ public class DhcpDesignatedDpnListener extends AsyncClusteredDataChangeListenerB
         String elanInstanceName = update.getElanInstanceName();
         dhcpExternalTunnelManager.removeFromLocalCache(BigInteger.valueOf(original.getDpId()), original.getTunnelRemoteIpAddress(), original.getElanInstanceName());
         dhcpExternalTunnelManager.updateLocalCache(designatedDpnId, tunnelRemoteIpAddress, elanInstanceName);
-/*        List<BigInteger> elanDpns = DhcpServiceUtils.getDpnsForElan(elanInstanceName, broker);
+        List<BigInteger> elanDpns = DhcpServiceUtils.getDpnsForElan(elanInstanceName, broker);
         if (elanDpns == null || elanDpns.isEmpty()) {
             dhcpExternalTunnelManager.installRemoteMcastMac(designatedDpnId, tunnelRemoteIpAddress, elanInstanceName);
-        }*/
+        }
     }
 
     @Override
@@ -76,10 +76,10 @@ public class DhcpDesignatedDpnListener extends AsyncClusteredDataChangeListenerB
         IpAddress tunnelRemoteIpAddress = add.getTunnelRemoteIpAddress();
         String elanInstanceName = add.getElanInstanceName();
         dhcpExternalTunnelManager.updateLocalCache(designatedDpnId, tunnelRemoteIpAddress, elanInstanceName);
-/*        List<BigInteger> elanDpns = DhcpServiceUtils.getDpnsForElan(elanInstanceName, broker);
+        List<BigInteger> elanDpns = DhcpServiceUtils.getDpnsForElan(elanInstanceName, broker);
         if (elanDpns == null || elanDpns.isEmpty()) {
             dhcpExternalTunnelManager.installRemoteMcastMac(designatedDpnId, tunnelRemoteIpAddress, elanInstanceName);
-        }*/
+        }
     }
 
     @Override
index b51c8342b889efb77d0bd82b809d5113078632c5..79e34826d7af148c54a93a3e82635c3524dff3ad 100644 (file)
@@ -34,6 +34,7 @@ import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
 import org.opendaylight.vpnservice.neutronvpn.api.l2gw.utils.L2GatewayCacheUtils;
 import org.opendaylight.vpnservice.neutronvpn.api.utils.NeutronUtils;
 import org.opendaylight.vpnservice.utils.clustering.ClusteringUtils;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundConstants;
 import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundUtils;
 import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
@@ -57,6 +58,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.d
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnelBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnelKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeVxlan;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetExternalTunnelInterfaceNameInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetExternalTunnelInterfaceNameOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
@@ -336,9 +339,6 @@ public class DhcpExternalTunnelManager {
                     designatedDpnId = dpn;
                 }
             }
-            if (!elanDpnAvailableFlag) {
-                installRemoteMcastMac(designatedDpnId, device, elanInstanceName);
-            }
             writeDesignatedSwitchForExternalTunnel(designatedDpnId, tunnelIp, elanInstanceName);
             return designatedDpnId;
         }
@@ -357,7 +357,8 @@ public class DhcpExternalTunnelManager {
     public void installDhcpEntries(final BigInteger dpnId, final String vmMacAddress, EntityOwnershipService eos) {
         final String nodeId = DhcpServiceUtils.getNodeIdFromDpnId(dpnId);
         ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
-                eos, MDSALUtil.NODE_PREFIX, nodeId);
+                eos, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+                HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
         Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
             @Override
             public void onSuccess(Boolean isOwner) {
@@ -382,7 +383,8 @@ public class DhcpExternalTunnelManager {
     public void unInstallDhcpEntries(final BigInteger dpnId, final String vmMacAddress, EntityOwnershipService eos) {
         final String nodeId = DhcpServiceUtils.getNodeIdFromDpnId(dpnId);
         ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
-                eos, MDSALUtil.NODE_PREFIX, nodeId);
+                eos, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+                HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
         Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
             @Override
             public void onSuccess(Boolean isOwner) {
@@ -407,7 +409,8 @@ public class DhcpExternalTunnelManager {
     public void installDhcpDropAction(final BigInteger dpnId, final String vmMacAddress, EntityOwnershipService eos) {
         final String nodeId = DhcpServiceUtils.getNodeIdFromDpnId(dpnId);
         ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
-                eos, MDSALUtil.NODE_PREFIX, nodeId);
+                eos, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+                HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
         Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
             @Override
             public void onSuccess(Boolean isOwner) {
@@ -511,10 +514,11 @@ public class DhcpExternalTunnelManager {
 
     public String getExternalTunnelInterfaceName(String sourceNode, String dstNode) {
         String tunnelInterfaceName = null;
+        Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
         try {
             Future<RpcResult<GetExternalTunnelInterfaceNameOutput>> output = itmRpcService
                     .getExternalTunnelInterfaceName(new GetExternalTunnelInterfaceNameInputBuilder()
-                            .setSourceNode(sourceNode).setDestinationNode(dstNode).build());
+                            .setSourceNode(sourceNode).setDestinationNode(dstNode).setTunnelType(tunType).build());
 
             RpcResult<GetExternalTunnelInterfaceNameOutput> rpcResult = output.get();
             if (rpcResult.isSuccessful()) {
@@ -569,22 +573,42 @@ public class DhcpExternalTunnelManager {
         return transaction;
     }
 
-    private void installRemoteMcastMac(BigInteger designatedDpnId, L2GatewayDevice device, String elanInstanceName) {
-        String tunnelInterfaceName = getExternalTunnelInterfaceName(String.valueOf(designatedDpnId), device.getHwvtepNodeId());
-        IpAddress internalTunnelIp = null;
-        if (tunnelInterfaceName != null) {
-            Interface tunnelInterface = DhcpServiceUtils.getInterfaceFromConfigDS(tunnelInterfaceName, broker);
-            if (tunnelInterface == null) {
-                logger.debug("Tunnel Interface is not present {}", tunnelInterfaceName);
-                return;
+    public void installRemoteMcastMac(final BigInteger designatedDpnId, final IpAddress tunnelIp, final String elanInstanceName) {
+        if (designatedDpnId.equals(DHCPMConstants.INVALID_DPID)) {
+            return;
+        }
+        ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(entityOwnershipService, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE, HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
+        Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
+            @Override
+            public void onSuccess(Boolean isOwner) {
+                if (isOwner) {
+                    logger.info("Installing remote McastMac");
+                    L2GatewayDevice device = getDeviceFromTunnelIp(elanInstanceName, tunnelIp);
+                    String tunnelInterfaceName = getExternalTunnelInterfaceName(String.valueOf(designatedDpnId), device.getHwvtepNodeId());
+                    IpAddress internalTunnelIp = null;
+                    if (tunnelInterfaceName != null) {
+                        Interface tunnelInterface = DhcpServiceUtils.getInterfaceFromConfigDS(tunnelInterfaceName, broker);
+                        if (tunnelInterface == null) {
+                            logger.trace("Tunnel Interface is not present {}", tunnelInterfaceName);
+                            return;
+                        }
+                        internalTunnelIp = tunnelInterface.getAugmentation(IfTunnel.class).getTunnelSource();
+                        WriteTransaction transaction = broker.newWriteOnlyTransaction();
+                        putRemoteMcastMac(transaction, elanInstanceName, device, internalTunnelIp);
+                        if (transaction != null) {
+                            transaction.submit();
+                        }
+                    }
+                } else {
+                      logger.info("Installing remote McastMac is not executed for this node.");
+                }
             }
-            internalTunnelIp = tunnelInterface.getAugmentation(IfTunnel.class).getTunnelSource();
-            WriteTransaction transaction = broker.newWriteOnlyTransaction();
-            putRemoteMcastMac(transaction, elanInstanceName, device, internalTunnelIp);
-            if (transaction != null) {
-                transaction.submit();
+
+            @Override
+            public void onFailure(Throwable error) {
+                logger.error("Failed to install remote McastMac", error);
             }
-        }
+        });
     }
 
     private L2GatewayDevice getDeviceFromTunnelIp(String elanInstanceName, IpAddress tunnelIp) {
index 199db9136be5478683dc9210f6ad55845c1992a6..3550156fcca16bff3b527f6b81ceb3e7af86e2fa 100644 (file)
@@ -23,7 +23,6 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.re
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
@@ -161,15 +160,6 @@ public class DhcpInterfaceEventListener extends AbstractDataChangeListener<Inter
             }
             return;
         }
-        if (update.getOperStatus() == OperStatus.Down) {
-            unInstallDhcpEntries(interfaceName, dpId);
-            dhcpManager.removeInterfaceCache(interfaceName);
-        } else if (update.getOperStatus() == OperStatus.Up) {
-            if (!dpId.equals(DHCPMConstants.INVALID_DPID)) {
-                installDhcpEntries(interfaceName, dpId);
-                dhcpManager.updateInterfaceCache(interfaceName, new ImmutablePair<BigInteger, String>(dpId, update.getPhysAddress().getValue()));
-            }
-        }
     }
 
     @Override
index 6ba17767dc2667928ceb7715d674d81428bf59a8..7118c723de5b77439234929e33829e7f32a00368 100644 (file)
@@ -58,20 +58,13 @@ public class DhcpL2GatewayConnectionListener extends AsyncClusteredDataChangeLis
                 .child(L2gateway.class, new L2gatewayKey(gatewayId));
         Optional<L2gateway> l2Gateway = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, inst);
         if (!l2Gateway.isPresent()) {
+            logger.trace("L2Gw not present id {}", gatewayId);
             return;
         }
         Uuid networkUuid = del.getNetworkId();
-        boolean isLastConnection = true;
-        InstanceIdentifier<L2gatewayConnections> l2gatewayConnectionIdentifier = InstanceIdentifier.create(Neutron.class).child(L2gatewayConnections.class);
-        Optional<L2gatewayConnections> l2GwConnection = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, l2gatewayConnectionIdentifier);
-        List<L2gatewayConnection> l2GatewayConnectionList = l2GwConnection.get().getL2gatewayConnection();
-        for (L2gatewayConnection l2gatewayConnection : l2GatewayConnectionList) {
-            if (networkUuid.equals(l2gatewayConnection.getNetworkId())) {
-                isLastConnection = false;
-                break;
-            }
-        }
+        boolean isLastConnection = isLastGatewayConnection(networkUuid);
         if (!isLastConnection) {
+            logger.trace("Not the last L2GatewayConnection. Not removing flows.");
             return;
         }
         List<Devices> l2Devices = l2Gateway.get().getDevices();
@@ -88,6 +81,20 @@ public class DhcpL2GatewayConnectionListener extends AsyncClusteredDataChangeLis
         }
     }
 
+    private boolean isLastGatewayConnection(Uuid networkUuid) {
+        boolean isLastConnection = true;
+        InstanceIdentifier<L2gatewayConnections> l2gatewayConnectionIdentifier = InstanceIdentifier.create(Neutron.class).child(L2gatewayConnections.class);
+        Optional<L2gatewayConnections> l2GwConnection = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, l2gatewayConnectionIdentifier);
+        List<L2gatewayConnection> l2GatewayConnectionList = l2GwConnection.get().getL2gatewayConnection();
+        for (L2gatewayConnection l2gatewayConnection : l2GatewayConnectionList) {
+            if (networkUuid.equals(l2gatewayConnection.getNetworkId())) {
+                isLastConnection = false;
+                break;
+            }
+        }
+        return isLastConnection;
+    }
+
     @Override
     protected void update(InstanceIdentifier<L2gatewayConnection> identifier,
             L2gatewayConnection original, L2gatewayConnection update) {
index 5f4661162e47221d8ee0c160bf9505e449d8a91c..fef7085d39d419e6d2d4bd05d20c09d44a828a4d 100644 (file)
@@ -132,7 +132,7 @@ public class DhcpLogicalSwitchListener extends AbstractDataChangeListener<Logica
         BigInteger designatedDpnId;
         designatedDpnId = dhcpExternalTunnelManager.readDesignatedSwitchesForExternalTunnel(tunnelIp, elanInstanceName);
         if (designatedDpnId == null || designatedDpnId.equals(DHCPMConstants.INVALID_DPID)) {
-            logger.error("Could not find designated DPN ID");
+            logger.info("Could not find designated DPN ID");
             return;
         }
         dhcpExternalTunnelManager.removeDesignatedSwitchForExternalTunnel(designatedDpnId, tunnelIp, elanInstanceName);
@@ -143,7 +143,7 @@ public class DhcpLogicalSwitchListener extends AbstractDataChangeListener<Logica
         BigInteger designatedDpnId;
         designatedDpnId = dhcpExternalTunnelManager.designateDpnId(tunnelIp, elanInstanceName, dpns);
         if (designatedDpnId == null || designatedDpnId.equals(DHCPMConstants.INVALID_DPID)) {
-            logger.error("Unable to designate a DPN");
+            logger.info("Unable to designate a DPN");
             return;
         }
     }
index c6fd549221261fa27daba380815468f7bae552f0..b925646fcdbb5e0fd4a953f1ad86ad93a723f7e1 100644 (file)
@@ -126,13 +126,13 @@ public class DhcpServiceUtils {
                     getDhcpFlowRef(dpId, tableId, vmMacAddress),
                     DHCPMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0,
                     DHCPMConstants.COOKIE_DHCP_BASE, matches, null);
-            logger.trace("Removing DHCP Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
+            logger.trace("Removing DHCP Drop Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
             mdsalUtil.removeFlow(flowEntity);
         } else {
             FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
                     getDhcpFlowRef(dpId, tableId, vmMacAddress),DHCPMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0,
                     DHCPMConstants.COOKIE_DHCP_BASE, matches, instructions);
-            logger.trace("Installing DHCP Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
+            logger.trace("Installing DHCP Drop Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
             mdsalUtil.installFlow(flowEntity);
         }
     }
index 472414eca8bcea1233c99008f045b9cdc3f2b8a4..5d967e56e0edcd3e32d76f2db297383d7a9a5d71 100644 (file)
@@ -19,6 +19,7 @@ import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListen
 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
 import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LocalUcastMacs;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
@@ -90,6 +91,13 @@ public class DhcpUCastMacListener extends AsyncClusteredDataChangeListenerBase<L
         }
         LogicalSwitches logicalSwitch = logicalSwitchOptional.get();
         String elanInstanceName = logicalSwitch.getHwvtepNodeName().getValue();
+        String macAddress = add.getMacEntryKey().getValue();
+        BigInteger vni = new BigInteger(logicalSwitch.getTunnelKey());
+        Port port = dhcpExternalTunnelManager.readVniMacToPortCache(vni, macAddress);
+        if (port == null) {
+            logger.trace("No neutron port created for macAddress {}, tunnelKey {}", macAddress, vni);
+            return;
+        }
         L2GatewayDevice device = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanInstanceName, torNodeId.getValue());
         if (device == null) {
             logger.error("Logical Switch Device with name {} is not present in L2GWCONN cache", elanInstanceName);
@@ -97,7 +105,7 @@ public class DhcpUCastMacListener extends AsyncClusteredDataChangeListenerBase<L
         }
         IpAddress tunnelIp = device.getTunnelIp();
         BigInteger designatedDpnId = dhcpExternalTunnelManager.readDesignatedSwitchesForExternalTunnel(tunnelIp, elanInstanceName);
-        dhcpExternalTunnelManager.installDhcpFlowsForVms(tunnelIp, elanInstanceName, DhcpServiceUtils.getListOfDpns(broker), designatedDpnId, add.getMacEntryKey().getValue());
+        dhcpExternalTunnelManager.installDhcpFlowsForVms(tunnelIp, elanInstanceName, DhcpServiceUtils.getListOfDpns(broker), designatedDpnId, macAddress);
     }
 
     @Override
index 4022cc23f50c76eee4578853ae066eed75fa68b9..3072448f068e2a39d040bca121a9b4a03ee91b8c 100644 (file)
@@ -8,11 +8,10 @@
 
 package org.opendaylight.elanmanager.utils;
 
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 
 import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
 import org.opendaylight.vpnservice.utils.cache.CacheUtil;
@@ -57,32 +56,32 @@ public class ElanL2GwCacheUtils {
     }
 
 
-    public static L2GatewayDevice removeL2GatewayDeviceFromCache(String elanName, String deviceName) {
+    public static L2GatewayDevice removeL2GatewayDeviceFromCache(String elanName, String l2gwDeviceNodeId) {
         ConcurrentMap<String, ConcurrentMap<String, L2GatewayDevice>> cachedMap =
                 (ConcurrentMap<String, ConcurrentMap<String, L2GatewayDevice>>) CacheUtil.getCache(
                         ElanL2GwCacheUtils.L2GATEWAY_CONN_CACHE_NAME);
         ConcurrentMap<String, L2GatewayDevice> deviceMap = cachedMap.get(elanName);
         if (deviceMap != null) {
-            L2GatewayDevice device = deviceMap.remove(deviceName);
+            L2GatewayDevice device = deviceMap.remove(l2gwDeviceNodeId);
             return device;
         } else {
             return null;
         }
     }
 
-    public static L2GatewayDevice getL2GatewayDeviceFromCache(String elanName, String deviceName) {
+    public static L2GatewayDevice getL2GatewayDeviceFromCache(String elanName, String l2gwDeviceNodeId) {
         ConcurrentMap<String, ConcurrentMap<String, L2GatewayDevice>> cachedMap =
                 (ConcurrentMap<String, ConcurrentMap<String, L2GatewayDevice>>) CacheUtil.getCache(
                         ElanL2GwCacheUtils.L2GATEWAY_CONN_CACHE_NAME);
         ConcurrentMap<String, L2GatewayDevice> deviceMap = cachedMap.get(elanName);
         if (deviceMap != null) {
-            return deviceMap.get(deviceName);
+            return deviceMap.get(l2gwDeviceNodeId);
         } else {
             return null;
         }
     }
 
-    public static ConcurrentMap<String, L2GatewayDevice> getAllElanL2GatewayDevicesFromCache(String elanName) {
+    public static ConcurrentMap<String, L2GatewayDevice> getInvolvedL2GwDevices(String elanName) {
         ConcurrentMap<String, ConcurrentMap<String, L2GatewayDevice>> cachedMap = (ConcurrentMap<String, ConcurrentMap<String, L2GatewayDevice>>) CacheUtil
                 .getCache(ElanL2GwCacheUtils.L2GATEWAY_CONN_CACHE_NAME);
         ConcurrentMap<String, L2GatewayDevice> result = cachedMap.get(elanName);
index b7ea5772449886db8e910d4933e08c63d4fec1dd..2fa9b6c9373b93718a1fba09afffe5db9f35495a 100644 (file)
@@ -106,6 +106,22 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
         <version>${powermock.version}</version>
         <scope>test</scope>
     </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>sal-binding-broker-impl</artifactId>
+          <scope>test</scope>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>sal-binding-broker-impl</artifactId>
+          <version>${mdsal.version}</version>
+          <scope>test</scope>
+          <type>test-jar</type>
+      </dependency>
+      <dependency>
+          <groupId>org.slf4j</groupId>
+          <artifactId>slf4j-simple</artifactId>
+          <scope>test</scope>
+      </dependency>
   </dependencies>
-
 </project>
index b34398e2f8d1987d0d41a6b4f9c83fe953e88d70..95ff81072992fd923dbd3d8f8a04fc7620510829 100644 (file)
@@ -52,10 +52,6 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
                         <type xmlns:entity-ownership="urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:entity-ownership-service">entity-ownership:entity-ownership-service</type>
                         <name>entity-ownership-service</name>
                     </entity-ownership-service>
-                    <binding-normalized-node-serializer>
-                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-normalized-node-serializer</type>
-                        <name>runtime-mapping-singleton</name>
-                    </binding-normalized-node-serializer>
                 </module>
             </modules>
             <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
index f9954043b0f33105a9acfe2b8db1ae9e68ab34ee..d08347b7a47d5069d23544e74676e930cd99ec35 100644 (file)
@@ -85,7 +85,7 @@ public class L2GwUtilsCacheCli extends OsgiCommandSupport {
             return;
         }
         ConcurrentMap<String, L2GatewayDevice> elanDevices = ElanL2GwCacheUtils
-                .getAllElanL2GatewayDevicesFromCache(elanName);
+                .getInvolvedL2GwDevices(elanName);
         print(elanName, elanDevices);
     }
 
diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanDpnInterfaceClusteredListener.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanDpnInterfaceClusteredListener.java
new file mode 100644 (file)
index 0000000..3260581
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.vpnservice.elan.internal;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.vpnservice.elan.utils.ElanClusterUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanDpnInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class ElanDpnInterfaceClusteredListener
+        extends AsyncClusteredDataChangeListenerBase<DpnInterfaces, ElanDpnInterfaceClusteredListener>
+        implements AutoCloseable {
+    private DataBroker broker;
+    private ElanInterfaceManager elanInterfaceManager;
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+
+    private static final Logger LOG = LoggerFactory.getLogger(ElanDpnInterfaceClusteredListener.class);
+
+    public ElanDpnInterfaceClusteredListener(final DataBroker db, final ElanInterfaceManager ifManager) {
+        super(DpnInterfaces.class, ElanDpnInterfaceClusteredListener.class);
+        broker = db;
+        elanInterfaceManager = ifManager;
+        registerListener(db);
+    }
+
+    private void registerListener(final DataBroker db) {
+        try {
+            listenerRegistration = broker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+                    getWildCardPath(), ElanDpnInterfaceClusteredListener.this, AsyncDataBroker.DataChangeScope.BASE);
+        } catch (final Exception e) {
+            LOG.error("DpnInterfaces DataChange listener registration fail!", e);
+        }
+    }
+
+    @Override
+    public InstanceIdentifier<DpnInterfaces> getWildCardPath() {
+        return InstanceIdentifier.builder(ElanDpnInterfaces.class).child(ElanDpnInterfacesList.class)
+                .child(DpnInterfaces.class).build();
+    }
+
+    @Override
+    protected ClusteredDataChangeListener getDataChangeListener() {
+        return ElanDpnInterfaceClusteredListener.this;
+    }
+
+    @Override
+    protected AsyncDataBroker.DataChangeScope getDataChangeScope() {
+        return AsyncDataBroker.DataChangeScope.BASE;
+    }
+
+    void handleUpdate(InstanceIdentifier<DpnInterfaces> id, DpnInterfaces dpnInterfaces) {
+        final String elanName = getElanName(id);
+        if (ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName).isEmpty()) {
+            LOG.debug("dpnInterface updation, no external l2 devices to update for elan {} with Dp Id:", elanName,
+                    dpnInterfaces.getDpId());
+            return;
+        }
+        ElanClusterUtils.runOnlyInLeaderNode(elanName, "updating mcast mac upon tunnel event",
+                new Callable<List<ListenableFuture<Void>>>() {
+                    @Override
+                    public List<ListenableFuture<Void>> call() throws Exception {
+                        return Lists.newArrayList(
+                                ElanL2GatewayMulticastUtils.updateRemoteMcastMacOnElanL2GwDevices(elanName));
+                    }
+                });
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<DpnInterfaces> identifier, final DpnInterfaces dpnInterfaces) {
+        // this is the last dpn interface on this elan
+        final String elanName = getElanName(identifier);
+        LOG.debug("Received ElanDpnInterface removed for for elan {} with Dp Id ", elanName,
+                dpnInterfaces.getDpId());
+
+        if (ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName).isEmpty()) {
+            LOG.debug("dpnInterface removed, no external l2 devices to update for elan {} with Dp Id:", elanName,
+                    dpnInterfaces.getDpId());
+            return;
+        }
+        ElanClusterUtils.runOnlyInLeaderNode(elanName, "handling ElanDpnInterface removed",
+                new Callable<List<ListenableFuture<Void>>>() {
+                    @Override
+                    public List<ListenableFuture<Void>> call() throws Exception {
+                        // deleting Elan L2Gw Devices UcastLocalMacs From Dpn
+                        ElanL2GatewayUtils.deleteElanL2GwDevicesUcastLocalMacsFromDpn(elanName,
+                                dpnInterfaces.getDpId());
+                        // updating remote mcast mac on l2gw devices
+                        return Lists.newArrayList(
+                                ElanL2GatewayMulticastUtils.updateRemoteMcastMacOnElanL2GwDevices(elanName));
+                    }
+                });
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<DpnInterfaces> identifier, DpnInterfaces original,
+            final DpnInterfaces dpnInterfaces) {
+        LOG.debug("dpninterfaces update fired new size {}", dpnInterfaces.getInterfaces().size());
+        if (dpnInterfaces.getInterfaces().size() == 0) {
+            LOG.debug("dpninterfaces last dpn interface on this elan {} ", dpnInterfaces.getKey());
+            // this is the last dpn interface on this elan
+            handleUpdate(identifier, dpnInterfaces);
+        }
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<DpnInterfaces> identifier, final DpnInterfaces dpnInterfaces) {
+        if (dpnInterfaces.getInterfaces().size() == 1) {
+            LOG.debug("dpninterfaces first dpn interface on this elan {} {} ", dpnInterfaces.getKey(),
+                    dpnInterfaces.getInterfaces().get(0));
+            // this is the first dpn interface on this elan
+            handleUpdate(identifier, dpnInterfaces);
+        }
+    }
+
+    /**
+     * @param identifier
+     * @return
+     */
+    private String getElanName(InstanceIdentifier<DpnInterfaces> identifier) {
+        return identifier.firstKeyOf(ElanDpnInterfacesList.class).getElanInstanceName();
+    }
+}
index 89f707112ad31c1bbe2f6a3a33ed474913e20a62..f33321534d48ae5aa2b7f43d01ec50eaad998627 100644 (file)
@@ -13,6 +13,8 @@ import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.interfacemgr.globals.InterfaceInfo;
+import org.opendaylight.vpnservice.interfacemgr.interfaces.IInterfaceManager;
 import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
 import org.opendaylight.vpnservice.elan.utils.ElanConstants;
 import org.opendaylight.vpnservice.elan.utils.ElanUtils;
@@ -39,6 +41,7 @@ public class ElanInstanceManager extends AbstractDataChangeListener<ElanInstance
     private ListenerRegistration<DataChangeListener> elanInstanceListenerRegistration;
     private IdManagerService idManager;
     private ElanInterfaceManager elanInterfaceManager;
+    private IInterfaceManager interfaceManager;
 
     private static final Logger logger = LoggerFactory.getLogger(ElanInstanceManager.class);
 
@@ -63,6 +66,10 @@ public class ElanInstanceManager extends AbstractDataChangeListener<ElanInstance
         this.elanInterfaceManager = elanInterfaceManager;
     }
 
+    public void setInterfaceManager(IInterfaceManager interfaceManager) {
+        this.interfaceManager = interfaceManager;
+    }
+
 
     /**
      * Starts listening for changes in elan.yang:elan-instance container
@@ -101,7 +108,8 @@ public class ElanInstanceManager extends AbstractDataChangeListener<ElanInstance
             if(elanInterfaces != null && !elanInterfaces.isEmpty()) {
                 for (String elanInterfaceName : elanInterfaces) {
                     InstanceIdentifier<ElanInterface> elanInterfaceId = ElanUtils.getElanInterfaceConfigurationDataPathId(elanInterfaceName);
-                    elanInterfaceManager.removeElanInterface(deletedElan, elanInterfaceName);
+                    InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(elanInterfaceName);
+                    elanInterfaceManager.removeElanInterface(deletedElan, elanInterfaceName, interfaceInfo);
                     ElanUtils.delete(broker, LogicalDatastoreType.CONFIGURATION, elanInterfaceId);
                 }
             }
diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceAddWorker.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceAddWorker.java
new file mode 100644 (file)
index 0000000..b02e9e9
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.vpnservice.elan.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.opendaylight.vpnservice.interfacemgr.globals.InterfaceInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.interfaces.ElanInterface;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class ElanInterfaceAddWorker implements Callable<List<ListenableFuture<Void>>> {
+    private String key;
+    private ElanInterface elanInterface;
+    private ElanInstance elanInstance;
+    private InterfaceInfo interfaceInfo;
+    private ElanInterfaceManager dataChangeListener;
+
+    public ElanInterfaceAddWorker(String key, ElanInterface elanInterface, InterfaceInfo interfaceInfo,
+            ElanInstance elanInstance, ElanInterfaceManager dataChangeListener) {
+        super();
+        this.key = key;
+        this.elanInterface = elanInterface;
+        this.interfaceInfo = interfaceInfo;
+        this.elanInstance = elanInstance;
+        this.dataChangeListener = dataChangeListener;
+    }
+
+    @Override
+    public String toString() {
+        return "ElanInterfaceAddWorker [key=" + key + ", elanInterface=" + elanInterface + ", elanInstance="
+                + elanInstance + ", interfaceInfo=" + interfaceInfo + "]";
+    }
+
+
+    @Override
+    public List<ListenableFuture<Void>> call() throws Exception {
+        List<ListenableFuture<Void>> futures = new ArrayList<>();
+        dataChangeListener.addElanInterface(elanInterface, interfaceInfo, elanInstance);
+        return futures;
+    }
+    
+    
+
+}
index 1b422c5d5b600c3baea4af94d20a1f72429312c1..83ba80101f672c7b39e5d145883c80ba00cf3f11 100644 (file)
@@ -18,29 +18,24 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.ConcurrentMap;
 
-import com.google.common.base.Optional;
-import com.google.common.collect.Maps;
-
+import org.apache.commons.lang3.StringUtils;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
-import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
+import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
 import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
 import org.opendaylight.vpnservice.elan.utils.ElanConstants;
 import org.opendaylight.vpnservice.elan.utils.ElanUtils;
 import org.opendaylight.vpnservice.interfacemgr.globals.InterfaceInfo;
 import org.opendaylight.vpnservice.interfacemgr.globals.InterfaceInfo.InterfaceType;
 import org.opendaylight.vpnservice.interfacemgr.interfaces.IInterfaceManager;
-import org.opendaylight.vpnservice.itm.api.IITMProvider;
 import org.opendaylight.vpnservice.itm.globals.ITMConstants;
 import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
 import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
 import org.opendaylight.vpnservice.mdsalutil.ActionType;
-import org.opendaylight.vpnservice.mdsalutil.BucketInfo;
 import org.opendaylight.vpnservice.mdsalutil.FlowEntity;
-import org.opendaylight.vpnservice.mdsalutil.GroupEntity;
 import org.opendaylight.vpnservice.mdsalutil.InstructionInfo;
 import org.opendaylight.vpnservice.mdsalutil.InstructionType;
 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
@@ -48,22 +43,18 @@ import org.opendaylight.vpnservice.mdsalutil.MatchFieldType;
 import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
 import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
 import org.opendaylight.vpnservice.mdsalutil.NwConstants;
-import org.opendaylight.vpnservice.itm.globals.ITMConstants;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.services.info.BoundServices;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
-import org.opendaylight.vpnservice.mdsalutil.*;
 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
 import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.services.info.BoundServices;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanDpnInterfaces;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanForwardingTables;
@@ -88,6 +79,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.f
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.forwarding.entries.MacEntryKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.external.tunnel.list.ExternalTunnel;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
@@ -95,8 +88,6 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
-import com.google.common.collect.Lists;
-
 
 /**
  * Class in charge of handling creations, modifications and removals of ElanInterfaces.
@@ -183,20 +174,15 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
     protected void remove(InstanceIdentifier<ElanInterface> identifier, ElanInterface del) {
         String interfaceName =  del.getName();
         ElanInstance elanInfo = ElanUtils.getElanInstanceByName(del.getElanInstanceName());
-        removeElanInterface(elanInfo, interfaceName);
-    }
-
-    public void removeElanService(ElanInterface del, InterfaceInfo interfaceInfo) {
-        ElanInstance elanInstance = ElanUtils.getElanInstanceByName(del.getElanInstanceName());
-        String interfaceName = del.getName();
-        removeElanInterface(elanInstance, interfaceInfo);
-        unbindService(elanInstance, interfaceName);
+        InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
+        String elanInstanceName = elanInfo.getElanInstanceName();
+        DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
+        ElanInterfaceRemoveWorker configWorker = new ElanInterfaceRemoveWorker(elanInstanceName, elanInfo, interfaceName, interfaceInfo, this);
+        coordinator.enqueueJob(elanInstanceName, configWorker, ElanConstants.JOB_MAX_RETRIES);
     }
 
-    public void removeElanInterface(ElanInstance elanInfo, String interfaceName) {
+    public void removeElanInterface(ElanInstance elanInfo, String interfaceName, InterfaceInfo interfaceInfo) {
         String elanName = elanInfo.getElanInstanceName();
-        InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
-
         if (interfaceInfo == null) {
             // Interface does not exist in ConfigDS, so lets remove everything about that interface related to Elan
             ElanInterfaceMac elanInterfaceMac =  ElanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
@@ -228,6 +214,7 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
 
         BigInteger dpId = interfaceInfo.getDpId();
         String elanName = elanInfo.getElanInstanceName();
+        long elanTag = elanInfo.getElanTag();
         String interfaceName = interfaceInfo.getInterfaceName();
         Elan elanState = ElanUtils.getElanByName(elanName);
         logger.debug("Removing the Interface:{} from elan:{}", interfaceName, elanName);
@@ -264,13 +251,13 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
                     DpnInterfaces dpnIfLists = ElanUtils.getElanInterfaceInfoByElanDpn(elanName, dpnInterface.getDpId());
                     if (dpnIfLists.getInterfaces().contains(interfaceName)) {
                         logger.debug("deleting the elanInterface from the ElanDpnInterface cache in pre-provision scenario of elan:{} dpn:{} interfaceName:{}", elanName, dpId, interfaceName);
-                        removeElanDpnInterfaceFromOperationalDataStore(elanName, dpId, interfaceName);
+                        removeElanDpnInterfaceFromOperationalDataStore(elanName, dpId, interfaceName, elanTag);
                         break;
                     }
                 }
             }
         } else {
-            removeElanDpnInterfaceFromOperationalDataStore(elanName, dpId, interfaceName);
+            removeElanDpnInterfaceFromOperationalDataStore(elanName, dpId, interfaceName, elanTag);
         }
 
         removeStaticELanFlows(elanInfo, interfaceInfo);
@@ -290,21 +277,39 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
         }
     }
 
-    private void removeElanDpnInterfaceFromOperationalDataStore(String elanName, BigInteger dpId, String interfaceName) {
+    private void removeElanDpnInterfaceFromOperationalDataStore(String elanName, BigInteger dpId, String interfaceName, long elanTag) {
         DpnInterfaces dpnInterfaces =  ElanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
         if(dpnInterfaces != null) {
             List<String> interfaceLists = dpnInterfaces.getInterfaces();
             interfaceLists.remove(interfaceName);
 
             if (interfaceLists == null || interfaceLists.isEmpty()) {
+                deleteAllRemoteMacsInADpn(elanName, dpId, elanTag);
                 deleteElanDpnInterface(elanName, dpId);
-                ElanL2GatewayMulticastUtils.updateRemoteMcastMacOnElanL2GwDevices(elanName);
             } else {
                 updateElanDpnInterfacesList(elanName, dpId, interfaceLists);
             }
         }
     }
 
+    private void deleteAllRemoteMacsInADpn(String elanName, BigInteger dpId, long elanTag) {
+        List<DpnInterfaces> dpnInterfaces = ElanUtils.getInvolvedDpnsInElan(elanName);
+        for (DpnInterfaces dpnInterface : dpnInterfaces) {
+            BigInteger currentDpId = dpnInterface.getDpId();
+            if (!currentDpId.equals(dpId)) {
+                for (String elanInterface : dpnInterface.getInterfaces()) {
+                    ElanInterfaceMac macs = ElanUtils.getElanInterfaceMacByInterfaceName(elanInterface);
+                    if (macs == null) {
+                        continue;
+                    }
+                    for (MacEntry mac : macs.getMacEntry())
+                        mdsalManager.removeFlow(dpId, MDSALUtil.buildFlow(ElanConstants.ELAN_DMAC_TABLE,
+                            ElanUtils.getKnownDynamicmacFlowRef(ElanConstants.ELAN_DMAC_TABLE, dpId, currentDpId, mac.getMacAddress().getValue(), elanTag)));
+                }
+            }
+        }
+    }
+
     @Override
     protected void update(InstanceIdentifier<ElanInterface> identifier, ElanInterface original, ElanInterface update) {
         // updating the static-Mac Entries for the existing elanInterface
@@ -374,7 +379,10 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
             unProcessedElanInterfaces.put(elanInstanceName, elanInterfaces);
             return;
         }
-        addElanInterface(elanInterfaceAdded, interfaceInfo, elanInstance);
+        DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
+        ElanInterfaceAddWorker addWorker = new ElanInterfaceAddWorker(elanInstanceName, elanInterfaceAdded,
+                interfaceInfo, elanInstance, this);
+        coordinator.enqueueJob(elanInstanceName, addWorker, ElanConstants.JOB_MAX_RETRIES);
     }
 
     void handleunprocessedElanInterfaces(ElanInstance elanInstance) {
@@ -451,12 +459,12 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
                 if ( elanInstance.getVni() != null && elanInstance.getVni().longValue() != 0 ) {
                     setExternalTunnelTable(dpId, elanInstance);
                 }
-                ElanL2GatewayMulticastUtils.updateRemoteMcastMacOnElanL2GwDevices(elanInstanceName);
+                ElanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance);
             } else {
                 List<String> elanInterfaces = existingElanDpnInterfaces.get().getInterfaces();
                 elanInterfaces.add(interfaceName);
                 if (elanInterfaces.size() == 1) {//1st dpn interface
-                    ElanL2GatewayMulticastUtils.updateRemoteMcastMacOnElanL2GwDevices(elanInstanceName);
+                    ElanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance);
                 }
                 updateElanDpnInterfacesList(elanInstanceName, dpId, elanInterfaces);
             }
@@ -490,7 +498,7 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
 
             if( isInterfaceOperational ) {
                 // Add MAC in TOR's remote MACs via OVSDB. Outside of the loop on purpose.
-                ElanL2GatewayUtils.installMacsInElanExternalDevices(elanInstance, dpId, staticMacAddresses);
+                ElanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), dpId, staticMacAddresses);
             }
         }
     }
@@ -519,11 +527,12 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
         if (isOperational(interfaceInfo)) {
 
             // LocalBroadcast Group creation with elan-Interfaces
-            setupElanBroadcastGroups(elanInfo, interfaceInfo);
+            setupElanBroadcastGroups(elanInfo, interfaceInfo.getDpId());
 
             setupLocalBroadcastGroups(elanInfo, interfaceInfo);
             //Terminating Service , UnknownDMAC Table.
             setupTerminateServiceTable(elanInfo, interfaceInfo);
+            ElanUtils.setupTermDmacFlows(interfaceInfo, mdsalManager);
             setupUnknownDMacTable(elanInfo, interfaceInfo);
             setupFilterEqualsTable(elanInfo, interfaceInfo);
             // bind the Elan service to the Interface
@@ -588,9 +597,7 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
         return listBuckets;
     }
 
-    private List<Bucket> getRemoteBCGroupBuckets(ElanInstance elanInfo,
-                                                         InterfaceInfo interfaceInfo, int bucketId) {
-        BigInteger dpnId = interfaceInfo.getDpId();
+    private List<Bucket> getRemoteBCGroupBuckets(ElanInstance elanInfo, BigInteger dpnId, int bucketId) {
         int elanTag = elanInfo.getElanTag().intValue();
         List<Bucket> listBucketInfo = new ArrayList<Bucket>();
         ElanDpnInterfacesList elanDpns = ElanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
@@ -667,40 +674,6 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
         }
     }
 
-    private void updateRemoteBCGrouponDpnTunnelEvent(ElanInstance elanInfo,
-                                               InterfaceInfo interfaceInfo, BigInteger dstDpId) {
-        int elanTag = elanInfo.getElanTag().intValue();
-        long groupId = ElanUtils.getElanRemoteBCGID(elanTag);
-        List<DpnInterfaces> elanDpns = ElanUtils.getInvolvedDpnsInElan(elanInfo.getElanInstanceName());
-        if(elanDpns != null) {
-            for(DpnInterfaces dpnInterface : elanDpns) {
-                int bucketId = 0;
-                List<Bucket> remoteListBucket = new ArrayList<Bucket>();
-                if(ElanUtils.isDpnPresent(dstDpId) && dpnInterface.getDpId().equals(dstDpId) && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
-                    try {
-                        List<Action> remoteListActionInfo = ElanUtils.getInternalItmEgressAction(interfaceInfo.getDpId(), dstDpId, elanTag);
-                        remoteListBucket.add(MDSALUtil.buildBucket(remoteListActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
-                        bucketId++;
-                    } catch (Exception ex) {
-                        logger.error( "Logical Group Interface not found between source Dpn - {}, destination Dpn - {} " ,dpnInterface.getDpId(), dstDpId);
-                        return;
-                    }
-                    List<Action> remoteListActionInfo = new ArrayList<Action>();
-                    remoteListActionInfo.add(new ActionInfo(ActionType.group, new String[] {String.valueOf(ElanUtils.getElanLocalBCGID(elanTag))}).buildAction());
-                    remoteListBucket.add(MDSALUtil.buildBucket(remoteListActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
-
-                    List<Bucket> elanL2GwDevicesBuckets = getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dstDpId, bucketId);
-                    remoteListBucket.addAll(elanL2GwDevicesBuckets);
-
-                    Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, MDSALUtil.buildBucketLists(remoteListBucket));
-                    mdsalManager.syncInstallGroup(interfaceInfo.getDpId(), group, ElanConstants.DELAY_TIME_IN_MILLISECOND);
-                    break;
-                }
-            }
-        }
-    }
-
-
     /**
      * Returns the bucket info with the given interface as the only bucket.
      */
@@ -842,17 +815,19 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
         }
     }
 
-    public void setupElanBroadcastGroups(ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
+    public void setupElanBroadcastGroups(ElanInstance elanInfo, BigInteger dpnId) {
         List<Bucket> listBucket = new ArrayList<Bucket>();
         int bucketId = 0;
-        BigInteger dpnId = interfaceInfo.getDpId();
         long groupId = ElanUtils.getElanRemoteBCGID(elanInfo.getElanTag());
 
         DpnInterfaces dpnInterfaces = ElanUtils.getElanInterfaceInfoByElanDpn(elanInfo.getElanInstanceName(), dpnId);
         for(String ifName : dpnInterfaces.getInterfaces()) {
             // In case if there is a InterfacePort in the cache which is not in
             // operational state, skip processing it
-            InterfaceInfo ifInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
+            // FIXME: interfaceType to be obtained dynamically. It doesn't
+            // affect the functionality here as it is nowhere used.
+            InterfaceType interfaceType = InterfaceInfo.InterfaceType.VLAN_INTERFACE;
+            InterfaceInfo ifInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(ifName, interfaceType);
             if (!isOperational(ifInfo)) {
                 continue;
             }
@@ -860,11 +835,11 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
             listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
             bucketId++;
         }
-        List<Bucket> listBucketInfoRemote = getRemoteBCGroupBuckets(elanInfo, interfaceInfo, bucketId);
+        List<Bucket> listBucketInfoRemote = getRemoteBCGroupBuckets(elanInfo, dpnId, bucketId);
         listBucket.addAll(listBucketInfoRemote);
 
         Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, MDSALUtil.buildBucketLists(listBucket));
-        logger.trace("installing the localBroadCast Group:{}", group);
+        logger.trace("installing the remote BroadCast Group:{}", group);
         mdsalManager.syncInstallGroup(dpnId, group, ElanConstants.DELAY_TIME_IN_MILLISECOND);
     }
 
@@ -956,6 +931,7 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
 
         String flowId = getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanInfo.getElanTag());
         FlowEntity flowEntity = new FlowEntity(dpnId);
+        flowEntity.setTableId(NwConstants.EXTERNAL_TUNNEL_TABLE);
         flowEntity.setFlowId(flowId);
         mdsalManager.removeFlow(flowEntity);
     }
@@ -999,6 +975,7 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
             // No more Elan Interfaces in this DPN
             logger.debug("deleting the elan: {} present on dpId: {}", elanInfo.getElanInstanceName(), dpId);
             removeDefaultTermFlow(dpId, elanInfo.getElanTag());
+            removeDefaultTermFlow(dpId, interfaceInfo.getInterfaceTag());
             removeUnknownDmacFlow(dpId, elanInfo);
             removeElanBroadcastGroup(elanInfo, interfaceInfo);
             removeLocalBroadcastGroup(elanInfo, interfaceInfo);
@@ -1007,7 +984,7 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
             }
             removeFilterEqualsTable(elanInfo, interfaceInfo);
         } else {
-            setupElanBroadcastGroups(elanInfo, interfaceInfo);
+            setupElanBroadcastGroups(elanInfo, dpId);
             setupLocalBroadcastGroups(elanInfo, interfaceInfo);
             removeFilterEqualsTable(elanInfo, interfaceInfo);
         }
@@ -1144,7 +1121,7 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
         if (interfaceInfo == null) {
             return false;
         }
-        return ((interfaceInfo.getOpState() == InterfaceInfo.InterfaceOpState.UP) && (interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED));
+        return interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED;
     }
 
     protected void updatedIfPrimaryAttributeChanged(ElanInterface elanInterface, boolean isUpdated) {
@@ -1191,9 +1168,8 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
         }
     }
 
-    public void handleTunnelStateEvent(BigInteger srcDpId, BigInteger dstDpId) {
+    public void handleInternalTunnelStateEvent(BigInteger srcDpId, BigInteger dstDpId) {
         ElanDpnInterfaces dpnInterfaceLists =  ElanUtils.getElanDpnInterfacesList();
-        Set<String> elanInstancesMap = new HashSet<>();
         if(dpnInterfaceLists == null) {
             return;
         }
@@ -1212,17 +1188,16 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
             }
             if(cnt == 2) {
                 logger.debug("Elan instance:{} is present b/w srcDpn:{} and dstDpn:{}", elanName, srcDpId, dstDpId);
+                ElanInstance elanInfo = ElanUtils.getElanInstanceByName(elanName);
+                // update Remote BC Group
+                setupElanBroadcastGroups(elanInfo, srcDpId);
+
                 DpnInterfaces dpnInterface = ElanUtils.getElanInterfaceInfoByElanDpn(elanName, srcDpId);
                 Set<String> interfaceLists = new HashSet<>();
-                ElanInstance elanInfo = ElanUtils.getElanInstanceByName(elanName);
                 interfaceLists.addAll(dpnInterface.getInterfaces());
                 for(String ifName : interfaceLists) {
                     InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(ifName);
                     if (isOperational(interfaceInfo)) {
-                        if (interfaceInfo.getDpId().equals(srcDpId) && !elanInstancesMap.contains(elanDpns.getElanInstanceName())) {
-                            elanInstancesMap.add(elanDpns.getElanInstanceName());
-                            elanInterfaceManager.updateRemoteBCGrouponDpnTunnelEvent(elanInfo, interfaceInfo, dstDpId);
-                        }
                         elanInterfaceManager.installDMacAddressTables(elanInfo, interfaceInfo, dstDpId);
                     }
                 }
@@ -1231,6 +1206,93 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
         }
     }
 
+    /**
+     * Handle external tunnel state event.
+     *
+     * @param externalTunnel
+     *            the external tunnel
+     * @param intrf
+     *            the interface
+     */
+    public void handleExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
+        if (!validateExternalTunnelStateEvent(externalTunnel, intrf)) {
+            return;
+        }
+        // dpId/externalNodeId will be available either in source or destination
+        // based on the tunnel end point
+        BigInteger dpId = null;
+        NodeId externalNodeId = null;
+        if (StringUtils.isNumeric(externalTunnel.getSourceDevice())) {
+            dpId = new BigInteger(externalTunnel.getSourceDevice());
+            externalNodeId = new NodeId(externalTunnel.getDestinationDevice());
+        } else if (StringUtils.isNumeric(externalTunnel.getDestinationDevice())) {
+            dpId = new BigInteger(externalTunnel.getDestinationDevice());
+            externalNodeId = new NodeId(externalTunnel.getSourceDevice());
+        }
+        if (dpId == null || externalNodeId == null) {
+            logger.error("Dp ID / externalNodeId not found in external tunnel {}", externalTunnel);
+            return;
+        }
+
+        ElanDpnInterfaces dpnInterfaceLists = ElanUtils.getElanDpnInterfacesList();
+        if (dpnInterfaceLists == null) {
+            return;
+        }
+        List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.getElanDpnInterfacesList();
+        for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
+            String elanName = elanDpns.getElanInstanceName();
+            ElanInstance elanInfo = ElanUtils.getElanInstanceByName(elanName);
+
+            DpnInterfaces dpnInterfaces = ElanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
+            if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
+                    || dpnInterfaces.getInterfaces().isEmpty()) {
+                continue;
+            }
+            logger.debug("Elan instance:{} is present in Dpn:{} ", elanName, dpId);
+
+            setupElanBroadcastGroups(elanInfo, dpId);
+            // install L2gwDevices local macs in dpn.
+            ElanL2GatewayUtils.installL2gwDeviceMacsInDpn(dpId, externalNodeId, elanInfo);
+            // Install dpn macs on external device
+            ElanL2GatewayUtils.installDpnMacsInL2gwDevice(elanName, new HashSet<>(dpnInterfaces.getInterfaces()), dpId,
+                    externalNodeId);
+        }
+        logger.info("Handled ExternalTunnelStateEvent for {}", externalTunnel);
+    }
+
+    /**
+     * Validate external tunnel state event.
+     *
+     * @param externalTunnel
+     *            the external tunnel
+     * @param intrf
+     *            the intrf
+     * @return true, if successful
+     */
+    private boolean validateExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
+        if (intrf.getOperStatus() == Interface.OperStatus.Up) {
+            String srcDevice = externalTunnel.getDestinationDevice();
+            String destDevice = externalTunnel.getSourceDevice();
+            ExternalTunnel otherEndPointExtTunnel = ElanUtils.getExternalTunnel(srcDevice, destDevice,
+                    LogicalDatastoreType.CONFIGURATION);
+            if (logger.isTraceEnabled()) {
+                logger.trace("Validating external tunnel state: src tunnel {}, dest tunnel {}", externalTunnel,
+                        otherEndPointExtTunnel);
+            }
+            if (otherEndPointExtTunnel != null) {
+                boolean otherEndPointInterfaceOperational = ElanUtils
+                        .isInterfaceOperational(otherEndPointExtTunnel.getTunnelInterfaceName(), broker);
+                if (otherEndPointInterfaceOperational) {
+                    return true;
+                } else {
+                    logger.debug("Other end [{}] of the external tunnel is not yet UP for {}",
+                            otherEndPointExtTunnel.getTunnelInterfaceName(), externalTunnel);
+                }
+            }
+        }
+        return false;
+    }
+
     public void handleInterfaceUpdated(InterfaceInfo interfaceInfo, ElanInstance elanInstance, boolean isStateUp) {
         BigInteger dpId = interfaceInfo.getDpId();
         String elanName = elanInstance.getElanInstanceName();
@@ -1252,6 +1314,15 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
             logger.trace("ElanInterface Service is installed for interface:{}", ifName);
             elanInterfaceManager.installFlowsAndGroups(elanInstance, interfaceInfo);
             elanInterfaceManager.installMacAddressTables(elanInstance, interfaceInfo);
+
+            if (elanInstance.getVni() != null && elanInstance.getVni() != 0) {
+                List<PhysAddress> macAddresses = ElanUtils
+                        .getElanInterfaceMacAddresses(interfaceInfo.getInterfaceName());
+                if (macAddresses != null && !macAddresses.isEmpty()) {
+                    ElanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(),
+                            dpId, macAddresses);
+                }
+            }
         } else {
 
             DpnInterfaces dpnInterfaces = ElanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
@@ -1296,81 +1367,21 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
         return mkMatches;
     }
 
-    public void updateElanBroadcastGroup(ElanInstance elanInfo) {
-        int bucketId = 0;
-        long groupId = ElanUtils.getElanRemoteBCGID(elanInfo.getElanTag());
-
-        List<DpnInterfaces> dpns = ElanUtils.getInvolvedDpnsInElan(elanInfo
-                .getElanInstanceName());
+    public void updateRemoteBroadcastGroupForAllElanDpns(ElanInstance elanInfo) {
+        List<DpnInterfaces> dpns = ElanUtils.getInvolvedDpnsInElan(elanInfo.getElanInstanceName());
         if (dpns == null) {
             return;
         }
         for (DpnInterfaces dpn : dpns) {
-            bucketId = 0;
-            List<Bucket> listBucket = new ArrayList<Bucket>();
-            bucketId = getLocalBcGroupBuckets(dpn, listBucket, bucketId);
-            getRemoteBCGroupBuckets(elanInfo, dpn.getDpId(), listBucket,
-                    bucketId);
-            Group group = MDSALUtil.buildGroup(groupId,
-                    elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
-                    MDSALUtil.buildBucketLists(listBucket));
-            logger.trace("installing the localBroadCast Group:{}", group);
-            mdsalManager.syncInstallGroup(dpn.getDpId(), group,
-                    ElanConstants.DELAY_TIME_IN_MILLISECOND);
-        }
-    }
-
-    private int getLocalBcGroupBuckets(DpnInterfaces dpn,
-            List<Bucket> listBucket, int bucketId) {
-        for (String intf : dpn.getInterfaces()) {
-            InterfaceInfo ifInfo = interfaceManager.getInterfaceInfo(intf);
-            if (!isOperational(ifInfo)) {
-                continue;
-            }
-            listBucket.add(MDSALUtil.buildBucket(
-                    getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT,
-                    bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
-            bucketId++;
-        }
-        return bucketId;
-    }
-
-    private void getRemoteBCGroupBuckets(ElanInstance elanInfo,
-            BigInteger dpnId, List<Bucket> listBucket, int bucketId) {
-        int elanTag = elanInfo.getElanTag().intValue();
-        ElanDpnInterfacesList elanDpns = ElanUtils
-                .getElanDpnInterfacesList(elanInfo.getElanInstanceName());
-        if (elanDpns != null) {
-            List<DpnInterfaces> dpnInterfaceses = elanDpns.getDpnInterfaces();
-            for (DpnInterfaces dpnInterface : dpnInterfaceses) {
-                if (ElanUtils.isDpnPresent(dpnInterface.getDpId())
-                        && dpnInterface.getDpId() != dpnId
-                        && dpnInterface.getInterfaces() != null
-                        && !dpnInterface.getInterfaces().isEmpty()) {
-                    try {
-                        List<Action> listActionInfo = ElanUtils
-                                .getInternalItmEgressAction(dpnId,
-                                        dpnInterface.getDpId(), elanTag);
-                        listBucket.add(MDSALUtil.buildBucket(listActionInfo, 0,
-                                bucketId, 0xffffffffL, 0xffffffffL));
-                        bucketId++;
-                    } catch (Exception ex) {
-                        logger.error(
-                                "Logical Group Interface not found between source Dpn - {}, destination Dpn - {} ",
-                                dpnId, dpnInterface.getDpId());
-                    }
-                }
-            }
+            setupElanBroadcastGroups(elanInfo, dpn.getDpId());
         }
-        List<Bucket> elanL2GwDevicesBuckets = getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpnId, bucketId);
-        listBucket.addAll(elanL2GwDevicesBuckets);
     }
 
     public static List<Bucket> getRemoteBCGroupBucketsOfElanL2GwDevices(ElanInstance elanInfo, BigInteger dpnId,
             int bucketId) {
         List<Bucket> listBucketInfo = new ArrayList<Bucket>();
         ConcurrentMap<String, L2GatewayDevice> map = ElanL2GwCacheUtils
-                .getAllElanL2GatewayDevicesFromCache(elanInfo.getElanInstanceName());
+                .getInvolvedL2GwDevices(elanInfo.getElanInstanceName());
         for (L2GatewayDevice device : map.values()) {
             String interfaceName = ElanL2GatewayUtils.getExternalTunnelInterfaceName(String.valueOf(dpnId),
                     device.getHwvtepNodeId());
diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceRemoveWorker.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceRemoveWorker.java
new file mode 100644 (file)
index 0000000..1b3bf96
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.vpnservice.elan.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.opendaylight.vpnservice.interfacemgr.globals.InterfaceInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class ElanInterfaceRemoveWorker implements Callable<List<ListenableFuture<Void>>> {
+    private String key;
+    private ElanInstance elanInfo;
+    private String interfaceName;
+    private InterfaceInfo interfaceInfo;
+    private ElanInterfaceManager dataChangeListener;
+
+    public ElanInterfaceRemoveWorker(String key, ElanInstance elanInfo, String interfaceName,
+            InterfaceInfo interfaceInfo, ElanInterfaceManager dataChangeListener) {
+        super();
+        this.key = key;
+        this.elanInfo = elanInfo;
+        this.interfaceName = interfaceName;
+        this.interfaceInfo = interfaceInfo;
+        this.dataChangeListener = dataChangeListener;
+    }
+
+    @Override
+    public String toString() {
+        return "ElanInterfaceRemoveWorker [key=" + key + ", elanInfo=" + elanInfo +
+                ", interfaceName=" + interfaceName
+                + ", interfaceInfo=" + interfaceInfo + "]";
+    }
+
+    @Override
+    public List<ListenableFuture<Void>> call() throws Exception {
+        List<ListenableFuture<Void>> futures = new ArrayList<>();
+        dataChangeListener.removeElanInterface(elanInfo, interfaceName, interfaceInfo);
+        return futures;
+    }
+
+}
index 80da723687533528511068ceb7070478d02dc4f0..f74e4b886a808385e4d9f5f84e26f6b2fa2d9325 100644 (file)
@@ -8,17 +8,20 @@
 package org.opendaylight.vpnservice.elan.internal;
 
 
-import com.google.common.base.Optional;
+import java.math.BigInteger;
+import java.util.List;
+
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
+import org.opendaylight.vpnservice.elan.utils.ElanConstants;
 import org.opendaylight.vpnservice.elan.utils.ElanUtils;
 import org.opendaylight.vpnservice.interfacemgr.globals.InterfaceInfo;
 import org.opendaylight.vpnservice.interfacemgr.interfaces.IInterfaceManager;
 import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.L2vlan;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
@@ -32,9 +35,6 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.math.BigInteger;
-import java.util.List;
-
 public class ElanInterfaceStateChangeListener extends AbstractDataChangeListener<Interface> implements AutoCloseable {
     private DataBroker broker;
     private IInterfaceManager interfaceManager;
@@ -67,24 +67,6 @@ public class ElanInterfaceStateChangeListener extends AbstractDataChangeListener
         this.interfaceManager = interfaceManager;
     }
 
-    private void handleVlanInterfaceOperationalStateChange(String interfaceName, boolean isStateUp) {
-        //fetching the elanInstanceName from elan-interface config data-store
-        ElanInterface elanInterface = ElanUtils.getElanInterfaceByElanInterfaceName(interfaceName);
-        if (elanInterface == null) {
-            return;
-        }
-        ElanInstance elanInfo = ElanUtils.getElanInstanceByName(elanInterface.getElanInstanceName());
-        InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(interfaceName, 
-                InterfaceInfo.InterfaceType.VLAN_INTERFACE);
-        if (interfaceInfo == null) {
-            logger.warn("Interface {} doesn't exist in operational datastore", interfaceName);
-            return;
-        }
-
-        logger.trace("ElanService Interface Operational state has changes for Interface:{}", interfaceName);
-        elanInterfaceManager.handleInterfaceUpdated(interfaceInfo, elanInfo , isStateUp);
-    }
-
     @Override
     protected void remove(InstanceIdentifier<Interface> identifier, Interface delIf) {
         logger.trace("Received interface {} Down event", delIf);
@@ -100,34 +82,29 @@ public class ElanInterfaceStateChangeListener extends AbstractDataChangeListener
         interfaceInfo.setInterfaceName(interfaceName);
         interfaceInfo.setInterfaceType(InterfaceInfo.InterfaceType.VLAN_INTERFACE);
         interfaceInfo.setInterfaceTag(delIf.getIfIndex());
-        elanInterfaceManager.removeElanService(elanInterface, interfaceInfo);
+        String elanInstanceName = elanInterface.getElanInstanceName();
+        ElanInstance elanInstance = ElanUtils.getElanInstanceByName(elanInstanceName);
+        DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
+        ElanInterfaceRemoveWorker removeWorker = new ElanInterfaceRemoveWorker(elanInstanceName, elanInstance, 
+                interfaceName, interfaceInfo, elanInterfaceManager);
+        coordinator.enqueueJob(elanInstanceName, removeWorker, ElanConstants.JOB_MAX_RETRIES);
     }
 
     @Override
     protected void update(InstanceIdentifier<Interface> identifier, Interface original, Interface update) {
         logger.trace("Operation Interface update event - Old: {}, New: {}", original, update);
         String interfaceName = update.getName();
-        if(update.getType() != null && update.getType().equals(Tunnel.class)) {
+        if (update.getType() == null) {
+            logger.trace("Interface type for interface {} is null", interfaceName);
+            return;
+        }
+        if(update.getType().equals(Tunnel.class)) {
             if (update.getOperStatus().equals(Interface.OperStatus.Up)) {
                 InternalTunnel internalTunnel = getTunnelState(interfaceName);
                 if (internalTunnel != null) {
-                    elanInterfaceManager.handleTunnelStateEvent(internalTunnel.getSourceDPN(), internalTunnel.getDestinationDPN());
+                    elanInterfaceManager.handleInternalTunnelStateEvent(internalTunnel.getSourceDPN(), internalTunnel.getDestinationDPN());
                 }
             }
-        } else if(update.getType().equals(L2vlan.class)) {
-            ElanInterface elanInterface = ElanUtils.getElanInterfaceByElanInterfaceName(interfaceName);
-            if(elanInterface == null) {
-                logger.debug("No Elan Interface is created for the interface:{} ", interfaceName);
-                return;
-            }
-            if (update.getOperStatus().equals(Interface.OperStatus.Up) && update.getAdminStatus() == Interface.AdminStatus.Up) {
-                logger.trace("Operation Status for Interface:{}  event state UP ", interfaceName);
-                handleVlanInterfaceOperationalStateChange(interfaceName, true);
-            } else if (update.getOperStatus().equals(Interface.OperStatus.Down)) {
-                logger.trace("Operation Status for Interface:{}  event state DOWN ", interfaceName);
-                handleVlanInterfaceOperationalStateChange(interfaceName, false);
-            }
-
         }
     }
 
@@ -141,7 +118,8 @@ public class ElanInterfaceStateChangeListener extends AbstractDataChangeListener
                 if(intrf.getOperStatus().equals(Interface.OperStatus.Up)) {
                     InternalTunnel internalTunnel = getTunnelState(interfaceName);
                     if (internalTunnel != null) {
-                        elanInterfaceManager.handleTunnelStateEvent(internalTunnel.getSourceDPN(), internalTunnel.getDestinationDPN());
+                        elanInterfaceManager.handleInternalTunnelStateEvent(internalTunnel.getSourceDPN(),
+                                internalTunnel.getDestinationDPN());
                     }
                 }
             }
@@ -159,7 +137,7 @@ public class ElanInterfaceStateChangeListener extends AbstractDataChangeListener
     public  InternalTunnel getTunnelState(String interfaceName) {
         InternalTunnel internalTunnel = null;
         TunnelList tunnelList = ElanUtils.buildInternalTunnel(broker);
-        if (tunnelList.getInternalTunnel() != null) {
+        if (tunnelList != null && tunnelList.getInternalTunnel() != null) {
             List<InternalTunnel> internalTunnels = tunnelList.getInternalTunnel();
             for (InternalTunnel tunnel : internalTunnels) {
                 if (tunnel.getTunnelInterfaceName().equalsIgnoreCase(interfaceName)) {
diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceStateClusteredListener.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceStateClusteredListener.java
new file mode 100644 (file)
index 0000000..3ce6b9f
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.vpnservice.elan.internal;
+
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
+import org.opendaylight.vpnservice.elan.utils.ElanClusterUtils;
+import org.opendaylight.vpnservice.elan.utils.ElanUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.external.tunnel.list.ExternalTunnel;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ElanInterfaceStateClusteredListener extends
+        AsyncClusteredDataChangeListenerBase<Interface, ElanInterfaceStateClusteredListener> implements AutoCloseable {
+    private DataBroker broker;
+    private ElanInterfaceManager elanInterfaceManager;
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+
+    private static final Logger logger = LoggerFactory.getLogger(ElanInterfaceStateClusteredListener.class);
+
+    public ElanInterfaceStateClusteredListener(final DataBroker db, final ElanInterfaceManager ifManager) {
+        super(Interface.class, ElanInterfaceStateClusteredListener.class);
+        broker = db;
+        elanInterfaceManager = ifManager;
+        registerListener(db);
+    }
+
+    private void registerListener(final DataBroker db) {
+        try {
+            listenerRegistration = broker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+                    getWildCardPath(), ElanInterfaceStateClusteredListener.this, AsyncDataBroker.DataChangeScope.BASE);
+        } catch (final Exception e) {
+            logger.error("Elan Interfaces DataChange listener registration fail!", e);
+            throw new IllegalStateException("ElanInterface registration Listener failed.", e);
+        }
+    }
+
+    @Override
+    public InstanceIdentifier<Interface> getWildCardPath() {
+        return InstanceIdentifier.create(InterfacesState.class).child(Interface.class);
+    }
+
+    @Override
+    protected ClusteredDataChangeListener getDataChangeListener() {
+        return ElanInterfaceStateClusteredListener.this;
+    }
+
+    @Override
+    protected AsyncDataBroker.DataChangeScope getDataChangeScope() {
+        return AsyncDataBroker.DataChangeScope.BASE;
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<Interface> identifier, Interface delIf) {
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<Interface> identifier, Interface original, final Interface update) {
+        add(identifier, update);
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<Interface> identifier, final Interface intrf) {
+        if (intrf.getType() != null && intrf.getType().equals(Tunnel.class)) {
+            if (intrf.getOperStatus().equals(Interface.OperStatus.Up)) {
+                final String interfaceName = intrf.getName();
+
+                ElanClusterUtils.runOnlyInLeaderNode(new Runnable() {
+                    @Override
+                    public void run() {
+                        logger.debug("running external tunnel update job for interface {} added", interfaceName);
+                        handleExternalTunnelUpdate(interfaceName, intrf);
+                    }
+                });
+            }
+        }
+    }
+
+    private void handleExternalTunnelUpdate(String interfaceName, Interface update) {
+        ExternalTunnel externalTunnel = ElanUtils.getExternalTunnel(interfaceName, LogicalDatastoreType.CONFIGURATION);
+        if (externalTunnel != null) {
+            logger.debug("handling external tunnel update event for ext device dst {}  src {} ",
+                    externalTunnel.getDestinationDevice(), externalTunnel.getSourceDevice());
+            elanInterfaceManager.handleExternalTunnelStateEvent(externalTunnel, update);
+        } else {
+            logger.trace("External tunnel not found with interfaceName: {}", interfaceName);
+        }
+    }
+}
index dbf83ddc6021537469ddef6649222106c157598b..85ccf597887c45e92715bb59a45660d748fc6001 100755 (executable)
@@ -22,14 +22,11 @@ import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
 import org.opendaylight.vpnservice.mdsalutil.NWUtil;
 import org.opendaylight.vpnservice.mdsalutil.packet.Ethernet;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.NoMatch;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketInReason;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingListener;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.interfacemgr.impl.rev150325.InterfacemgrImpl;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.state.Elan;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.tag.name.map.ElanTagName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.forwarding.entries.MacEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.forwarding.entries.MacEntryBuilder;
@@ -40,9 +37,8 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Optional;
-import java.math.BigInteger;
+
 import java.util.Arrays;
-import java.util.List;
 
 @SuppressWarnings("deprecation")
 public class ElanPacketInHandler implements PacketProcessingListener {
@@ -134,7 +130,8 @@ public class ElanPacketInHandler implements PacketProcessingListener {
                 ElanUtils.setupMacFlows(elanInstance, interfaceManager.getInterfaceInfo(interfaceName), elanInstance.getMacTimeout(), macAddress);
 
                 BigInteger dpId = interfaceManager.getDpnForInterface(interfaceName);
-                ElanL2GatewayUtils.installMacsInElanExternalDevices(elanInstance, dpId, Arrays.asList(physAddress));
+                ElanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), dpId,
+                        Arrays.asList(physAddress));
             } catch (Exception e) {
                 logger.trace("Failed to decode packet: {}", e);
             }
index af817b8595fd34ea60aef5f3c6d60f3a40072efa..6ad3df3b75c2c0e070a19bba1ca76402705de750 100644 (file)
@@ -22,9 +22,11 @@ import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
 import org.opendaylight.elanmanager.api.IElanService;
 import org.opendaylight.elanmanager.exceptions.MacNotFoundException;
+import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
 import org.opendaylight.vpnservice.elan.l2gw.internal.ElanL2GatewayProvider;
 import org.opendaylight.vpnservice.elan.statisitcs.ElanStatisticsImpl;
 import org.opendaylight.vpnservice.elan.statusanddiag.ElanStatusMonitor;
+import org.opendaylight.vpnservice.elan.utils.ElanClusterUtils;
 import org.opendaylight.vpnservice.elan.utils.ElanConstants;
 import org.opendaylight.vpnservice.elan.utils.ElanUtils;
 import org.opendaylight.vpnservice.interfacemgr.interfaces.IInterfaceManager;
@@ -59,7 +61,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev1512
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
-import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
@@ -79,6 +80,8 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
     private ElanPacketInHandler elanPacketInHandler;
     private ElanSmacFlowEventListener elanSmacFlowEventListener;
     private ElanInterfaceStateChangeListener elanInterfaceStateChangeListener;
+    private ElanInterfaceStateClusteredListener infStateChangeClusteredListener;
+    private ElanDpnInterfaceClusteredListener elanDpnInterfaceClusteredListener;
     private ElanNodeListener elanNodeListener;
     private NotificationService notificationService;
     private RpcProviderRegistry rpcProviderRegistry;
@@ -88,9 +91,21 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
     private ElanL2GatewayProvider elanL2GatewayProvider;
 
     private EntityOwnershipService entityOwnershipService;
-    private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
 
     private static final ElanStatusMonitor elanStatusMonitor = ElanStatusMonitor.getInstance();
+    static DataStoreJobCoordinator dataStoreJobCoordinator;
+
+    public static void setDataStoreJobCoordinator(DataStoreJobCoordinator ds) {
+        dataStoreJobCoordinator = ds;
+    }
+
+    public static DataStoreJobCoordinator getDataStoreJobCoordinator() {
+        if (dataStoreJobCoordinator == null) {
+            dataStoreJobCoordinator = DataStoreJobCoordinator.getInstance();
+        }
+        return dataStoreJobCoordinator;
+    }
+
 
     public ElanServiceProvider(RpcProviderRegistry rpcRegistry) {
         rpcProviderRegistry = rpcRegistry;
@@ -107,6 +122,7 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
         elanStatusMonitor.reportStatus("STARTING");
         try {
             createIdPool();
+            getDataStoreJobCoordinator();
             broker = session.getSALService(DataBroker.class);
 
             ElanUtils.setDataBroker(broker);
@@ -128,6 +144,7 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
             elanInstanceManager.setDataBroker(broker);
             elanInstanceManager.setIdManager(idManager);
             elanInstanceManager.setElanInterfaceManager(elanInterfaceManager);
+            elanInstanceManager.setInterfaceManager(interfaceManager);
 
 
             elanNodeListener = new ElanNodeListener(broker, mdsalManager);
@@ -150,7 +167,11 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
             elanInterfaceStateChangeListener = new ElanInterfaceStateChangeListener(broker, elanInterfaceManager);
             elanInterfaceStateChangeListener.setInterfaceManager(interfaceManager);
 
+            infStateChangeClusteredListener = new ElanInterfaceStateClusteredListener(broker, elanInterfaceManager);
 
+            elanDpnInterfaceClusteredListener = new ElanDpnInterfaceClusteredListener(broker, elanInterfaceManager);
+            ElanClusterUtils.setEntityOwnershipService(entityOwnershipService);
+            ElanClusterUtils.setDataStoreJobCoordinator(dataStoreJobCoordinator);
             this.elanL2GatewayProvider = new ElanL2GatewayProvider(this);
 
             elanInterfaceManager.registerListener();
@@ -181,10 +202,6 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
         this.entityOwnershipService = entityOwnershipService;
     }
 
-    public void setBindingNormalizedNodeSerializer(BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer) {
-        this.bindingNormalizedNodeSerializer = bindingNormalizedNodeSerializer;
-    }
-
     public IInterfaceManager getInterfaceManager() {
         return this.interfaceManager;
     }
@@ -237,10 +254,6 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
         return entityOwnershipService;
     }
 
-    public BindingNormalizedNodeSerializer getBindingNormalizedNodeSerializer() {
-        return bindingNormalizedNodeSerializer;
-    }
-
     private void createIdPool() {
         CreateIdPoolInput createPool = new CreateIdPoolInputBuilder().setPoolName(ElanConstants.ELAN_ID_POOL_NAME)
                 .setLow(ElanConstants.ELAN_ID_LOW_VALUE).setHigh(ElanConstants.ELAN_ID_HIGH_VALUE).build();
index 76bdb6e863da34888a828b67fdc2afa3de976388..65068970393207736224a075c245ac669e73712f 100644 (file)
@@ -9,19 +9,26 @@
 package org.opendaylight.vpnservice.elan.l2gw.internal;
 
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException;
 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
 import org.opendaylight.vpnservice.elan.internal.ElanInstanceManager;
 import org.opendaylight.vpnservice.elan.internal.ElanInterfaceManager;
 import org.opendaylight.vpnservice.elan.internal.ElanServiceProvider;
 import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepLocalUcastMacListener;
+import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepLogicalSwitchListener;
 import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepNodeListener;
+import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepPhysicalLocatorListener;
+import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepRemoteMcastMacListener;
 import org.opendaylight.vpnservice.elan.l2gw.listeners.L2GatewayConnectionListener;
 import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
 import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.vpnservice.elan.l2gw.utils.L2GatewayConnectionUtils;
+import org.opendaylight.vpnservice.utils.clustering.EntityOwnerUtils;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundConstants;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
-import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -34,7 +41,6 @@ public class ElanL2GatewayProvider implements AutoCloseable {
 
     private DataBroker broker;
     private EntityOwnershipService entityOwnershipService;
-    private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
     private ItmRpcService itmRpcService;
     private ElanInstanceManager elanInstanceManager;
     private ElanInterfaceManager elanInterfaceManager;
@@ -42,6 +48,9 @@ public class ElanL2GatewayProvider implements AutoCloseable {
     private L2GatewayConnectionListener l2GwConnListener;
     private HwvtepNodeListener hwvtepNodeListener;
     private HwvtepLocalUcastMacListener torMacsListener;
+    private HwvtepPhysicalLocatorListener physicalLocatorListener;
+
+    static DataStoreJobCoordinator dataStoreJobCoordinator;
 
     /**
      * Instantiates a new elan l2 gateway provider.
@@ -52,11 +61,10 @@ public class ElanL2GatewayProvider implements AutoCloseable {
     public ElanL2GatewayProvider(ElanServiceProvider elanServiceProvider) {
         this.broker = elanServiceProvider.getBroker();
         this.entityOwnershipService = elanServiceProvider.getEntityOwnershipService();
-        this.bindingNormalizedNodeSerializer = elanServiceProvider.getBindingNormalizedNodeSerializer();
         this.itmRpcService = elanServiceProvider.getItmRpcService();
         this.elanInstanceManager = elanServiceProvider.getElanInstanceManager();
         this.elanInterfaceManager = elanServiceProvider.getElanInterfaceManager();
-
+        dataStoreJobCoordinator = elanServiceProvider.getDataStoreJobCoordinator();
         init();
 
         LOG.info("ElanL2GatewayProvider Initialized");
@@ -69,18 +77,33 @@ public class ElanL2GatewayProvider implements AutoCloseable {
         ElanL2GwCacheUtils.createElanL2GwDeviceCache();
         ElanL2GatewayUtils.setDataBroker(broker);
         ElanL2GatewayUtils.setItmRpcService(itmRpcService);
+        ElanL2GatewayUtils.setDataStoreJobCoordinator(dataStoreJobCoordinator);
 
         ElanL2GatewayMulticastUtils.setBroker(broker);
         ElanL2GatewayMulticastUtils.setElanInstanceManager(elanInstanceManager);
         ElanL2GatewayMulticastUtils.setElanInterfaceManager(elanInterfaceManager);
+        ElanL2GatewayMulticastUtils.setDataStoreJobCoordinator(dataStoreJobCoordinator);
+
+        L2GatewayConnectionUtils.setElanInstanceManager(elanInstanceManager);
+        L2GatewayConnectionUtils.setBroker(broker);
+        L2GatewayConnectionUtils.setDataStoreJobCoordinator(dataStoreJobCoordinator);
 
-        this.torMacsListener = new HwvtepLocalUcastMacListener(broker, entityOwnershipService,
-                bindingNormalizedNodeSerializer);
-        this.l2GwConnListener = new L2GatewayConnectionListener(broker, entityOwnershipService,
-                bindingNormalizedNodeSerializer, elanInstanceManager);
-        this.hwvtepNodeListener = new HwvtepNodeListener(broker, entityOwnershipService,
-                bindingNormalizedNodeSerializer, elanInstanceManager, itmRpcService);
+        HwvtepRemoteMcastMacListener.setDataStoreJobCoordinator(dataStoreJobCoordinator);
+        HwvtepLogicalSwitchListener.setDataStoreJobCoordinator(dataStoreJobCoordinator);
+
+        this.torMacsListener = new HwvtepLocalUcastMacListener(broker);
+        this.l2GwConnListener = new L2GatewayConnectionListener(broker, elanInstanceManager);
+        this.hwvtepNodeListener = new HwvtepNodeListener(broker, elanInstanceManager, itmRpcService);
         this.hwvtepNodeListener.registerListener(LogicalDatastoreType.OPERATIONAL, broker);
+
+        physicalLocatorListener = new HwvtepPhysicalLocatorListener(broker);
+        try {
+            EntityOwnerUtils.registerEntityCandidateForOwnerShip(entityOwnershipService,
+                    HwvtepSouthboundConstants.ELAN_ENTITY_TYPE, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+                    null/*listener*/);
+        } catch (CandidateAlreadyRegisteredException e) {
+            LOG.error("failed to register the entity");
+        }
     }
 
     /*
diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/AssociateHwvtepToElanJob.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/AssociateHwvtepToElanJob.java
new file mode 100644 (file)
index 0000000..946fb24
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.vpnservice.elan.l2gw.jobs;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundUtils;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.attributes.Devices;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+* Created by ekvsver on 4/15/2016.
+*/
+public class AssociateHwvtepToElanJob implements Callable<List<ListenableFuture<Void>>> {
+    DataBroker broker;
+    L2GatewayDevice l2GatewayDevice;
+    ElanInstance elanInstance;
+    Devices l2Device;
+    Integer defaultVlan;
+    boolean createLogicalSwitch;
+    private static final Logger LOG = LoggerFactory.getLogger(AssociateHwvtepToElanJob.class);
+
+    public AssociateHwvtepToElanJob(DataBroker broker, L2GatewayDevice l2GatewayDevice, ElanInstance elanInstance,
+            Devices l2Device, Integer defaultVlan, boolean createLogicalSwitch) {
+        this.broker = broker;
+        this.l2GatewayDevice = l2GatewayDevice;
+        this.elanInstance = elanInstance;
+        this.l2Device = l2Device;
+        this.defaultVlan = defaultVlan;
+        this.createLogicalSwitch = createLogicalSwitch;
+        LOG.debug("created assosiate l2gw connection job for {} {} ", elanInstance.getElanInstanceName(),
+                l2GatewayDevice.getHwvtepNodeId());
+    }
+
+    public String getJobKey() {
+        return elanInstance.getElanInstanceName();
+    }
+
+    @Override
+    public List<ListenableFuture<Void>> call() throws Exception {
+        List<ListenableFuture<Void>> futures = new ArrayList<>();
+        String hwvtepNodeId = l2GatewayDevice.getHwvtepNodeId();
+        String elanInstanceName = elanInstance.getElanInstanceName();
+        LOG.debug("running assosiate l2gw connection job for {} {} ", elanInstanceName, hwvtepNodeId);
+
+        // Create Logical Switch if it's not created already in the device
+        if (createLogicalSwitch) {
+            LOG.info("creating logical switch {} for {} ", elanInstanceName, hwvtepNodeId);
+
+            ListenableFuture<Void> lsCreateFuture = createLogicalSwitch(l2GatewayDevice, elanInstance);
+            futures.add(lsCreateFuture);
+        } else {
+            String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanInstanceName);
+            LOG.info("{} is already created in {}; adding remaining configurations", logicalSwitchName, hwvtepNodeId);
+
+            LogicalSwitchAddedJob logicalSwitchAddedJob = new LogicalSwitchAddedJob(logicalSwitchName, l2Device,
+                    l2GatewayDevice, defaultVlan);
+            return logicalSwitchAddedJob.call();
+        }
+
+        return futures;
+    }
+
+    private ListenableFuture<Void> createLogicalSwitch(L2GatewayDevice l2GatewayDevice, ElanInstance elanInstance) {
+        final String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(
+                elanInstance.getElanInstanceName());
+        String segmentationId = elanInstance.getVni().toString();
+
+        if (LOG.isTraceEnabled()) {
+            LOG.trace("logical switch {} is created on {} with VNI {}", logicalSwitchName,
+                    l2GatewayDevice.getHwvtepNodeId(), segmentationId);
+        }
+        NodeId hwvtepNodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
+        InstanceIdentifier<LogicalSwitches> path = HwvtepSouthboundUtils
+                .createLogicalSwitchesInstanceIdentifier(hwvtepNodeId, new HwvtepNodeName(logicalSwitchName));
+        LogicalSwitches logicalSwitch = HwvtepSouthboundUtils.createLogicalSwitch(logicalSwitchName,
+                elanInstance.getDescription(), segmentationId);
+
+        ListenableFuture<Void> lsCreateFuture = HwvtepUtils.addLogicalSwitch(broker, hwvtepNodeId, logicalSwitch);
+        Futures.addCallback(lsCreateFuture, new FutureCallback<Void>() {
+            @Override
+            public void onSuccess(Void noarg) {
+                // Listener will be closed after all configuration completed
+                // on hwvtep by
+                // listener itself
+                if (LOG.isTraceEnabled()) {
+                    LOG.trace("Successful in initiating logical switch {} creation", logicalSwitchName);
+                }
+            }
+
+            @Override
+            public void onFailure(Throwable error) {
+                LOG.error("Failed logical switch {} creation", logicalSwitchName, error);
+            }
+        });
+        return lsCreateFuture;
+    }
+}
diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/DeleteL2GwDeviceMacsFromElanJob.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/DeleteL2GwDeviceMacsFromElanJob.java
new file mode 100644 (file)
index 0000000..96170f6
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.vpnservice.elan.l2gw.jobs;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentMap;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * The Job class to delete L2 gateway device local ucast macs from other Elan L2
+ * gateway devices.
+ */
+public class DeleteL2GwDeviceMacsFromElanJob implements Callable<List<ListenableFuture<Void>>> {
+
+    /** The Constant JOB_KEY_PREFIX. */
+    private static final String JOB_KEY_PREFIX = "hwvtep:";
+
+    /** The Constant LOG. */
+    private static final Logger LOG = LoggerFactory.getLogger(DeleteL2GwDeviceMacsFromElanJob.class);
+
+    /** The broker. */
+    private final DataBroker broker;
+
+    /** The elan name. */
+    private final String elanName;
+
+    /** The l2 gw device. */
+    private final L2GatewayDevice l2GwDevice;
+
+    /** The mac addresses. */
+    private final List<MacAddress> macAddresses;
+
+    /**
+     * Instantiates a new delete l2 gw device macs from elan job.
+     *
+     * @param broker
+     *            the broker
+     * @param elanName
+     *            the elan name
+     * @param l2GwDevice
+     *            the l2 gw device
+     * @param macAddresses
+     *            the mac addresses
+     */
+    public DeleteL2GwDeviceMacsFromElanJob(DataBroker broker, String elanName, L2GatewayDevice l2GwDevice,
+            List<MacAddress> macAddresses) {
+        this.broker = broker;
+        this.elanName = elanName;
+        this.l2GwDevice = l2GwDevice;
+        this.macAddresses = macAddresses;
+    }
+
+    public String getJobKey() {
+        return JOB_KEY_PREFIX + this.elanName;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.util.concurrent.Callable#call()
+     */
+    @Override
+    public List<ListenableFuture<Void>> call() {
+        LOG.debug("Deleting l2gw device [{}] macs from other l2gw devices for elan [{}]",
+                this.l2GwDevice.getHwvtepNodeId(), this.elanName);
+        final String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(this.elanName);
+
+        ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices = ElanL2GwCacheUtils
+                .getInvolvedL2GwDevices(this.elanName);
+        List<ListenableFuture<Void>> futures = Lists.newArrayList();
+        for (L2GatewayDevice otherDevice : elanL2GwDevices.values()) {
+            if (!otherDevice.getHwvtepNodeId().equals(this.l2GwDevice.getHwvtepNodeId())
+                    && !ElanL2GatewayUtils.areMLAGDevices(this.l2GwDevice, otherDevice)) {
+                final String hwvtepId = otherDevice.getHwvtepNodeId();
+                // never batch deletes
+                ListenableFuture<Void> uninstallFuture = HwvtepUtils.deleteRemoteUcastMacs(this.broker,
+                        new NodeId(hwvtepId), logicalSwitchName, this.macAddresses);
+                Futures.addCallback(uninstallFuture, new FutureCallback<Void>() {
+                    @Override
+                    public void onSuccess(Void noarg) {
+                        LOG.trace("Successful in initiating ucast_remote_macs deletion related to {} in {}",
+                                logicalSwitchName, hwvtepId);
+                    }
+
+                    @Override
+                    public void onFailure(Throwable error) {
+                        LOG.error(String.format("Failed removing ucast_remote_macs related to %s in %s",
+                                logicalSwitchName, hwvtepId), error);
+                    }
+                });
+                // TODO: why to create a new arraylist for uninstallFuture?
+                futures.addAll(Lists.newArrayList(uninstallFuture));
+            }
+        }
+        return futures;
+    }
+}
diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/DisAssociateHwvtepFromElanJob.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/DisAssociateHwvtepFromElanJob.java
new file mode 100644 (file)
index 0000000..49e0c20
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.vpnservice.elan.l2gw.jobs;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.attributes.Devices;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+/**
+* Created by ekvsver on 4/15/2016.
+*/
+public class DisAssociateHwvtepFromElanJob implements Callable<List<ListenableFuture<Void>>> {
+    DataBroker broker;
+    L2GatewayDevice l2GatewayDevice;
+    ElanInstance elanInstance;
+    Devices l2Device;
+    Integer defaultVlan;
+    boolean isLastL2GwConnDeleted;
+
+    private static final Logger LOG = LoggerFactory.getLogger(DisAssociateHwvtepFromElanJob.class);
+
+    public DisAssociateHwvtepFromElanJob(DataBroker broker, L2GatewayDevice l2GatewayDevice, ElanInstance elanInstance,
+                                         Devices l2Device, Integer defaultVlan, boolean isLastL2GwConnDeleted) {
+        this.broker = broker;
+        this.l2GatewayDevice = l2GatewayDevice;
+        this.elanInstance = elanInstance;
+        this.l2Device = l2Device;
+        this.defaultVlan = defaultVlan;
+        this.isLastL2GwConnDeleted = isLastL2GwConnDeleted;
+        LOG.info("created disassosiate l2gw connection job for {} {}", elanInstance.getElanInstanceName(),
+                l2GatewayDevice.getHwvtepNodeId());
+    }
+
+    public String getJobKey() {
+        return elanInstance.getElanInstanceName();
+    }
+
+    @Override
+    public List<ListenableFuture<Void>> call() throws Exception {
+        String elanName = elanInstance.getElanInstanceName();
+        String strHwvtepNodeId = l2GatewayDevice.getHwvtepNodeId();
+        NodeId hwvtepNodeId = new NodeId(strHwvtepNodeId);
+        LOG.info("running disassosiate l2gw connection job for {} {}", elanName, strHwvtepNodeId);
+
+        List<ListenableFuture<Void>> futures = new ArrayList<>();
+
+        // Remove remote MACs and vlan mappings from physical port
+        // Once all above configurations are deleted, delete logical
+        // switch
+        LOG.info("delete vlan bindings for {} {}", elanName, strHwvtepNodeId);
+        futures.add(ElanL2GatewayUtils.deleteVlanBindingsFromL2GatewayDevice(hwvtepNodeId, l2Device, defaultVlan));
+
+        if (isLastL2GwConnDeleted) {
+            LOG.info("delete remote ucast macs {} {}", elanName, strHwvtepNodeId);
+            futures.add(ElanL2GatewayUtils.deleteElanMacsFromL2GatewayDevice(l2GatewayDevice, elanName));
+
+            LOG.info("delete mcast mac for {} {}", elanName, strHwvtepNodeId);
+            futures.addAll(ElanL2GatewayMulticastUtils.handleMcastForElanL2GwDeviceDelete(elanInstance,
+                    l2GatewayDevice));
+
+            LOG.info("delete local ucast macs {} {}", elanName, strHwvtepNodeId);
+            futures.addAll(ElanL2GatewayUtils.deleteL2GwDeviceUcastLocalMacsFromElan(l2GatewayDevice, elanName));
+
+            LOG.info("scheduled delete logical switch {} {}", elanName, strHwvtepNodeId);
+            ElanL2GatewayUtils.scheduleDeleteLogicalSwitch(hwvtepNodeId,
+                    ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName));
+        }
+
+        return futures;
+    }
+}
diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/HwvtepDeviceMcastMacUpdateJob.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/HwvtepDeviceMcastMacUpdateJob.java
new file mode 100644 (file)
index 0000000..e94d626
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.vpnservice.elan.l2gw.jobs;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class HwvtepDeviceMcastMacUpdateJob implements Callable<List<ListenableFuture<Void>>> {
+    private static final Logger LOG = LoggerFactory.getLogger(HwvtepDeviceMcastMacUpdateJob.class);
+
+    String elanName;
+    L2GatewayDevice l2GatewayDevice;
+
+    public HwvtepDeviceMcastMacUpdateJob(String elanName, L2GatewayDevice l2GatewayDevice) {
+        this.l2GatewayDevice = l2GatewayDevice;
+        this.elanName = elanName;
+    }
+
+    public String getJobKey() {
+        return elanName;
+    }
+    @Override
+    public List<ListenableFuture<Void>> call() throws Exception {
+        LOG.info("running update mcast mac entry job for {} {}",
+                elanName, l2GatewayDevice.getHwvtepNodeId());
+        return Lists.newArrayList(
+                ElanL2GatewayMulticastUtils.updateRemoteMcastMacOnElanL2GwDevice(elanName, l2GatewayDevice));
+    }
+
+}
diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/LogicalSwitchAddedJob.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/LogicalSwitchAddedJob.java
new file mode 100644 (file)
index 0000000..7ad1c45
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.vpnservice.elan.l2gw.jobs;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepRemoteMcastMacListener;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.vpnservice.elan.utils.ElanUtils;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.attributes.Devices;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * The Class LogicalSwitchAddedWorker.
+ */
+public class LogicalSwitchAddedJob implements Callable<List<ListenableFuture<Void>>> {
+    /** The logical switch name. */
+    private String logicalSwitchName;
+
+    /** The physical device. */
+    private Devices physicalDevice;
+
+    /** The l2 gateway device. */
+    private L2GatewayDevice elanL2GwDevice;
+
+    /** The default vlan id. */
+    private Integer defaultVlanId;
+
+    private static final Logger LOG = LoggerFactory.getLogger(LogicalSwitchAddedJob.class);
+
+    public LogicalSwitchAddedJob(String logicalSwitchName, Devices physicalDevice, L2GatewayDevice l2GatewayDevice,
+            Integer defaultVlanId) {
+        this.logicalSwitchName = logicalSwitchName;
+        this.physicalDevice = physicalDevice;
+        this.elanL2GwDevice = l2GatewayDevice;
+        this.defaultVlanId = defaultVlanId;
+        LOG.debug("created logical switch added job for {} {}", logicalSwitchName, elanL2GwDevice.getHwvtepNodeId());
+    }
+
+    public String getJobKey() {
+        return logicalSwitchName;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.util.concurrent.Callable#call()
+     */
+    @Override
+    public List<ListenableFuture<Void>> call() throws Exception {
+        try {
+            LOG.debug("running logical switch added job for {} {}", logicalSwitchName, elanL2GwDevice.getHwvtepNodeId());
+            List<ListenableFuture<Void>> futures = new ArrayList<>();
+            String elan = ElanL2GatewayUtils.getElanFromLogicalSwitch(logicalSwitchName);
+
+            LOG.info("creating vlan bindings for {} {}", logicalSwitchName, elanL2GwDevice.getHwvtepNodeId());
+            futures.add(ElanL2GatewayUtils.updateVlanBindingsInL2GatewayDevice(
+                    new NodeId(elanL2GwDevice.getHwvtepNodeId()), logicalSwitchName, physicalDevice, defaultVlanId));
+            LOG.info("creating mast mac entries for {} {}", logicalSwitchName, elanL2GwDevice.getHwvtepNodeId());
+            futures.add(ElanL2GatewayMulticastUtils.handleMcastForElanL2GwDeviceAdd(logicalSwitchName, elanL2GwDevice));
+
+            List<IpAddress> expectedPhyLocatorIps = Lists.newArrayList();
+            HwvtepRemoteMcastMacListener list = new HwvtepRemoteMcastMacListener(ElanUtils.getDataBroker(),
+                    logicalSwitchName, elanL2GwDevice, expectedPhyLocatorIps,
+                    new Callable<List<ListenableFuture<Void>>>() {
+                        @Override
+                        public List<ListenableFuture<Void>> call() {
+                            LOG.info("adding remote ucast macs for {} {}", logicalSwitchName,
+                                    elanL2GwDevice.getHwvtepNodeId());
+                            List<ListenableFuture<Void>> futures = new ArrayList<>();
+                            futures.add(ElanL2GatewayUtils.installElanMacsInL2GatewayDevice(
+                                    logicalSwitchName, elanL2GwDevice));
+                            return futures;
+                        }
+                    });
+
+            return futures;
+        } catch (Throwable e) {
+            LOG.error("failed to add ls ", e);
+            return null;
+        }
+    }
+
+}
diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/LogicalSwitchDeletedJob.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/LogicalSwitchDeletedJob.java
new file mode 100644 (file)
index 0000000..f29e409
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.vpnservice.elan.l2gw.jobs;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+/**
+ * The Class LogicalSwitchDeletedJob.
+ */
+public class LogicalSwitchDeletedJob implements Callable<List<ListenableFuture<Void>>> {
+    private DataBroker broker;
+
+    /** The logical switch name. */
+    private String logicalSwitchName;
+
+    /** The physical device. */
+    private NodeId hwvtepNodeId;
+
+    private static final Logger LOG = LoggerFactory.getLogger(LogicalSwitchDeletedJob.class);
+
+    public LogicalSwitchDeletedJob(DataBroker broker, NodeId hwvtepNodeId, String logicalSwitchName) {
+        this.broker = broker;
+        this.hwvtepNodeId = hwvtepNodeId;
+        this.logicalSwitchName = logicalSwitchName;
+        LOG.debug("created logical switch deleted job for {} on {}", logicalSwitchName, hwvtepNodeId);
+    }
+
+    public String getJobKey() {
+        return logicalSwitchName;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.util.concurrent.Callable#call()
+     */
+    @Override
+    public List<ListenableFuture<Void>> call() throws Exception {
+        try {
+            LOG.debug("running logical switch deleted job for {} in {}", logicalSwitchName, hwvtepNodeId);
+            List<ListenableFuture<Void>> futures = new ArrayList<>();
+            futures.add(HwvtepUtils.deleteLogicalSwitch(broker, hwvtepNodeId, logicalSwitchName));
+            return futures;
+        } catch (Throwable e) {
+            LOG.error("failed to delete ls ", e);
+            return null;
+        }
+    }
+}
index c2558fe51b9aa78d8c6492af4b46851bc73cc6eb..d0e9e2e75877f477d5a307c143f7f059b008b728 100644 (file)
@@ -7,29 +7,26 @@
  */
 package org.opendaylight.vpnservice.elan.l2gw.listeners;
 
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
-import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LocalUcastMacs;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
-import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
-import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
-import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
-import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
-import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
-import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.collect.Lists;
+
 /**
  * A listener for Ucast MAC entries that are added/removed to/from an External Device (e.g., TOR).
  *
@@ -42,19 +39,14 @@ public class HwvtepLocalUcastMacListener extends
         AsyncClusteredDataChangeListenerBase<LocalUcastMacs, HwvtepLocalUcastMacListener> implements AutoCloseable {
 
     private DataBroker broker;
-    private EntityOwnershipService entityOwnershipService;
-    private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
     private ListenerRegistration<DataChangeListener> lstnerRegistration;
 
     private static final Logger logger = LoggerFactory.getLogger(HwvtepLocalUcastMacListener.class);
 
-    public HwvtepLocalUcastMacListener(DataBroker broker, EntityOwnershipService entityOwnershipService,
-            BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer) {
+    public HwvtepLocalUcastMacListener(DataBroker broker) {
         super(LocalUcastMacs.class, HwvtepLocalUcastMacListener.class);
 
         this.broker = broker;
-        this.entityOwnershipService = entityOwnershipService;
-        this.bindingNormalizedNodeSerializer = bindingNormalizedNodeSerializer;
         registerListener();
     }
 
@@ -103,8 +95,9 @@ public class HwvtepLocalUcastMacListener extends
         // Remove MAC from cache
         elanL2GwDevice.removeUcastLocalMac(macRemoved);
 
-        ElanL2GatewayUtils.unInstallL2GwUcastMacFromElan(entityOwnershipService, bindingNormalizedNodeSerializer, elan,
-                elanL2GwDevice, macRemoved);    }
+        ElanL2GatewayUtils.unInstallL2GwUcastMacFromElan(elan, elanL2GwDevice,
+                Lists.newArrayList(macRemoved.getMacEntryKey()));
+    }
 
     @Override
     protected void update(InstanceIdentifier<LocalUcastMacs> identifier, LocalUcastMacs original,
@@ -136,8 +129,7 @@ public class HwvtepLocalUcastMacListener extends
         // Cache MAC for furthur processing later
         elanL2GwDevice.addUcastLocalMac(macAdded);
 
-        ElanL2GatewayUtils.installL2GwUcastMacInElan(entityOwnershipService, bindingNormalizedNodeSerializer, elan,
-                elanL2GwDevice, macAddress);
+        ElanL2GatewayUtils.installL2GwUcastMacInElan(elan, elanL2GwDevice, macAddress);
     }
 
     @Override
index 9edbd86294f27b60d2d60d9790b8e2e6452de6b2..a0e4c6680d9f452a7f7346873e78cb971e14b859 100644 (file)
@@ -7,22 +7,16 @@
  */
 package org.opendaylight.vpnservice.elan.l2gw.listeners;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.Callable;
-
 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
-import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
 import org.opendaylight.vpnservice.datastoreutils.AsyncDataChangeListenerBase;
 import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
-import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
-import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.vpnservice.elan.l2gw.jobs.LogicalSwitchAddedJob;
 import org.opendaylight.vpnservice.elan.l2gw.utils.L2GatewayConnectionUtils;
-import org.opendaylight.vpnservice.elan.utils.ElanUtils;
 import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
 import org.opendaylight.vpnservice.utils.SystemPropertyReader;
 import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.attributes.Devices;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
@@ -31,8 +25,6 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.util.concurrent.ListenableFuture;
-
 /**
  * The listener class for listening to {@code LogicalSwitches}
  * add/delete/update.
@@ -60,6 +52,15 @@ public class HwvtepLogicalSwitchListener
     /** The default vlan id. */
     private Integer defaultVlanId;
 
+    /** Id of L2 Gateway connection responsible for this logical switch creation */
+    private Uuid l2GwConnId;
+
+    static DataStoreJobCoordinator dataStoreJobCoordinator;
+
+    public static void setDataStoreJobCoordinator(DataStoreJobCoordinator ds) {
+        dataStoreJobCoordinator = ds;
+    }
+
     /**
      * Instantiates a new hardware vtep logical switch listener.
      *
@@ -71,15 +72,18 @@ public class HwvtepLogicalSwitchListener
      *            the physical device
      * @param defaultVlanId
      *            the default vlan id
+     * @param l2GwConnId
+     *            the l2 gateway connection id
      */
     public HwvtepLogicalSwitchListener(L2GatewayDevice l2GatewayDevice, String logicalSwitchName,
-            Devices physicalDevice, Integer defaultVlanId) {
+            Devices physicalDevice, Integer defaultVlanId, Uuid l2GwConnId) {
         super(LogicalSwitches.class, HwvtepLogicalSwitchListener.class);
         this.nodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
         this.logicalSwitchName = logicalSwitchName;
         this.physicalDevice = physicalDevice;
         this.l2GatewayDevice = l2GatewayDevice;
         this.defaultVlanId = defaultVlanId;
+        this.l2GwConnId = l2GwConnId;
     }
 
     /*
@@ -162,12 +166,12 @@ public class HwvtepLogicalSwitchListener
         LOG.debug("Received Add DataChange Notification for identifier: {}, LogicalSwitches: {}", identifier,
                 logicalSwitchNew);
         try {
-            L2GatewayConnectionUtils.addL2DeviceToElanL2GwCache(logicalSwitchNew.getHwvtepNodeName().getValue(), l2GatewayDevice);
-            DataStoreJobCoordinator jobCoordinator = DataStoreJobCoordinator.getInstance();
-            LogicalSwitchAddedWorker logicalSwitchAddedWorker = new LogicalSwitchAddedWorker(nodeId, logicalSwitchNew);
-            String jobKey = ElanL2GatewayUtils.getL2GatewayConnectionJobKey(nodeId.getValue(),
-                    logicalSwitchNew.getHwvtepNodeName().getValue());
-            jobCoordinator.enqueueJob(jobKey, logicalSwitchAddedWorker,
+            L2GatewayDevice elanDevice = L2GatewayConnectionUtils.addL2DeviceToElanL2GwCache(
+                    logicalSwitchNew.getHwvtepNodeName().getValue(), l2GatewayDevice, l2GwConnId);
+
+            LogicalSwitchAddedJob logicalSwitchAddedWorker = new LogicalSwitchAddedJob(
+                    logicalSwitchName, physicalDevice, elanDevice, defaultVlanId);
+            dataStoreJobCoordinator.enqueueJob(logicalSwitchAddedWorker.getJobKey(), logicalSwitchAddedWorker,
                     SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
 
         } catch (Exception e) {
@@ -185,66 +189,4 @@ public class HwvtepLogicalSwitchListener
         }
     }
 
-    /**
-     * The Class LogicalSwitchAddedWorker.
-     */
-    private class LogicalSwitchAddedWorker implements Callable<List<ListenableFuture<Void>>> {
-        /** The logical switch new. */
-        LogicalSwitches logicalSwitchNew;
-
-        /**
-         * Instantiates a new logical switch added worker.
-         *
-         * @param nodeId
-         *            the node id
-         * @param logicalSwitchNew
-         *            the logical switch new
-         */
-        public LogicalSwitchAddedWorker(NodeId nodeId, LogicalSwitches logicalSwitchNew) {
-            this.logicalSwitchNew = logicalSwitchNew;
-        }
-
-        /*
-         * (non-Javadoc)
-         *
-         * @see java.util.concurrent.Callable#call()
-         */
-        @Override
-        public List<ListenableFuture<Void>> call() throws Exception {
-            try {
-                List<ListenableFuture<Void>> futures = new ArrayList<>();
-                String elan = ElanL2GatewayUtils.getElanFromLogicalSwitch(logicalSwitchName);
-                final L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils
-                        .getL2GatewayDeviceFromCache(elan, l2GatewayDevice.getHwvtepNodeId());
-                if (elanL2GwDevice == null) {
-                    LOG.error("Could not find L2GatewayDevice for ELAN: {}, nodeID:{} from cache",
-                            l2GatewayDevice.getHwvtepNodeId());
-                    return null;
-                } else {
-                    LOG.trace("got logical switch device {}", elanL2GwDevice);
-                    futures.add(ElanL2GatewayUtils.updateVlanBindingsInL2GatewayDevice(
-                            new NodeId(elanL2GwDevice.getHwvtepNodeId()), logicalSwitchName, physicalDevice, defaultVlanId));
-                    futures.add(ElanL2GatewayMulticastUtils.handleMcastForElanL2GwDeviceAdd(logicalSwitchName, elanL2GwDevice));
-
-                    HwvtepRemoteMcastMacListener list = new HwvtepRemoteMcastMacListener(ElanUtils.getDataBroker(),
-                            logicalSwitchName, elanL2GwDevice,
-                            new Callable<List<ListenableFuture<Void>>>() {
-
-                            @Override
-                            public List<ListenableFuture<Void>> call() {
-                                List<ListenableFuture<Void>> futures = new ArrayList<>();
-                                futures.add(ElanL2GatewayUtils.installElanMacsInL2GatewayDevice(
-                                        logicalSwitchName, elanL2GwDevice));
-                                return futures;
-                            }}
-                        );
-                    return futures;
-                }
-            } catch (Throwable e) {
-                LOG.error("failed to add ls ", e);
-                return null;
-            }
-        }
-
-    }
 }
\ No newline at end of file
index 3891246bc8e36237a8ab624ff2c89b2493ebaf6a..1841823039c4f2f3ed850da6470cfc689c98b426 100644 (file)
@@ -12,7 +12,6 @@ import java.util.ArrayList;
 import java.util.List;
 
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
@@ -39,7 +38,6 @@ import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
-import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -51,18 +49,13 @@ public class HwvtepNodeListener
     private static final Logger LOG = LoggerFactory.getLogger(HwvtepNodeListener.class);
 
     private DataBroker dataBroker;
-    private EntityOwnershipService entityOwnershipService;
-    private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
     private ItmRpcService itmRpcService;
     ElanInstanceManager elanInstanceManager;
 
-    public HwvtepNodeListener(final DataBroker dataBroker, EntityOwnershipService entityOwnershipService,
-            BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, ElanInstanceManager elanInstanceManager,
+    public HwvtepNodeListener(final DataBroker dataBroker, ElanInstanceManager elanInstanceManager,
             ItmRpcService itmRpcService) {
         super(Node.class, HwvtepNodeListener.class);
         this.dataBroker = dataBroker;
-        this.entityOwnershipService = entityOwnershipService;
-        this.bindingNormalizedNodeSerializer = bindingNormalizedNodeSerializer;
         this.itmRpcService = itmRpcService;
         this.elanInstanceManager = elanInstanceManager;
     }
@@ -85,43 +78,63 @@ public class HwvtepNodeListener
 
     @Override
     protected void remove(InstanceIdentifier<Node> key, Node nodeDeleted) {
-        LOG.debug("Received Node Remove Event: {}, {}", key, nodeDeleted.getNodeId().getValue());
+        String nodeId = nodeDeleted.getNodeId().getValue();
+        LOG.debug("Received Node Remove Event for {}", nodeId);
 
         PhysicalSwitchAugmentation psAugmentation = nodeDeleted.getAugmentation(PhysicalSwitchAugmentation.class);
         if (psAugmentation != null) {
             String psName = psAugmentation.getHwvtepNodeName().getValue();
+            LOG.info("Physical switch {} removed from node {} event received", psName, nodeId);
+
             L2GatewayDevice l2GwDevice = L2GatewayCacheUtils.getL2DeviceFromCache(psName);
             if (l2GwDevice != null) {
                 if (!L2GatewayConnectionUtils.isGatewayAssociatedToL2Device(l2GwDevice)) {
                     L2GatewayCacheUtils.removeL2DeviceFromCache(psName);
+                    LOG.debug("{} details removed from L2Gateway Cache", psName);
+                } else {
+                    LOG.debug("{} details are not removed from L2Gateway Cache as it has L2Gateway refrence", psName);
                 }
+
                 l2GwDevice.setConnected(false);
                 ElanL2GwCacheUtils.removeL2GatewayDeviceFromAllElanCache(psName);
             } else {
                 LOG.error("Unable to find L2 Gateway details for {}", psName);
             }
+        } else {
+            LOG.trace("Received Node Remove Event for {} is not related to Physical switch; it's not processed",
+                    nodeId);
         }
     }
 
     @Override
     protected void update(InstanceIdentifier<Node> key, Node nodeBefore, Node nodeAfter) {
-        LOG.debug("Received Node Update Event: {}, {}, {}", key, nodeBefore, nodeAfter);
+        if (LOG.isTraceEnabled()) {
+            LOG.trace("Received Node Update Event: Node Before: {}, Node After: {}", nodeBefore, nodeAfter);
+        }
     }
 
     @Override
     protected void add(InstanceIdentifier<Node> key, Node nodeAdded) {
-        LOG.debug("Received Node Add Event: {}, {}", key, nodeAdded.getNodeId().getValue());
+        String nodeId = nodeAdded.getNodeId().getValue();
+        LOG.debug("Received Node Add Event for {}", nodeId);
 
         PhysicalSwitchAugmentation psAugmentation = nodeAdded.getAugmentation(PhysicalSwitchAugmentation.class);
         if (psAugmentation != null) {
             String psName = psAugmentation.getHwvtepNodeName().getValue();
+            LOG.info("Physical switch {} added to node {} event received", psName, nodeId);
+
             L2GatewayDevice l2GwDevice = L2GatewayCacheUtils.getL2DeviceFromCache(psName);
             if (l2GwDevice == null) {
+                LOG.debug("{} details are not present in L2Gateway Cache; added now!", psName);
+
                 l2GwDevice = new L2GatewayDevice();
                 l2GwDevice.setDeviceName(psName);
                 L2GatewayCacheUtils.addL2DeviceToCache(psName, l2GwDevice);
+            } else {
+                LOG.debug("{} details are present in L2Gateway Cache and same reference used for updates", psName);
             }
 
+            l2GwDevice.setConnected(true);
             String hwvtepNodeId = getManagedByNodeId(psAugmentation.getManagedBy());
             l2GwDevice.setHwvtepNodeId(hwvtepNodeId);
             List<TunnelIps> tunnelIps = psAugmentation.getTunnelIps();
@@ -130,6 +143,11 @@ public class HwvtepNodeListener
                     IpAddress tunnelIpAddr = tunnelIp.getTunnelIpsKey();
                     l2GwDevice.addTunnelIp(tunnelIpAddr);
                     if (L2GatewayConnectionUtils.isGatewayAssociatedToL2Device(l2GwDevice)) {
+                        if (LOG.isDebugEnabled()) {
+                            LOG.debug("L2Gateway {} associated for {} physical switch; creating ITM tunnels for {}",
+                                    l2GwDevice.getL2GatewayIds(), psName, tunnelIpAddr);
+                        }
+
                         // It's a pre-provision scenario
                         // Initiate ITM tunnel creation
                         ElanL2GatewayUtils.createItmTunnels(itmRpcService, hwvtepNodeId, psName, tunnelIpAddr);
@@ -139,15 +157,25 @@ public class HwvtepNodeListener
                         List<L2gatewayConnection> l2GwConns = getAssociatedL2GwConnections(dataBroker,
                                 l2GwDevice.getL2GatewayIds());
                         if (l2GwConns != null) {
+                            LOG.debug("L2GatewayConnections associated for {} physical switch", psName);
+
                             for (L2gatewayConnection l2GwConn : l2GwConns) {
-                                L2GatewayConnectionUtils.addL2GatewayConnection(dataBroker, entityOwnershipService,
-                                        bindingNormalizedNodeSerializer, elanInstanceManager, l2GwConn, psName);
+                                LOG.trace("L2GatewayConnection {} changes executed on physical switch {}",
+                                        l2GwConn.getL2gatewayId(), psName);
+
+                                L2GatewayConnectionUtils.addL2GatewayConnection(l2GwConn, psName);
                             }
                         }
                         //TODO handle deleted l2gw connections while the device is offline
                     }
                 }
             }
+
+            if (LOG.isTraceEnabled()) {
+                LOG.trace("L2Gateway cache updated with below details: {}", l2GwDevice);
+            }
+        } else {
+            LOG.trace("Received Node Add Event for {} is not related to Physical switch; it's not processed", nodeId);
         }
     }
 
diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepPhysicalLocatorListener.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepPhysicalLocatorListener.java
new file mode 100644 (file)
index 0000000..04f6304
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.vpnservice.elan.l2gw.listeners;
+
+import com.google.common.collect.Lists;
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+
+/**
+ * Listener for physical locator presence in operational datastore
+ *
+ *
+ *
+ */
+public class HwvtepPhysicalLocatorListener extends
+        AsyncClusteredDataChangeListenerBase<TerminationPoint, HwvtepPhysicalLocatorListener> implements AutoCloseable {
+
+    private DataBroker broker;
+    private ListenerRegistration<DataChangeListener> lstnerRegistration;
+
+    private static final Logger logger = LoggerFactory.getLogger(HwvtepPhysicalLocatorListener.class);
+
+    public HwvtepPhysicalLocatorListener(DataBroker broker) {
+        super(TerminationPoint.class, HwvtepPhysicalLocatorListener.class);
+
+        this.broker = broker;
+        registerListener();
+        logger.debug("created HwvtepPhysicalLocatorListener");
+    }
+
+    static Map<InstanceIdentifier<TerminationPoint>, List<Runnable>> waitingJobsList = new ConcurrentHashMap<>();
+    static Map<InstanceIdentifier<TerminationPoint>, Boolean> teps = new ConcurrentHashMap<>();
+
+    public static void runJobAfterPhysicalLocatorIsAvialable(InstanceIdentifier<TerminationPoint> key, Runnable runnable) {
+        if (teps.get(key) != null) {
+            logger.debug("physical locator already available {} running job ", key);
+            runnable.run();
+            return;
+        }
+        synchronized (HwvtepPhysicalLocatorListener.class) {
+            List<Runnable> list = waitingJobsList.get(key);
+            if (list == null) {
+                waitingJobsList.put(key, Lists.newArrayList(runnable));
+            } else {
+                list.add(runnable);
+            }
+            logger.debug("added the job to wait list of physical locator {}", key);
+        }
+    }
+
+    protected void registerListener() {
+        try {
+            lstnerRegistration = this.broker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+                    InstanceIdentifier.create(NetworkTopology.class).child(Topology.class).child(Node.class).
+                            child(TerminationPoint.class), this, DataChangeScope.BASE);
+        } catch (final Exception e) {
+            logger.error("Hwvtep LocalUcasMacs DataChange listener registration failed !", e);
+            throw new IllegalStateException("Hwvtep LocalUcasMacs DataChange listener registration failed .", e);
+        }
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (lstnerRegistration != null) {
+            try {
+                lstnerRegistration.close();
+            } catch (final Exception e) {
+                logger.error("Error when cleaning up DataChangeListener.", e);
+            }
+            lstnerRegistration = null;
+        }
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<TerminationPoint> identifier, TerminationPoint del) {
+        logger.trace("physical locator removed {}", identifier);
+        teps.remove(identifier);
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<TerminationPoint> identifier, TerminationPoint original, TerminationPoint update) {
+        logger.trace("physical locator available {}", identifier);
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<TerminationPoint> identifier, TerminationPoint add) {
+        logger.trace("physical locator available {}", identifier);
+        teps.put(identifier, true);
+        List<Runnable> runnableList = null;
+        synchronized (HwvtepPhysicalLocatorListener.class) {
+            runnableList = waitingJobsList.get(identifier);
+            waitingJobsList.remove(identifier);
+        }
+        if (runnableList != null) {
+            logger.debug("physical locator available {} running jobs ", identifier);
+            for (Runnable r : runnableList) {
+                r.run();
+            }
+        } else {
+            logger.debug("no jobs are waiting for physical locator {}", identifier);
+        }
+    }
+
+    @Override
+    protected InstanceIdentifier<TerminationPoint> getWildCardPath() {
+        return InstanceIdentifier.create(NetworkTopology.class).child(Topology.class).child(Node.class).
+                child(TerminationPoint.class);
+    }
+
+    @Override
+    protected ClusteredDataChangeListener getDataChangeListener() {
+        return HwvtepPhysicalLocatorListener.this;
+    }
+
+    @Override
+    protected DataChangeScope getDataChangeScope() {
+        return DataChangeScope.BASE;
+    }
+}
index 520462715c07d0d154d367ebeef0ab0567d13618..9f80390e499e1afcda5c342f31259cf38eef5e5b 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.vpnservice.elan.l2gw.listeners;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.Callable;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -23,9 +24,13 @@ import org.opendaylight.vpnservice.elan.utils.ElanUtils;
 import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
 import org.opendaylight.vpnservice.utils.SystemPropertyReader;
 import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSet;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@@ -50,6 +55,8 @@ public class HwvtepRemoteMcastMacListener
     /** The node id. */
     private NodeId nodeId;
 
+    private List<IpAddress> expectedPhyLocatorIps;
+
     DataBroker broker;
 
     String logicalSwitchName;
@@ -57,37 +64,50 @@ public class HwvtepRemoteMcastMacListener
     AtomicBoolean executeTask = new AtomicBoolean(true);
 
     Callable<List<ListenableFuture<Void>>> taskToRun;
+
+    static DataStoreJobCoordinator dataStoreJobCoordinator;
+
+    public static void setDataStoreJobCoordinator(DataStoreJobCoordinator ds) {
+        dataStoreJobCoordinator = ds;
+    }
+
     /**
      * Instantiates a new remote mcast mac listener.
      *
      * @param broker
      *            the mdsal databroker reference
      * @param logicalSwitchName
+     *            the logical switch name
      * @param l2GatewayDevice
      *            the l2 gateway device
+     * @param expectedPhyLocatorIps
+     *            the expected phy locator ips
      * @param task
      *            the task to be run upon data presence
      * @throws Exception
+     *             the exception
      */
     public HwvtepRemoteMcastMacListener(DataBroker broker, String logicalSwitchName, L2GatewayDevice l2GatewayDevice,
-            Callable<List<ListenableFuture<Void>>> task) throws Exception {
+            List<IpAddress> expectedPhyLocatorIps, Callable<List<ListenableFuture<Void>>> task) throws Exception {
         super(RemoteMcastMacs.class, HwvtepRemoteMcastMacListener.class);
         this.nodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
         this.broker = broker;
         this.taskToRun = task;
         this.logicalSwitchName = logicalSwitchName;
-        LOG.debug("registering the listener for mcast mac ");
+        this.expectedPhyLocatorIps = expectedPhyLocatorIps;
+        LOG.info("registering the listener for mcast mac ");
         registerListener(LogicalDatastoreType.OPERATIONAL, broker);
+        LOG.info("registered the listener for mcast mac ");
         if (isDataPresentInOpDs(getWildCardPath())) {
-            LOG.debug("mcast mac already present running the task ");
+            LOG.info("mcast mac already present running the task ");
             if (executeTask.compareAndSet(true, false)) {
                 runTask();
             }
         }
     }
 
-    private boolean isDataPresentInOpDs(InstanceIdentifier<? extends DataObject> path) throws Exception {
-        Optional<? extends DataObject> mac = null;
+    private boolean isDataPresentInOpDs(InstanceIdentifier<RemoteMcastMacs> path) throws Exception {
+        Optional<RemoteMcastMacs> mac = null;
         try {
             mac = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL, path);
         } catch (Throwable e) {
@@ -95,6 +115,21 @@ public class HwvtepRemoteMcastMacListener
         if (mac == null || !mac.isPresent()) {
             return false;
         }
+        if (this.expectedPhyLocatorIps != null && !this.expectedPhyLocatorIps.isEmpty()) {
+            RemoteMcastMacs remoteMcastMac = mac.get();
+            if (remoteMcastMac.getLocatorSet() == null || remoteMcastMac.getLocatorSet().isEmpty()) {
+                return false;
+            }
+            for (IpAddress ip : this.expectedPhyLocatorIps) {
+                boolean ipExists = ElanL2GatewayUtils.checkIfPhyLocatorAlreadyExistsInRemoteMcastEntry(this.nodeId,
+                        remoteMcastMac, ip);
+                if (!ipExists) {
+                    LOG.trace("IP [{}] not found in RemoteMcastMacs for node [{}]", String.valueOf(ip.getValue()),
+                            this.nodeId.getValue());
+                    return false;
+                }
+            }
+        }
         return true;
     }
 
@@ -175,8 +210,9 @@ public class HwvtepRemoteMcastMacListener
      */
     @Override
     protected void add(InstanceIdentifier<RemoteMcastMacs> identifier, RemoteMcastMacs mcastMac) {
-        LOG.debug("Received Add DataChange Notification for identifier: {}, RemoteMcastMacs: {}", identifier,
-                mcastMac);
+        LOG.debug("Received Add DataChange Notification for identifier: {}, RemoteMcastMacs: {}", identifier, mcastMac);
+        // No isDataPresentInOpDs check is done as assuming all the expected phy
+        // locator ips will be available during add
         if (executeTask.compareAndSet(true, false)) {
             runTask();
         }
@@ -184,9 +220,9 @@ public class HwvtepRemoteMcastMacListener
 
     void runTask() {
         try {
-            DataStoreJobCoordinator jobCoordinator = DataStoreJobCoordinator.getInstance();
-            String jobKey = ElanL2GatewayUtils.getL2GatewayConnectionJobKey(nodeId.getValue(), ElanConstants.UNKNOWN_DMAC);
-            jobCoordinator.enqueueJob(jobKey, taskToRun, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
+
+            String jobKey = ElanL2GatewayUtils.getL2GatewayConnectionJobKey(nodeId.getValue(), nodeId.getValue());
+            dataStoreJobCoordinator.enqueueJob(jobKey, taskToRun, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
         } catch (Exception e) {
             LOG.error("Failed to handle remote mcast mac - add: {}", e);
         } finally {
index 305bb1c0ac161cf752e0178affffc960fbaaf93f..ad6296a9251893579ff929f833378e2136af9f4d 100644 (file)
@@ -10,7 +10,6 @@ package org.opendaylight.vpnservice.elan.l2gw.listeners;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
 import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
@@ -19,7 +18,6 @@ import org.opendaylight.vpnservice.elan.l2gw.utils.L2GatewayConnectionUtils;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.connections.attributes.L2gatewayConnections;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.connections.attributes.l2gatewayconnections.L2gatewayConnection;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
-import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
@@ -31,16 +29,11 @@ public class L2GatewayConnectionListener extends AsyncClusteredDataChangeListene
 
     private ListenerRegistration<DataChangeListener> listenerRegistration;
     private final DataBroker broker;
-    private EntityOwnershipService entityOwnershipService;
-    private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
     private ElanInstanceManager elanInstanceManager;
 
-    public L2GatewayConnectionListener(final DataBroker db, EntityOwnershipService entityOwnershipService,
-            BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, ElanInstanceManager elanInstanceManager) {
+    public L2GatewayConnectionListener(final DataBroker db, ElanInstanceManager elanInstanceManager) {
         super(L2gatewayConnection.class, L2GatewayConnectionListener.class);
         broker = db;
-        this.entityOwnershipService = entityOwnershipService;
-        this.bindingNormalizedNodeSerializer = bindingNormalizedNodeSerializer;
         this.elanInstanceManager = elanInstanceManager;
         registerListener(db);
     }
@@ -74,33 +67,30 @@ public class L2GatewayConnectionListener extends AsyncClusteredDataChangeListene
     @Override
     protected void add(final InstanceIdentifier<L2gatewayConnection> identifier, final L2gatewayConnection input) {
         if (LOG.isTraceEnabled()) {
-            LOG.trace("Adding L2gatewayConnection : key: " + identifier + ", value=" + input);
+            LOG.trace("Adding L2gatewayConnection: {}", input);
         }
 
         // Get associated L2GwId from 'input'
         // Create logical switch in each of the L2GwDevices part of L2Gw
         // Logical switch name is network UUID
         // Add L2GwDevices to ELAN
-        L2GatewayConnectionUtils.addL2GatewayConnection(broker, entityOwnershipService, bindingNormalizedNodeSerializer,
-                elanInstanceManager, input);
+        L2GatewayConnectionUtils.addL2GatewayConnection(input);
     }
 
     @Override
     protected void remove(InstanceIdentifier<L2gatewayConnection> identifier, L2gatewayConnection input) {
         if (LOG.isTraceEnabled()) {
-            LOG.trace("Removing L2gatewayConnection : key: " + identifier + ", value=" + input);
+            LOG.trace("Removing L2gatewayConnection: {}", input);
         }
 
-        L2GatewayConnectionUtils.deleteL2GatewayConnection(broker, entityOwnershipService, bindingNormalizedNodeSerializer,
-                elanInstanceManager, input);
+        L2GatewayConnectionUtils.deleteL2GatewayConnection(input);
     }
 
     @Override
     protected void update(InstanceIdentifier<L2gatewayConnection> identifier, L2gatewayConnection original,
             L2gatewayConnection update) {
         if (LOG.isTraceEnabled()) {
-            LOG.trace("Updating L2gatewayConnection : key: " + identifier + ", original value=" + original
-                    + ", update value=" + update);
+            LOG.trace("Updating L2gatewayConnection : original value={}, updated value={}", original, update);
         }
     }
 
index 498530cebcb0de178d7a1a8cacff081df00221f7..ca700aadc4e5d1879df38c03dddd9c2acab434cc 100644 (file)
@@ -16,8 +16,10 @@ import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
 import org.opendaylight.vpnservice.elan.internal.ElanInstanceManager;
 import org.opendaylight.vpnservice.elan.internal.ElanInterfaceManager;
+import org.opendaylight.vpnservice.elan.l2gw.jobs.HwvtepDeviceMcastMacUpdateJob;
 import org.opendaylight.vpnservice.elan.utils.ElanConstants;
 import org.opendaylight.vpnservice.elan.utils.ElanUtils;
 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
@@ -36,9 +38,9 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hw
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSet;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSetBuilder;
-//import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev150129.DesignatedSwitchesForExternalTunnels;
-//import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev150129.designated.switches._for.external.tunnels.DesignatedSwitchForTunnel;
-//import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev150129.designated.switches._for.external.tunnels.DesignatedSwitchForTunnelKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.DesignatedSwitchesForExternalTunnels;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnelKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
@@ -68,6 +70,12 @@ public class ElanL2GatewayMulticastUtils {
     /** The elan interface manager. */
     private static ElanInterfaceManager elanInterfaceManager;
 
+    static DataStoreJobCoordinator dataStoreJobCoordinator;
+
+    public static void setDataStoreJobCoordinator(DataStoreJobCoordinator ds) {
+        dataStoreJobCoordinator = ds;
+    }
+
     /**
      * Sets the broker.
      *
@@ -108,7 +116,7 @@ public class ElanL2GatewayMulticastUtils {
      * @return the listenable future
      */
     public static ListenableFuture<Void> handleMcastForElanL2GwDeviceAdd(String elanName, L2GatewayDevice device) {
-        return updateMcastMacs(elanName, device, true/* updateThisDevice */);
+        return updateMcastMacsForAllElanDevices(elanName, device, true/* updateThisDevice */);
     }
 
     /**
@@ -124,22 +132,9 @@ public class ElanL2GatewayMulticastUtils {
         SettableFuture<Void> future = SettableFuture.create();
         future.set(null);
         try {
-            ConcurrentMap<String, L2GatewayDevice> mapL2gwDevices = ElanL2GwCacheUtils
-                    .getAllElanL2GatewayDevicesFromCache(elanName);
-            if (mapL2gwDevices == null || mapL2gwDevices.isEmpty()) {
-                LOG.trace("No L2GatewayDevices to configure RemoteMcastMac for elan {}", elanName);
-                return future;
-            }
-            List<DpnInterfaces> dpns = ElanUtils.getInvolvedDpnsInElan(elanName);
-
-            // TODO revisit
-            L2GatewayDevice firstDevice = mapL2gwDevices.values().iterator().next();
-            List<IpAddress> dpnsTepIps = getAllTepIpsOfDpns(firstDevice, dpns);
-            List<IpAddress> l2GwDevicesTepIps = getAllTepIpsOfL2GwDevices(mapL2gwDevices);
-
             WriteTransaction transaction = broker.newWriteOnlyTransaction();
-            for (L2GatewayDevice device : mapL2gwDevices.values()) {
-                updateRemoteMcastMac(transaction, elanName, device, dpnsTepIps, l2GwDevicesTepIps);
+            for (L2GatewayDevice device : ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName).values()) {
+                prepareRemoteMcastMacUpdateOnDevice(transaction, elanName, device);
             }
             return transaction.submit();
         } catch (Throwable e) {
@@ -148,8 +143,40 @@ public class ElanL2GatewayMulticastUtils {
         return future;
     }
 
+    public static void scheduleMcastMacUpdateJob(String elanName, L2GatewayDevice device) {
+        HwvtepDeviceMcastMacUpdateJob job = new HwvtepDeviceMcastMacUpdateJob(elanName,device);
+        dataStoreJobCoordinator.enqueueJob(job.getJobKey(), job);
+    }
+
     /**
-     * Update mcast macs.
+     * Update remote mcast mac on elan l2 gw device.
+     *
+     * @param elanName
+     *            the elan name
+     * @param device
+     *            the device
+     * @return the listenable future
+     */
+    public static ListenableFuture<Void> updateRemoteMcastMacOnElanL2GwDevice(String elanName, L2GatewayDevice device) {
+        WriteTransaction transaction = broker.newWriteOnlyTransaction();
+        prepareRemoteMcastMacUpdateOnDevice(transaction, elanName, device);
+        return transaction.submit();
+    }
+
+    public static void prepareRemoteMcastMacUpdateOnDevice(WriteTransaction transaction,String elanName,
+                                                           L2GatewayDevice device) {
+        ConcurrentMap<String, L2GatewayDevice> elanL2gwDevices = ElanL2GwCacheUtils
+                .getInvolvedL2GwDevices(elanName);
+        List<DpnInterfaces> dpns = ElanUtils.getInvolvedDpnsInElan(elanName);
+        List<IpAddress> dpnsTepIps = getAllTepIpsOfDpns(device, dpns);
+        List<IpAddress> l2GwDevicesTepIps = getAllTepIpsOfL2GwDevices(elanL2gwDevices);
+        preapareRemoteMcastMacEntry(transaction, elanName, device, dpnsTepIps, l2GwDevicesTepIps);
+    }
+
+    /**
+     * Update mcast macs for this elan.
+     * for all dpns in this elan  recompute and update broadcast group
+     * for all l2gw devices in this elan recompute and update remote mcast mac entry
      *
      * @param elanName
      *            the elan name
@@ -159,19 +186,19 @@ public class ElanL2GatewayMulticastUtils {
      *            the update this device
      * @return the listenable future
      */
-    public static ListenableFuture<Void> updateMcastMacs(String elanName, L2GatewayDevice device,
-            boolean updateThisDevice) {
+    public static ListenableFuture<Void> updateMcastMacsForAllElanDevices(String elanName, L2GatewayDevice device,
+                                                                          boolean updateThisDevice) {
 
         SettableFuture<Void> ft = SettableFuture.create();
         ft.set(null);
 
         ElanInstance elanInstance = elanInstanceManager.getElanInstanceByName(elanName);
-        elanInterfaceManager.updateElanBroadcastGroup(elanInstance);
+        elanInterfaceManager.updateRemoteBroadcastGroupForAllElanDpns(elanInstance);
 
         List<DpnInterfaces> dpns = ElanUtils.getInvolvedDpnsInElan(elanName);
 
         ConcurrentMap<String, L2GatewayDevice> devices = ElanL2GwCacheUtils
-                .getAllElanL2GatewayDevicesFromCache(elanName);
+                .getInvolvedL2GwDevices(elanName);
 
         List<IpAddress> dpnsTepIps = getAllTepIpsOfDpns(device, dpns);
         List<IpAddress> l2GwDevicesTepIps = getAllTepIpsOfL2GwDevices(devices);
@@ -182,14 +209,14 @@ public class ElanL2GatewayMulticastUtils {
 
         WriteTransaction transaction = broker.newWriteOnlyTransaction();
         if (updateThisDevice) {
-            updateRemoteMcastMac(transaction, elanName, device, dpnsTepIps, l2GwDevicesTepIps);
+            preapareRemoteMcastMacEntry(transaction, elanName, device, dpnsTepIps, l2GwDevicesTepIps);
         }
 
         // TODO: Need to revisit below logic as logical switches might not be
-        // created to configure RemoteMcastMac entry
+        // present to configure RemoteMcastMac entry
         for (L2GatewayDevice otherDevice : devices.values()) {
             if (!otherDevice.getDeviceName().equals(device.getDeviceName())) {
-                updateRemoteMcastMac(transaction, elanName, otherDevice, dpnsTepIps, l2GwDevicesTepIps);
+                preapareRemoteMcastMacEntry(transaction, elanName, otherDevice, dpnsTepIps, l2GwDevicesTepIps);
             }
         }
         return transaction.submit();
@@ -211,22 +238,21 @@ public class ElanL2GatewayMulticastUtils {
      *            the l2 gw devices tep ips
      * @return the write transaction
      */
-    private static WriteTransaction updateRemoteMcastMac(WriteTransaction transaction, String elanName,
-            L2GatewayDevice device, List<IpAddress> dpnsTepIps, List<IpAddress> l2GwDevicesTepIps) {
+    private static void preapareRemoteMcastMacEntry(WriteTransaction transaction, String elanName,
+                                                    L2GatewayDevice device, List<IpAddress> dpnsTepIps,
+                                                    List<IpAddress> l2GwDevicesTepIps) {
         NodeId nodeId = new NodeId(device.getHwvtepNodeId());
         String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName);
 
-        ArrayList<IpAddress> otherTepIps = new ArrayList<>(l2GwDevicesTepIps);
-        otherTepIps.remove(device.getTunnelIp());
-
-        if (!dpnsTepIps.isEmpty()) {
-            otherTepIps.addAll(dpnsTepIps);
-        } else {
+        ArrayList<IpAddress> remoteTepIps = new ArrayList<>(l2GwDevicesTepIps);
+        remoteTepIps.remove(device.getTunnelIp());
+        remoteTepIps.addAll(dpnsTepIps);
+        if (dpnsTepIps.isEmpty()) {
             // If no dpns in elan, configure dhcp designated switch Tep Ip as a
             // physical locator in l2 gw device
             IpAddress dhcpDesignatedSwitchTepIp = getTepIpOfDesignatedSwitchForExternalTunnel(device, elanName);
             if (dhcpDesignatedSwitchTepIp != null) {
-                otherTepIps.add(dhcpDesignatedSwitchTepIp);
+                remoteTepIps.add(dhcpDesignatedSwitchTepIp);
 
                 HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
                         .createHwvtepPhysicalLocatorAugmentation(String.valueOf(dhcpDesignatedSwitchTepIp.getValue()));
@@ -241,10 +267,9 @@ public class ElanL2GatewayMulticastUtils {
             }
         }
 
-        putRemoteMcastMac(transaction, nodeId, logicalSwitchName, otherTepIps);
+        putRemoteMcastMac(transaction, nodeId, logicalSwitchName, remoteTepIps);
         LOG.info("Adding RemoteMcastMac for node: {} with physical locators: {}", device.getHwvtepNodeId(),
-                otherTepIps);
-        return transaction;
+                remoteTepIps);
     }
 
     /**
@@ -281,12 +306,10 @@ public class ElanL2GatewayMulticastUtils {
     /**
      * Gets all the tep ips of dpns.
      *
-     * @param device
+     * @param l2GwDevice
      *            the device
      * @param dpns
      *            the dpns
-     * @param devices
-     *            the devices
      * @return the all tep ips of dpns and devices
      */
     private static List<IpAddress> getAllTepIpsOfDpns(L2GatewayDevice l2GwDevice, List<DpnInterfaces> dpns) {
@@ -327,7 +350,7 @@ public class ElanL2GatewayMulticastUtils {
      */
     public static List<ListenableFuture<Void>> handleMcastForElanL2GwDeviceDelete(ElanInstance elanInstance,
             L2GatewayDevice l2GatewayDevice) {
-        ListenableFuture<Void> updateMcastMacsFuture = updateMcastMacs(elanInstance.getElanInstanceName(),
+        ListenableFuture<Void> updateMcastMacsFuture = updateMcastMacsForAllElanDevices(elanInstance.getElanInstanceName(),
                 l2GatewayDevice, false/* updateThisDevice */);
         ListenableFuture<Void> deleteRemoteMcastMacFuture = deleteRemoteMcastMac(
                 new NodeId(l2GatewayDevice.getHwvtepNodeId()), elanInstance.getElanInstanceName());
@@ -374,13 +397,12 @@ public class ElanL2GatewayMulticastUtils {
     public static IpAddress getTepIpOfDesignatedSwitchForExternalTunnel(L2GatewayDevice l2GwDevice,
             String elanInstanceName) {
         IpAddress tepIp = null;
-     // TODO: Uncomment after DHCP changes are merged
-/*        DesignatedSwitchForTunnel desgSwitch = getDesignatedSwitchForExternalTunnel(l2GwDevice.getTunnelIp(),
+        DesignatedSwitchForTunnel desgSwitch = getDesignatedSwitchForExternalTunnel(l2GwDevice.getTunnelIp(),
                 elanInstanceName);
         if (desgSwitch != null) {
             tepIp = ElanL2GatewayUtils.getSourceDpnTepIp(BigInteger.valueOf(desgSwitch.getDpId()),
                     new NodeId(l2GwDevice.getHwvtepNodeId()));
-        }*/
+        }
         return tepIp;
     }
 
@@ -393,8 +415,7 @@ public class ElanL2GatewayMulticastUtils {
      *            the elan instance name
      * @return the designated switch for external tunnel
      */
-    // TODO: Uncomment after DHCP changes are merged
-/*    public static DesignatedSwitchForTunnel getDesignatedSwitchForExternalTunnel(IpAddress tunnelIp,
+    public static DesignatedSwitchForTunnel getDesignatedSwitchForExternalTunnel(IpAddress tunnelIp,
             String elanInstanceName) {
         InstanceIdentifier<DesignatedSwitchForTunnel> instanceIdentifier = InstanceIdentifier
                 .builder(DesignatedSwitchesForExternalTunnels.class)
@@ -406,6 +427,6 @@ public class ElanL2GatewayMulticastUtils {
             return designatedSwitchForTunnelOptional.get();
         }
         return null;
-    }*/
+    }
 
 }
index e695055f90ae0e8a0a575dab076398e110af6dfb..4a18a9ae447813949be9e9613cd54a870490848e 100644 (file)
@@ -13,23 +13,29 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
 import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.vpnservice.elan.l2gw.jobs.DeleteL2GwDeviceMacsFromElanJob;
 import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
+import org.opendaylight.vpnservice.elan.l2gw.jobs.LogicalSwitchDeletedJob;
+import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepPhysicalLocatorListener;
+import org.opendaylight.vpnservice.elan.utils.ElanClusterUtils;
+import org.opendaylight.vpnservice.elan.utils.ElanConstants;
 import org.opendaylight.vpnservice.elan.utils.ElanUtils;
 import org.opendaylight.vpnservice.interfacemgr.IfmUtil;
 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
 import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
 import org.opendaylight.vpnservice.utils.SystemPropertyReader;
-import org.opendaylight.vpnservice.utils.clustering.ClusteringUtils;
 import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundConstants;
 import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundUtils;
 import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
@@ -40,10 +46,16 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.attributes.Devices;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepLogicalSwitchRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LocalUcastMacs;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteUcastMacs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSet;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.port.attributes.VlanBindings;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMac;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
@@ -51,15 +63,20 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.e
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.forwarding.entries.MacEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeVxlan;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.AddL2GwDeviceInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetExternalTunnelInterfaceNameInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetExternalTunnelInterfaceNameOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
-import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -69,7 +86,6 @@ import com.google.common.collect.Lists;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.SettableFuture;
 
 /**
  * It gathers a set of utility methods that handle ELAN configuration in external Devices (where external means
@@ -81,9 +97,13 @@ import com.google.common.util.concurrent.SettableFuture;
  *
  */
 public class ElanL2GatewayUtils {
-
-    private static DataBroker         broker;
-    private static ItmRpcService      itmRpcService;
+    private static DataBroker broker;
+    private static ItmRpcService itmRpcService;
+    private static DataStoreJobCoordinator dataStoreJobCoordinator;
+    private static Timer LogicalSwitchDeleteJobTimer = new Timer();
+    private static final int LOGICAL_SWITCH_DELETE_DELAY = 120000;
+    private static ConcurrentMap<Pair<NodeId, String>, TimerTask> LogicalSwitchDeletedTasks =
+            new ConcurrentHashMap<Pair<NodeId, String>, TimerTask>();
 
     private static final Logger LOG = LoggerFactory.getLogger(ElanL2GatewayUtils.class);
 
@@ -108,69 +128,21 @@ public class ElanL2GatewayUtils {
     }
 
     /**
-     * Installs the given MAC as a remote mac in all external devices (as of
-     * now, TORs) that participate in the given Elan.
+     * Sets DataStoreJobCoordinator
      *
-     * @param elanInstance
-     *            Elan to which the interface belongs to
-     * @param dpId
-     *            Id of the DPN where the macs are located. Needed for selecting
-     *            the right tunnel
-     * @param macAddresses
-     *            the mac addresses
+     * @param dsJobCoordinator
+     *            the new dataStoreJobCoordinator
      */
-    public static void installMacsInElanExternalDevices(ElanInstance elanInstance, BigInteger dpId,
-            List<PhysAddress> macAddresses) {
-        String logicalSwitchName = getElanFromLogicalSwitch(elanInstance.getElanInstanceName());
-        ConcurrentMap<String, L2GatewayDevice> elanDevices = ElanL2GwCacheUtils
-                .getAllElanL2GatewayDevicesFromCache(elanInstance.getElanInstanceName());
-        for (L2GatewayDevice externalDevice : elanDevices.values()) {
-            NodeId nodeId = new NodeId(externalDevice.getHwvtepNodeId());
-            IpAddress dpnTepIp = getSourceDpnTepIp(dpId, nodeId);
-            LOG.trace("Dpn Tep IP: {} for dpnId: {} and nodeId: {}", dpnTepIp, dpId, nodeId);
-            if (dpnTepIp == null) {
-                LOG.error("TEP IP not found for dpnId {} and nodeId {}", dpId, nodeId);
-                continue;
-            }
-            installMacsInExternalDeviceAsRemoteUcastMacs(externalDevice.getHwvtepNodeId(), macAddresses,
-                    logicalSwitchName, dpnTepIp);
-        }
+    public static void setDataStoreJobCoordinator(DataStoreJobCoordinator dsJobCoordinator) {
+        dataStoreJobCoordinator = dsJobCoordinator;
     }
 
     /**
-     * Installs a list of Mac Addresses as remote Ucast address in an external
-     * device using the hwvtep-southbound.
-     *
-     * @param deviceNodeId
-     *            NodeId if the ExternalDevice where the macs must be installed
-     *            in.
-     * @param macAddresses
-     *            List of Mac addresses to be installed in the external device.
-     * @param logicalSwitchName
-     *            the logical switch name
-     * @param remoteVtepIp
-     *            VTEP's IP in this CSS used for the tunnel with external
-     *            device.
-     */
-    private static ListenableFuture<Void> installMacsInExternalDeviceAsRemoteUcastMacs(String deviceNodeId,
-            List<PhysAddress> macAddresses, String logicalSwitchName, IpAddress remoteVtepIp) {
-        NodeId nodeId = new NodeId(deviceNodeId);
-        HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
-                .createHwvtepPhysicalLocatorAugmentation(String.valueOf(remoteVtepIp.getValue()));
-        List<RemoteUcastMacs> macs = new ArrayList<RemoteUcastMacs>();
-        for (PhysAddress mac : macAddresses) {
-            // TODO: Query ARP cache to get IP address corresponding to
-            // the MAC
-            IpAddress ipAddress = null;
-            macs.add(HwvtepSouthboundUtils.createRemoteUcastMac(nodeId, mac.getValue(), ipAddress, logicalSwitchName,
-                    phyLocatorAug));
-        }
-        return HwvtepUtils.addRemoteUcastMacs(broker, nodeId, macs);
-    }
-
-    /**
-     * Install macs in external device as remote ucast macs.
-     *
+     * Installs dpn macs in external device.
+     * first it checks if the physical locator towards this dpn tep is present or not
+     * if the physical locator is present go ahead and add the ucast macs
+     * otherwise update the mcast mac entry to include this dpn tep ip
+     * and schedule the job to put ucast macs once the physical locator is programmed in device
      * @param elanName
      *            the elan name
      * @param lstElanInterfaceNames
@@ -179,47 +151,110 @@ public class ElanL2GatewayUtils {
      *            the dpn id
      * @param externalNodeId
      *            the external node id
-     * @return the listenable future
      */
-    public static ListenableFuture<Void> installMacsInExternalDeviceAsRemoteUcastMacs(String elanName,
-            Set<String> lstElanInterfaceNames, BigInteger dpnId, NodeId externalNodeId) {
-        SettableFuture<Void> future = SettableFuture.create();
-        future.set(null);
-        if (lstElanInterfaceNames == null || lstElanInterfaceNames.isEmpty()) {
-            return future;
+    public static void installDpnMacsInL2gwDevice(String elanName,  Set<String> lstElanInterfaceNames,
+                                                  BigInteger dpnId, NodeId externalNodeId) {
+        L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName,
+                externalNodeId.getValue());
+        if (elanL2GwDevice == null) {
+            LOG.debug("L2 gw device not found in elan cache for device name {}", externalNodeId);
+            return;
         }
-
         IpAddress dpnTepIp = getSourceDpnTepIp(dpnId, externalNodeId);
         if (dpnTepIp == null) {
-            return future;
+            LOG.warn("Could not install dpn macs in l2gw device , dpnTepIp not found dpn : {} , nodeid : {}",
+                    dpnId, externalNodeId);
+            return;
         }
 
-        WriteTransaction transaction = broker.newWriteOnlyTransaction();
-        HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepUtils.getPhysicalLocator(broker,
-                LogicalDatastoreType.CONFIGURATION, externalNodeId, dpnTepIp);
-        if (phyLocatorAug == null) {
-            phyLocatorAug = HwvtepSouthboundUtils
-                    .createHwvtepPhysicalLocatorAugmentation(String.valueOf(dpnTepIp.getValue()));
-            HwvtepUtils.putPhysicalLocator(transaction, externalNodeId, phyLocatorAug);
+        String logicalSwitchName = getLogicalSwitchFromElan(elanName);
+        RemoteMcastMacs remoteMcastMac = readRemoteMcastMac(externalNodeId, logicalSwitchName,
+                LogicalDatastoreType.OPERATIONAL);
+        boolean phyLocAlreadyExists = checkIfPhyLocatorAlreadyExistsInRemoteMcastEntry(externalNodeId, remoteMcastMac,
+                dpnTepIp);
+        LOG.debug("phyLocAlreadyExists = {} for locator [{}] in remote mcast entry for elan [{}], nodeId [{}]",
+                phyLocAlreadyExists, String.valueOf(dpnTepIp.getValue()), elanName, externalNodeId.getValue());
+        List<PhysAddress> staticMacs = null;
+        staticMacs = getElanDpnMacsFromInterfaces(lstElanInterfaceNames);
+
+        if (phyLocAlreadyExists) {
+            scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
+            return;
         }
+        ElanL2GatewayMulticastUtils.scheduleMcastMacUpdateJob(elanName, elanL2GwDevice);
+        scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
+    }
 
-        String logicalSwitchName = getLogicalSwitchFromElan(elanName);
+    /**
+     * gets the macs addresses for elan interfaces
+     *
+     * @param lstElanInterfaceNames
+     *            the lst elan interface names
+     * @return the list
+     */
+    private static List<PhysAddress> getElanDpnMacsFromInterfaces(Set<String> lstElanInterfaceNames) {
+        List<PhysAddress> result = new ArrayList<>();
         for (String interfaceName : lstElanInterfaceNames) {
             ElanInterfaceMac elanInterfaceMac = ElanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
             if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
                 for (MacEntry macEntry : elanInterfaceMac.getMacEntry()) {
-                    // TODO: Query ARP cache to get IP address corresponding to
-                    // the MAC
-                    IpAddress ipAddress = null;
-                    RemoteUcastMacs mac = HwvtepSouthboundUtils.createRemoteUcastMac(externalNodeId,
-                            macEntry.getMacAddress().getValue(), ipAddress, logicalSwitchName, phyLocatorAug);
-                    HwvtepUtils.putRemoteUcastMac(transaction, externalNodeId, mac);
+                    result.add(macEntry.getMacAddress());
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Check if phy locator already exists in remote mcast entry.
+     *
+     * @param nodeId
+     *            the node id
+     * @param remoteMcastMac
+     *            the remote mcast mac
+     * @param expectedPhyLocatorIp
+     *            the expected phy locator ip
+     * @return true, if successful
+     */
+    public static boolean checkIfPhyLocatorAlreadyExistsInRemoteMcastEntry(NodeId nodeId,
+            RemoteMcastMacs remoteMcastMac, IpAddress expectedPhyLocatorIp) {
+        if (remoteMcastMac != null) {
+            HwvtepPhysicalLocatorAugmentation expectedPhyLocatorAug = HwvtepSouthboundUtils
+                    .createHwvtepPhysicalLocatorAugmentation(String.valueOf(expectedPhyLocatorIp.getValue()));
+            HwvtepPhysicalLocatorRef expectedPhyLocRef = new HwvtepPhysicalLocatorRef(
+                    HwvtepSouthboundUtils.createPhysicalLocatorInstanceIdentifier(nodeId, expectedPhyLocatorAug));
+            if (remoteMcastMac.getLocatorSet() != null) {
+                for (LocatorSet locatorSet : remoteMcastMac.getLocatorSet()) {
+                    if (locatorSet.getLocatorRef().equals(expectedPhyLocRef)) {
+                        LOG.trace("matched phyLocRef: {}", expectedPhyLocRef);
+                        return true;
+                    }
                 }
             }
         }
-        LOG.debug("Installing macs in external device [{}] for dpn [{}], elan [{}], no of interfaces [{}]",
-                externalNodeId.getValue(), dpnId, elanName, lstElanInterfaceNames.size());
-        return transaction.submit();
+        return false;
+    }
+
+    /**
+     * Gets the remote mcast mac.
+     *
+     * @param nodeId
+     *            the node id
+     * @param logicalSwitchName
+     *            the logical switch name
+     * @param datastoreType
+     *            the datastore type
+     * @return the remote mcast mac
+     */
+    public static RemoteMcastMacs readRemoteMcastMac(NodeId nodeId, String logicalSwitchName,
+                                                     LogicalDatastoreType datastoreType) {
+        InstanceIdentifier<LogicalSwitches> logicalSwitch = HwvtepSouthboundUtils
+                .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName));
+        RemoteMcastMacsKey remoteMcastMacsKey = new RemoteMcastMacsKey(new HwvtepLogicalSwitchRef(logicalSwitch),
+                new MacAddress(ElanConstants.UNKNOWN_DMAC));
+        RemoteMcastMacs remoteMcastMac = HwvtepUtils.getRemoteMcastMac(broker, datastoreType, nodeId,
+                remoteMcastMacsKey);
+        return remoteMcastMac;
     }
 
     /**
@@ -233,7 +268,7 @@ public class ElanL2GatewayUtils {
      */
     public static void removeMacsFromElanExternalDevices(ElanInstance elanInstance, List<PhysAddress> macAddresses) {
         ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices = ElanL2GwCacheUtils
-                .getAllElanL2GatewayDevicesFromCache(elanInstance.getElanInstanceName());
+                .getInvolvedL2GwDevices(elanInstance.getElanInstanceName());
         for (L2GatewayDevice l2GatewayDevice : elanL2GwDevices.values()) {
             removeRemoteUcastMacsFromExternalDevice(l2GatewayDevice.getHwvtepNodeId(),
                     elanInstance.getElanInstanceName(), macAddresses);
@@ -291,228 +326,244 @@ public class ElanL2GatewayUtils {
      * @param elan
      *            the elan
      */
-    public static void installL2gwDeviceLocalMacsInDpn(BigInteger dpnId, NodeId l2gwDeviceNodeId, ElanInstance elan) {
-        String elanName = elan.getElanInstanceName();
-        L2GatewayDevice l2gwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName,
+    public static void installL2gwDeviceMacsInDpn(BigInteger dpnId, NodeId l2gwDeviceNodeId, ElanInstance elan) {
+        L2GatewayDevice l2gwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elan.getElanInstanceName(),
                 l2gwDeviceNodeId.getValue());
         if (l2gwDevice == null) {
             LOG.debug("L2 gw device not found in elan cache for device name {}", l2gwDeviceNodeId.getValue());
             return;
         }
 
+        installDmacFlowsOnDpn(dpnId, l2gwDevice, elan);
+    }
+
+    /**
+     * Install dmac flows on dpn.
+     *
+     * @param dpnId
+     *            the dpn id
+     * @param l2gwDevice
+     *            the l2gw device
+     * @param elan
+     *            the elan
+     */
+    public static void installDmacFlowsOnDpn(BigInteger dpnId, L2GatewayDevice l2gwDevice, ElanInstance elan) {
+        String elanName = elan.getElanInstanceName();
+
         List<LocalUcastMacs> l2gwDeviceLocalMacs = l2gwDevice.getUcastLocalMacs();
         if (l2gwDeviceLocalMacs != null && !l2gwDeviceLocalMacs.isEmpty()) {
             for (LocalUcastMacs localUcastMac : l2gwDeviceLocalMacs) {
-                ElanUtils.installDmacFlowsToExternalRemoteMac(dpnId, l2gwDeviceNodeId.getValue(), elan.getElanTag(),
+                //TODO batch these ops
+                ElanUtils.installDmacFlowsToExternalRemoteMac(dpnId, l2gwDevice.getHwvtepNodeId(), elan.getElanTag(),
                         elan.getVni(), localUcastMac.getMacEntryKey().getValue(), elanName);
             }
+            LOG.debug("Installing L2gw device [{}] local macs [size: {}] in dpn [{}] for elan [{}]",
+                    l2gwDevice.getHwvtepNodeId(), l2gwDeviceLocalMacs.size(), dpnId, elanName);
         }
-        LOG.debug("Installing L2gw device [{}] local macs [size: {}] in dpn [{}] for elan [{}]",
-                l2gwDeviceNodeId.getValue(), l2gwDeviceLocalMacs.size(), dpnId, elanName);
     }
 
-    public static void installL2GwUcastMacInElan(EntityOwnershipService entityOwnershipService,
-            BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, final ElanInstance elan,
-            L2GatewayDevice extL2GwDevice, final String macToBeAdded) {
+    /**
+     * Install elan l2gw devices local macs in dpn.
+     *
+     * @param dpnId
+     *            the dpn id
+     * @param elan
+     *            the elan
+     */
+    public static void installElanL2gwDevicesLocalMacsInDpn(BigInteger dpnId, ElanInstance elan) {
+        ConcurrentMap<String, L2GatewayDevice> elanL2GwDevicesFromCache = ElanL2GwCacheUtils
+                .getInvolvedL2GwDevices(elan.getElanInstanceName());
+        if (elanL2GwDevicesFromCache != null) {
+            for (L2GatewayDevice l2gwDevice : elanL2GwDevicesFromCache.values()) {
+                installDmacFlowsOnDpn(dpnId, l2gwDevice, elan);
+            }
+        } else {
+            LOG.debug("No Elan l2 gateway devices in cache for [{}] ", elan.getElanInstanceName());
+        }
+    }
+
+    public static void installL2GwUcastMacInElan(final ElanInstance elan,
+            final L2GatewayDevice extL2GwDevice, final String macToBeAdded) {
         final String extDeviceNodeId = extL2GwDevice.getHwvtepNodeId();
         final String elanInstanceName = elan.getElanInstanceName();
 
         // Retrieve all participating DPNs in this Elan. Populate this MAC in DMAC table.
         // Looping through all DPNs in order to add/remove mac flows in their DMAC table
-        List<DpnInterfaces> elanDpns = ElanUtils.getInvolvedDpnsInElan(elanInstanceName);
-        for (DpnInterfaces elanDpn : elanDpns) {
-            final BigInteger dpnId = elanDpn.getDpId();
-            final String nodeId = getNodeIdFromDpnId(dpnId);
-
-            ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
-                    entityOwnershipService, MDSALUtil.NODE_PREFIX, nodeId);
-            Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
-                @Override
-                public void onSuccess(Boolean isOwner) {
-                    if (isOwner) {
-                        LOG.info("Installing DMAC flows in {} connected to cluster node owner", dpnId.toString());
-
-                        DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
-                        dataStoreCoordinator.enqueueJob(nodeId, new Callable<List<ListenableFuture<Void>>>() {
-                            @Override
-                            public List<ListenableFuture<Void>> call() throws Exception {
-                                return ElanUtils.installDmacFlowsToExternalRemoteMac(dpnId, extDeviceNodeId,
-                                        elan.getElanTag(), elan.getVni(), macToBeAdded, elanInstanceName);
+        final List<DpnInterfaces> elanDpns = ElanUtils.getInvolvedDpnsInElan(elanInstanceName);
+        if (elanDpns != null && elanDpns.size() > 0) {
+            String jobKey = elan.getElanInstanceName() + ":" + macToBeAdded;
+            ElanClusterUtils.runOnlyInLeaderNode(jobKey,
+                    "install l2gw mcas in dmac table",
+                    new Callable<List<ListenableFuture<Void>>>() {
+                        @Override
+                        public List<ListenableFuture<Void>> call() throws Exception {
+                            List<ListenableFuture<Void>> fts = Lists.newArrayList();
+                            for (DpnInterfaces elanDpn : elanDpns) {
+                                //TODO batch the below call
+                                fts.addAll(ElanUtils.installDmacFlowsToExternalRemoteMac(elanDpn.getDpId(),
+                                        extDeviceNodeId, elan.getElanTag(), elan.getVni(), macToBeAdded,
+                                        elanInstanceName));
                             }
-                        }, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
-                    } else {
-                        LOG.info("Install DMAC flows is not executed on the cluster node as this is not owner " +
-                                    "for the DPN {}", dpnId.toString());
-                    }
-                }
-
-                @Override
-                public void onFailure(Throwable error) {
-                    LOG.error("Failed to install DMAC flows", error);
-                }
-            });
+                            return fts;
+                        }
+                    });
         }
-
         final IpAddress extL2GwDeviceTepIp = extL2GwDevice.getTunnelIp();
         final List<PhysAddress> macList = new ArrayList<PhysAddress>();
         macList.add(new PhysAddress(macToBeAdded));
 
-        ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices =
-                ElanL2GwCacheUtils.getAllElanL2GatewayDevicesFromCache(elanInstanceName);
-        for (L2GatewayDevice otherDevice : elanL2GwDevices.values()) {
-            if (!otherDevice.getHwvtepNodeId().equals(extDeviceNodeId) && !areMLAGDevices(extL2GwDevice, otherDevice)) {
-                final String hwvtepId = otherDevice.getHwvtepNodeId();
-                InstanceIdentifier<Node> iid = HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(hwvtepId));
-                ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
-                        entityOwnershipService, HwvtepSouthboundConstants.HWVTEP_ENTITY_TYPE,
-                        bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid));
-                Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
+        String jobKey = "hwvtep:"+elan.getElanInstanceName() + ":" + macToBeAdded;
+        ElanClusterUtils.runOnlyInLeaderNode(jobKey,
+                "install remote ucast macs in l2gw device",
+                new Callable<List<ListenableFuture<Void>>>() {
                     @Override
-                    public void onSuccess(Boolean isOwner) {
-                        if (isOwner) {
-                            LOG.info("Adding DMAC entry in {} connected to cluster node owner", hwvtepId);
+                    public List<ListenableFuture<Void>> call() throws Exception {
+                        ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices =
+                                ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanInstanceName);
+
+                        List<ListenableFuture<Void>>  fts = Lists.newArrayList();
+                        for (L2GatewayDevice otherDevice : elanL2GwDevices.values()) {
+                            if (!otherDevice.getHwvtepNodeId().equals(extDeviceNodeId)
+                                    && !areMLAGDevices(extL2GwDevice, otherDevice)) {
+                                final String hwvtepId = otherDevice.getHwvtepNodeId();
+                                InstanceIdentifier<Node> iid = HwvtepSouthboundUtils.createInstanceIdentifier(
+                                        new NodeId(hwvtepId));
+                                final String logicalSwitchName = elanInstanceName;
+
+                                ListenableFuture<Void> ft = HwvtepUtils.installUcastMacs(
+                                        broker, hwvtepId, macList, logicalSwitchName, extL2GwDeviceTepIp);
+                                //TODO batch the above call
+                                Futures.addCallback(ft, new FutureCallback<Void>() {
+                                    @Override
+                                    public void onSuccess(Void noarg) {
+                                        LOG.trace("Successful in initiating ucast_remote_macs addition" +
+                                                "related to {} in {}", logicalSwitchName, hwvtepId);
+                                    }
 
-                            DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
-                            dataStoreCoordinator.enqueueJob(hwvtepId, new Callable<List<ListenableFuture<Void>>>() {
-                                @Override
-                                public List<ListenableFuture<Void>> call() throws Exception {
-                                    final String logicalSwitchName = getLogicalSwitchFromElan(elanInstanceName);
-                                    ListenableFuture<Void> installFuture = installMacsInExternalDeviceAsRemoteUcastMacs(
-                                            hwvtepId, macList, logicalSwitchName, extL2GwDeviceTepIp);
-
-                                    Futures.addCallback(installFuture, new FutureCallback<Void>() {
-                                        @Override
-                                        public void onSuccess(Void noarg) {
-                                            if (LOG.isTraceEnabled()) {
-                                                LOG.trace("Successful in initiating ucast_remote_macs addition" +
-                                                        "related to {} in {}", logicalSwitchName, hwvtepId);
-                                            }
-                                        }
-
-                                        @Override
-                                        public void onFailure(Throwable error) {
-                                            LOG.error(String.format("Failed adding ucast_remote_macs related to " +
-                                                    "%s in %s", logicalSwitchName, hwvtepId), error);
-                                        }
-                                    });
-
-                                    return Lists.newArrayList(installFuture);
-                                }
-                            }, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
-                        } else {
-                            LOG.info("DMAC entry addition is not executed on the cluster node as this is not owner for " +
-                                    "the Hwvtep {}", hwvtepId);
+                                    @Override
+                                    public void onFailure(Throwable error) {
+                                        LOG.error(String.format("Failed adding ucast_remote_macs related to " +
+                                                "%s in %s", logicalSwitchName, hwvtepId), error);
+                                    };
+                                });
+                                fts.add(ft);
+                            }
                         }
-                    }
+                        return fts;
+                    }});
+    }
 
-                    @Override
-                    public void onFailure(Throwable error) {
-                        LOG.error("Failed to install DMAC entry", error);
-                    }
-                });
+    /**
+     * Un install l2 gw ucast mac from elan.
+     *
+     * @param elan
+     *            the elan
+     * @param l2GwDevice
+     *            the l2 gw device
+     * @param macAddresses
+     *            the mac addresses
+     */
+    public static void unInstallL2GwUcastMacFromElan(final ElanInstance elan, final L2GatewayDevice l2GwDevice,
+            final List<MacAddress> macAddresses) {
+        if (macAddresses == null || macAddresses.isEmpty()) {
+            return;
+        }
+        final String elanName = elan.getElanInstanceName();
+
+        // Retrieve all participating DPNs in this Elan. Populate this MAC in
+        // DMAC table. Looping through all DPNs in order to add/remove mac flows
+        // in their DMAC table
+        for (final MacAddress mac : macAddresses) {
+            final List<DpnInterfaces> elanDpns = ElanUtils.getInvolvedDpnsInElan(elanName);
+            if (elanDpns != null && !elanDpns.isEmpty()) {
+                String jobKey = elanName + ":" + mac.getValue();
+                ElanClusterUtils.runOnlyInLeaderNode(jobKey, "delete l2gw macs from dmac table",
+                        new Callable<List<ListenableFuture<Void>>>() {
+                            @Override
+                            public List<ListenableFuture<Void>> call() {
+                                List<ListenableFuture<Void>> fts = Lists.newArrayList();
+                                for (DpnInterfaces elanDpn : elanDpns) {
+                                    BigInteger dpnId = elanDpn.getDpId();
+                                    // never batch deletes
+                                    fts.addAll(ElanUtils.deleteDmacFlowsToExternalMac(elan.getElanTag(), dpnId,
+                                            l2GwDevice.getHwvtepNodeId(), mac.getValue()));
+                                }
+                                return fts;
+                            }
+                        });
             }
         }
-    }
 
-    public static void unInstallL2GwUcastMacFromElan(EntityOwnershipService entityOwnershipService,
-            BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, final ElanInstance elan,
-            L2GatewayDevice extL2GwDevice, final LocalUcastMacs macToBeRemoved) {
-        final String extDeviceNodeId = extL2GwDevice.getHwvtepNodeId();
-        final String elanInstanceName = elan.getElanInstanceName();
+        DeleteL2GwDeviceMacsFromElanJob job = new DeleteL2GwDeviceMacsFromElanJob(broker, elanName, l2GwDevice,
+                macAddresses);
+        ElanClusterUtils.runOnlyInLeaderNode(job.getJobKey(), "delete remote ucast macs in l2gw devices", job);
+    }
 
-        // Retrieve all participating DPNs in this Elan. Populate this MAC in DMAC table.
-        // Looping through all DPNs in order to add/remove mac flows in their DMAC table
-        List<DpnInterfaces> elanDpns = ElanUtils.getInvolvedDpnsInElan(elanInstanceName);
-        for (DpnInterfaces elanDpn : elanDpns) {
-            final BigInteger dpnId = elanDpn.getDpId();
-            final String nodeId = getNodeIdFromDpnId(dpnId);
-
-            ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
-                    entityOwnershipService, MDSALUtil.NODE_PREFIX, nodeId);
-            Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
-                @Override
-                public void onSuccess(Boolean isOwner) {
-                    if (isOwner) {
-                        LOG.info("Uninstalling DMAC flows from {} connected to cluster node owner",
-                                dpnId.toString());
+    /**
+     * Delete elan l2 gateway devices ucast local macs from dpn.
+     *
+     * @param elanName
+     *            the elan name
+     * @param dpnId
+     *            the dpn id
+     */
+    public static void deleteElanL2GwDevicesUcastLocalMacsFromDpn(final String elanName, final BigInteger dpnId) {
+        ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices = ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName);
+        if (elanL2GwDevices == null || elanL2GwDevices.isEmpty()) {
+            LOG.trace("No L2 gateway devices in Elan [{}] cache.", elanName);
+            return;
+        }
+        final ElanInstance elan = ElanUtils.getElanInstanceByName(elanName);
+        if (elan == null) {
+            LOG.error("Could not find Elan by name: {}", elanName);
+            return;
+        }
+        LOG.info("Deleting Elan [{}] L2GatewayDevices UcastLocalMacs from Dpn [{}]", elanName, dpnId);
+
+        final Long elanTag = elan.getElanTag();
+        for (final L2GatewayDevice l2GwDevice : elanL2GwDevices.values()) {
+            List<MacAddress> localMacs = getL2GwDeviceLocalMacs(l2GwDevice);
+            if (localMacs != null && !localMacs.isEmpty()) {
+                for (final MacAddress mac : localMacs) {
+                    String jobKey = elanName + ":" + mac.getValue();
+                    ElanClusterUtils.runOnlyInLeaderNode(jobKey, "delete l2gw macs from dmac table",
+                            new Callable<List<ListenableFuture<Void>>>() {
+                                @Override
+                                public List<ListenableFuture<Void>> call() {
+                                    List<ListenableFuture<Void>> futures = Lists.newArrayList();
 
-                        DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
-                        dataStoreCoordinator.enqueueJob(nodeId, new Callable<List<ListenableFuture<Void>>>() {
-                            @Override
-                            public List<ListenableFuture<Void>> call() throws Exception {
-                                return ElanUtils.deleteDmacFlowsToExternalMac(elan.getElanTag(), dpnId,
-                                        extDeviceNodeId, macToBeRemoved.getMacEntryKey().getValue());
-                            }
-                        }, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
-                    } else {
-                        LOG.info("Uninstall DMAC flows is not executed on the cluster node as this is not owner " +
-                                    "for the DPN {}", dpnId.toString());
-                    }
+                                    futures.addAll(ElanUtils.deleteDmacFlowsToExternalMac(elanTag, dpnId,
+                                            l2GwDevice.getHwvtepNodeId(), mac.getValue()));
+                                    return futures;
+                                }
+                            });
                 }
+            }
+        }
+    }
 
+    /**
+     * Gets the l2 gw device local macs.
+     *
+     * @param l2gwDevice
+     *            the l2gw device
+     * @return the l2 gw device local macs
+     */
+    public static List<MacAddress> getL2GwDeviceLocalMacs(L2GatewayDevice l2gwDevice) {
+        List<MacAddress> macs = new ArrayList<>();
+        if (l2gwDevice == null) {
+            return macs;
+        }
+        List<LocalUcastMacs> lstUcastLocalMacs = l2gwDevice.getUcastLocalMacs();
+        if (lstUcastLocalMacs != null && !lstUcastLocalMacs.isEmpty()) {
+            macs = Lists.transform(lstUcastLocalMacs, new Function<LocalUcastMacs, MacAddress>() {
                 @Override
-                public void onFailure(Throwable error) {
-                    LOG.error("Failed to uninstall DMAC flows", error);
+                public MacAddress apply(LocalUcastMacs localUcastMac) {
+                    return (localUcastMac != null) ? localUcastMac.getMacEntryKey() : null;
                 }
             });
         }
-
-        ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices =
-                ElanL2GwCacheUtils.getAllElanL2GatewayDevicesFromCache(elanInstanceName);
-        for (L2GatewayDevice otherDevice : elanL2GwDevices.values()) {
-            if (!otherDevice.getHwvtepNodeId().equals(extDeviceNodeId) && !areMLAGDevices(extL2GwDevice, otherDevice)) {
-                final String hwvtepId = otherDevice.getHwvtepNodeId();
-                final NodeId hwvtepNodeId = new NodeId(hwvtepId);
-                InstanceIdentifier<Node> iid = HwvtepSouthboundUtils.createInstanceIdentifier(hwvtepNodeId);
-                ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
-                        entityOwnershipService, HwvtepSouthboundConstants.HWVTEP_ENTITY_TYPE,
-                        bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid));
-                Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
-                    @Override
-                    public void onSuccess(Boolean isOwner) {
-                        if (isOwner) {
-                            LOG.info("Removing DMAC entry from {} connected to cluster node owner", hwvtepId);
-
-                            DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
-                            dataStoreCoordinator.enqueueJob(hwvtepId, new Callable<List<ListenableFuture<Void>>>() {
-                                @Override
-                                public List<ListenableFuture<Void>> call() throws Exception {
-                                    final String logicalSwitchName = getLogicalSwitchFromElan(elanInstanceName);
-                                    ListenableFuture<Void> uninstallFuture = HwvtepUtils.deleteRemoteUcastMac(broker,
-                                            hwvtepNodeId, logicalSwitchName, macToBeRemoved.getMacEntryKey());
-
-                                    Futures.addCallback(uninstallFuture, new FutureCallback<Void>() {
-                                        @Override
-                                        public void onSuccess(Void noarg) {
-                                            if (LOG.isTraceEnabled()) {
-                                                LOG.trace("Successful in initiating ucast_remote_macs deletion " +
-                                                        "related to {} in {}", logicalSwitchName, hwvtepId);
-                                            }
-                                        }
-
-                                        @Override
-                                        public void onFailure(Throwable error) {
-                                            LOG.error(String.format("Failed removing ucast_remote_macs related " +
-                                                    "to %s in %s", logicalSwitchName, hwvtepId), error);
-                                        }
-                                    });
-
-                                    return Lists.newArrayList(uninstallFuture);
-                                }
-                            }, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
-                        } else {
-                            LOG.info("DMAC entry removal is not executed on the cluster node as this is not owner for " +
-                                    "the Hwvtep {}", hwvtepId);
-                        }
-                    }
-
-                    @Override
-                    public void onFailure(Throwable error) {
-                        LOG.error("Failed to uninstall DMAC entry", error);
-                    }
-                });
-            }
-        }
+        return macs;
     }
 
     /**
@@ -574,7 +625,7 @@ public class ElanL2GatewayUtils {
         List<MacAddress> lstL2GatewayDeviceMacs = new ArrayList<>();
 
         ConcurrentMap<String, L2GatewayDevice> elanL2GwDevicesFromCache = ElanL2GwCacheUtils
-                .getAllElanL2GatewayDevicesFromCache(elanName);
+                .getInvolvedL2GwDevices(elanName);
         if (elanL2GwDevicesFromCache != null) {
             for (L2GatewayDevice otherDevice : elanL2GwDevicesFromCache.values()) {
                 if (!otherDevice.getHwvtepNodeId().equals(l2GwDeviceToBeExcluded.getHwvtepNodeId())) {
@@ -611,9 +662,9 @@ public class ElanL2GatewayUtils {
         String logicalSwitchName = getLogicalSwitchFromElan(elanName);
         NodeId hwVtepNodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
 
-        List<RemoteUcastMacs> lstL2GatewayDevicesMacs = getL2GatewayDevicesUcastLocalMacsAsRemoteUcastMacs(elanName,
+        List<RemoteUcastMacs> lstL2GatewayDevicesMacs = getOtherDevicesMacs(elanName,
                 l2GatewayDevice, hwVtepNodeId, logicalSwitchName);
-        List<RemoteUcastMacs> lstElanMacTableEntries = getElanMacTableEntriesAsRemoteUcastMacs(elanName,
+        List<RemoteUcastMacs> lstElanMacTableEntries = getElanMacTableEntriesMacs(elanName,
                 l2GatewayDevice, hwVtepNodeId, logicalSwitchName);
 
         List<RemoteUcastMacs> lstRemoteUcastMacs = new ArrayList<>(lstL2GatewayDevicesMacs);
@@ -639,11 +690,12 @@ public class ElanL2GatewayUtils {
      *            the logical switch name
      * @return the l2 gateway devices macs as remote ucast macs
      */
-    public static List<RemoteUcastMacs> getL2GatewayDevicesUcastLocalMacsAsRemoteUcastMacs(String elanName,
-            L2GatewayDevice l2GatewayDeviceToBeConfigured, NodeId hwVtepNodeId, String logicalSwitchName) {
+    public static List<RemoteUcastMacs> getOtherDevicesMacs(String elanName,
+                                                            L2GatewayDevice l2GatewayDeviceToBeConfigured,
+                                                            NodeId hwVtepNodeId, String logicalSwitchName) {
         List<RemoteUcastMacs> lstRemoteUcastMacs = new ArrayList<RemoteUcastMacs>();
         ConcurrentMap<String, L2GatewayDevice> elanL2GwDevicesFromCache = ElanL2GwCacheUtils
-                .getAllElanL2GatewayDevicesFromCache(elanName);
+                .getInvolvedL2GwDevices(elanName);
 
         if (elanL2GwDevicesFromCache != null) {
             for (L2GatewayDevice otherDevice : elanL2GwDevicesFromCache.values()) {
@@ -699,8 +751,9 @@ public class ElanL2GatewayUtils {
      *            the logical switch name
      * @return the elan mac table entries as remote ucast macs
      */
-    public static List<RemoteUcastMacs> getElanMacTableEntriesAsRemoteUcastMacs(String elanName,
-            L2GatewayDevice l2GatewayDeviceToBeConfigured, NodeId hwVtepNodeId, String logicalSwitchName) {
+    public static List<RemoteUcastMacs> getElanMacTableEntriesMacs(String elanName,
+                                                                   L2GatewayDevice l2GatewayDeviceToBeConfigured,
+                                                                   NodeId hwVtepNodeId, String logicalSwitchName) {
         List<RemoteUcastMacs> lstRemoteUcastMacs = new ArrayList<RemoteUcastMacs>();
 
         MacTable macTable = ElanUtils.getElanMacTable(elanName);
@@ -744,11 +797,12 @@ public class ElanL2GatewayUtils {
      * @return the external tunnel interface name
      */
     public static String getExternalTunnelInterfaceName(String sourceNode, String dstNode) {
+        Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
         String tunnelInterfaceName = null;
         try {
             Future<RpcResult<GetExternalTunnelInterfaceNameOutput>> output = itmRpcService
                     .getExternalTunnelInterfaceName(new GetExternalTunnelInterfaceNameInputBuilder()
-                            .setSourceNode(sourceNode).setDestinationNode(dstNode).build());
+                            .setSourceNode(sourceNode).setDestinationNode(dstNode).setTunnelType(tunType).build());
 
             RpcResult<GetExternalTunnelInterfaceNameOutput> rpcResult = output.get();
             if (rpcResult.isSuccessful()) {
@@ -913,7 +967,7 @@ public class ElanL2GatewayUtils {
      * @return the l2 gateway connection job key
      */
     public static String getL2GatewayConnectionJobKey(String nodeId, String logicalSwitchName) {
-        return new StringBuilder(nodeId).append(logicalSwitchName).toString();
+        return logicalSwitchName;
     }
 
     public static InstanceIdentifier<Interface> getInterfaceIdentifier(InterfaceKey interfaceKey) {
@@ -944,45 +998,19 @@ public class ElanL2GatewayUtils {
      *            the elan name
      * @return the listenable future
      */
-    public static List<ListenableFuture<Void>> deleteL2GatewayDeviceUcastLocalMacsFromElan(
-            L2GatewayDevice l2GatewayDevice, String elanName) {
-        List<ListenableFuture<Void>> futures = new ArrayList<>();
+    public static List<ListenableFuture<Void>> deleteL2GwDeviceUcastLocalMacsFromElan(L2GatewayDevice l2GatewayDevice,
+            String elanName) {
+        LOG.info("Deleting L2GatewayDevice [{}] UcastLocalMacs from elan [{}]", l2GatewayDevice.getHwvtepNodeId(), elanName);
 
+        List<ListenableFuture<Void>> futures = new ArrayList<>();
         ElanInstance elan = ElanUtils.getElanInstanceByName(elanName);
         if (elan == null) {
             LOG.error("Could not find Elan by name: {}", elanName);
             return futures;
         }
 
-        List<LocalUcastMacs> lstLocalUcastMacs = l2GatewayDevice.getUcastLocalMacs();
-        if (lstLocalUcastMacs != null) {
-            for (LocalUcastMacs localUcastMac : lstLocalUcastMacs) {
-                List<DpnInterfaces> dpnInterfaces = ElanUtils.getInvolvedDpnsInElan(elanName);
-                if (dpnInterfaces != null) {
-                    // TODO: Need to check if it can be optimized
-                    for (DpnInterfaces elanDpn : dpnInterfaces) {
-                        ElanUtils.deleteDmacFlowsToExternalMac(elan.getElanTag(), elanDpn.getDpId(),
-                                l2GatewayDevice.getHwvtepNodeId(), localUcastMac.getMacEntryKey().getValue());
-                    }
-                }
-            }
-
-            List<MacAddress> lstMac = Lists.transform(lstLocalUcastMacs, new Function<LocalUcastMacs, MacAddress>() {
-                @Override
-                public MacAddress apply(LocalUcastMacs mac) {
-                    return (mac != null) ? mac.getMacEntryKey() : null;
-                }
-            });
-
-            ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices = ElanL2GwCacheUtils
-                    .getAllElanL2GatewayDevicesFromCache(elanName);
-            for (L2GatewayDevice otherDevice : elanL2GwDevices.values()) {
-                if (!otherDevice.getHwvtepNodeId().equals(l2GatewayDevice.getHwvtepNodeId())) {
-                    futures.add(HwvtepUtils.deleteRemoteUcastMacs(broker, new NodeId(otherDevice.getHwvtepNodeId()),
-                            elanName, lstMac));
-                }
-            }
-        }
+        List<MacAddress> localMacs = getL2GwDeviceLocalMacs(l2GatewayDevice);
+        unInstallL2GwUcastMacFromElan(elan, l2GatewayDevice, localMacs);
         return futures;
     }
 
@@ -1009,4 +1037,62 @@ public class ElanL2GatewayUtils {
         return MDSALUtil.NODE_PREFIX + MDSALUtil.SEPARATOR + dpnId.toString();
     }
 
+    public static void scheduleAddDpnMacInExtDevices(String elanName, BigInteger dpId,
+                                                     List<PhysAddress> staticMacAddresses) {
+        ConcurrentMap<String, L2GatewayDevice> elanDevices = ElanL2GwCacheUtils
+                .getInvolvedL2GwDevices(elanName);
+        for (final L2GatewayDevice externalDevice : elanDevices.values()) {
+            scheduleAddDpnMacsInExtDevice(elanName, dpId, staticMacAddresses, externalDevice);
+        }
+    }
+
+    public static void scheduleAddDpnMacsInExtDevice(final String elanName, BigInteger dpId,
+                                                     final List<PhysAddress> staticMacAddresses,
+                                                     final L2GatewayDevice externalDevice) {
+        NodeId nodeId = new NodeId(externalDevice.getHwvtepNodeId());
+        final IpAddress dpnTepIp = ElanL2GatewayUtils.getSourceDpnTepIp(dpId, nodeId);
+        LOG.trace("Dpn Tep IP: {} for dpnId: {} and nodeId: {}", dpnTepIp, dpId, nodeId);
+        if (dpnTepIp == null) {
+            LOG.error("could not install dpn mac in l2gw TEP IP not found for dpnId {} and nodeId {}", dpId, nodeId);
+            return;
+        }
+        TerminationPointKey tpKey = HwvtepSouthboundUtils.getTerminationPointKey(
+                dpnTepIp.getIpv4Address().getValue());
+        InstanceIdentifier<TerminationPoint> tpPath = HwvtepSouthboundUtils.createTerminationPointId
+                (nodeId, tpKey);
+
+        HwvtepPhysicalLocatorListener.runJobAfterPhysicalLocatorIsAvialable(tpPath, new Runnable() {
+            @Override
+            public void run() {
+                HwvtepUtils.installUcastMacs(broker,
+                        externalDevice.getHwvtepNodeId(), staticMacAddresses,
+                        elanName, dpnTepIp);
+            }
+        });
+    }
+
+    public static void scheduleDeleteLogicalSwitch(final NodeId hwvtepNodeId, final String lsName) {
+        TimerTask logicalSwitchDeleteTask = new TimerTask() {
+            @Override
+            public void run() {
+                LogicalSwitchDeletedJob logicalSwitchDeletedJob = new LogicalSwitchDeletedJob(broker, hwvtepNodeId,
+                        lsName);
+                ElanL2GatewayUtils.dataStoreJobCoordinator.enqueueJob(logicalSwitchDeletedJob.getJobKey(),
+                        logicalSwitchDeletedJob, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
+            }
+        };
+        Pair<NodeId, String> nodeIdLogicalSwitchNamePair = new ImmutablePair<NodeId, String>(hwvtepNodeId, lsName);
+        LogicalSwitchDeletedTasks.putIfAbsent(nodeIdLogicalSwitchNamePair, logicalSwitchDeleteTask);
+        LogicalSwitchDeleteJobTimer.schedule(logicalSwitchDeleteTask, LOGICAL_SWITCH_DELETE_DELAY);
+    }
+
+    public static void cancelDeleteLogicalSwitch(final NodeId hwvtepNodeId, final String lsName) {
+        Pair<NodeId, String> nodeIdLogicalSwitchNamePair = new ImmutablePair<NodeId, String>(hwvtepNodeId, lsName);
+        TimerTask logicalSwitchDeleteTask = LogicalSwitchDeletedTasks.get(nodeIdLogicalSwitchNamePair);
+        if (logicalSwitchDeleteTask != null) {
+            LOG.debug("Delete logical switch {} action on node {} cancelled", lsName, hwvtepNodeId);
+            logicalSwitchDeleteTask.cancel();
+            LogicalSwitchDeletedTasks.remove(nodeIdLogicalSwitchNamePair);
+        }
+    }
 }
index be0012f47b899f0f27d86dbae8550271d48095ad..688fd151d8ac5f5f0ff9930b457ad908269b57f1 100644 (file)
@@ -8,26 +8,20 @@
 
 package org.opendaylight.vpnservice.elan.l2gw.utils;
 
-import java.util.ArrayList;
 import java.util.List;
-import java.util.concurrent.Callable;
 
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
 import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
 import org.opendaylight.vpnservice.elan.internal.ElanInstanceManager;
+import org.opendaylight.vpnservice.elan.l2gw.jobs.AssociateHwvtepToElanJob;
+import org.opendaylight.vpnservice.elan.l2gw.jobs.DisAssociateHwvtepFromElanJob;
 import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepLogicalSwitchListener;
-import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepRemoteMcastMacListener;
-import org.opendaylight.vpnservice.elan.utils.ElanUtils;
+import org.opendaylight.vpnservice.elan.utils.ElanClusterUtils;
 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
 import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
 import org.opendaylight.vpnservice.neutronvpn.api.l2gw.utils.L2GatewayCacheUtils;
-import org.opendaylight.vpnservice.utils.SystemPropertyReader;
-import org.opendaylight.vpnservice.utils.clustering.ClusteringUtils;
-import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundConstants;
-import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundUtils;
 import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.attributes.Devices;
@@ -37,24 +31,35 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev15071
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateways.attributes.l2gateways.L2gateway;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateways.attributes.l2gateways.L2gatewayKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
-import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Optional;
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
 
 public class L2GatewayConnectionUtils {
     private static final Logger LOG = LoggerFactory.getLogger(L2GatewayConnectionUtils.class);
 
+    private static DataBroker broker;
+    private static ElanInstanceManager elanInstanceManager;
+
+    static DataStoreJobCoordinator dataStoreJobCoordinator;
+
+    public static void setDataStoreJobCoordinator(DataStoreJobCoordinator ds) {
+        dataStoreJobCoordinator = ds;
+    }
+
+    public static void setBroker(DataBroker broker) {
+        L2GatewayConnectionUtils.broker = broker;
+    }
+
+    public static void setElanInstanceManager(ElanInstanceManager elanInstanceManager) {
+        L2GatewayConnectionUtils.elanInstanceManager = elanInstanceManager;
+    }
+
     public static boolean isGatewayAssociatedToL2Device(L2GatewayDevice l2GwDevice) {
         return (l2GwDevice.getL2GatewayIds().size() > 0);
     }
@@ -90,16 +95,13 @@ public class L2GatewayConnectionUtils {
         return null;
     }
 
-    public static void addL2GatewayConnection(DataBroker broker, EntityOwnershipService entityOwnershipService,
-            BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, ElanInstanceManager elanInstanceManager,
-            L2gatewayConnection input) {
-        addL2GatewayConnection(broker, entityOwnershipService, bindingNormalizedNodeSerializer, elanInstanceManager,
-                input, null);
+    public static void addL2GatewayConnection(L2gatewayConnection input) {
+        addL2GatewayConnection(input, null/*deviceName*/);
     }
 
-    public static void addL2GatewayConnection(DataBroker broker, EntityOwnershipService entityOwnershipService,
-            BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, ElanInstanceManager elanInstanceManager,
-            L2gatewayConnection input, String l2GwDeviceName) {
+    public static void addL2GatewayConnection(L2gatewayConnection input, String l2GwDeviceName) {
+        LOG.info("Adding L2gateway Connection with ID: {}", input.getKey().getUuid());
+
         Uuid networkUuid = input.getNetworkId();
         ElanInstance elanInstance = elanInstanceManager.getElanInstanceByName(networkUuid.getValue());
         if (elanInstance == null || elanInstance.getVni() == null) {
@@ -110,15 +112,14 @@ public class L2GatewayConnectionUtils {
             if (l2Gateway == null) {
                 LOG.error("L2Gateway with id {} is not present", l2GatewayId.getValue());
             } else {
-                associateHwvtepsToElan(broker, entityOwnershipService, bindingNormalizedNodeSerializer, elanInstance,
-                        l2Gateway, input.getSegmentId(), l2GwDeviceName);
+                associateHwvtepsToElan(elanInstance, l2Gateway, input, l2GwDeviceName);
             }
         }
     }
 
-    public static void deleteL2GatewayConnection(DataBroker broker, EntityOwnershipService entityOwnershipService,
-            BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, ElanInstanceManager elanInstanceManager,
-            L2gatewayConnection input) {
+    public static void deleteL2GatewayConnection(L2gatewayConnection input) {
+        LOG.info("Deleting L2gateway Connection with ID: {}", input.getKey().getUuid());
+
         Uuid networkUuid = input.getNetworkId();
         ElanInstance elanInstance = elanInstanceManager.getElanInstanceByName(networkUuid.getValue());
         if (elanInstance == null) {
@@ -129,269 +130,130 @@ public class L2GatewayConnectionUtils {
             if (l2Gateway == null) {
                 LOG.error("L2Gateway with id {} is not present", l2GatewayId.getValue());
             } else {
-                disAssociateHwvtepsToElan(broker, entityOwnershipService, bindingNormalizedNodeSerializer, elanInstance,
-                        l2Gateway, input.getSegmentId());
+                disAssociateHwvtepsFromElan(elanInstance, l2Gateway, input);
             }
         }
     }
 
-    private static void disAssociateHwvtepsToElan(final DataBroker broker, EntityOwnershipService entityOwnershipService,
-            BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, final ElanInstance elanInstance,
-            L2gateway l2Gateway, final Integer defaultVlan) {
-        final String elanName = elanInstance.getElanInstanceName();
+    private static void disAssociateHwvtepsFromElan(ElanInstance elanInstance, L2gateway l2Gateway,
+            L2gatewayConnection input) {
+        String elanName = elanInstance.getElanInstanceName();
+        Integer defaultVlan = input.getSegmentId();
         List<Devices> l2Devices = l2Gateway.getDevices();
-        for (final Devices l2Device : l2Devices) {
-            final String l2DeviceName = l2Device.getDeviceName();
-            final L2GatewayDevice l2GatewayDevice = L2GatewayCacheUtils.getL2DeviceFromCache(l2DeviceName);
+        for (Devices l2Device : l2Devices) {
+            String l2DeviceName = l2Device.getDeviceName();
+            L2GatewayDevice l2GatewayDevice = L2GatewayCacheUtils.getL2DeviceFromCache(l2DeviceName);
             if (isL2GwDeviceConnected(l2GatewayDevice)) {//TODO handle delete while device is offline
                 // Delete L2 Gateway device from 'ElanL2GwDevice' cache
-                ElanL2GwCacheUtils.removeL2GatewayDeviceFromCache(elanName, l2GatewayDevice.getHwvtepNodeId());
-
-                final String hwvtepId = l2GatewayDevice.getHwvtepNodeId();
-                InstanceIdentifier<Node> iid = HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(hwvtepId));
-                ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
-                        entityOwnershipService, HwvtepSouthboundConstants.HWVTEP_ENTITY_TYPE,
-                        bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid));
-                Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
-                    @Override
-                    public void onSuccess(Boolean isOwner) {
-                        if (isOwner) {
-                            LOG.info("L2 Gateway device delete is triggered for {} connected to cluster owner node",
-                                    l2DeviceName);
-
-                            // Create DataStoreJobCoordinator jobs to create Logical
-                            // switches on all physical switches
-                            // which are part of L2 Gateway
-                            DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
-                            DisAssociateHwvtepFromElan disAssociateHwvtepToElan = new DisAssociateHwvtepFromElan(broker,
-                                    l2GatewayDevice, elanInstance, l2Device, defaultVlan);
-                            String jobKey = ElanL2GatewayUtils.getL2GatewayConnectionJobKey(hwvtepId, elanName);
-                            dataStoreCoordinator.enqueueJob(jobKey, disAssociateHwvtepToElan,
-                                    SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
-                        } else {
-                            LOG.info("L2 Gateway device delete is not triggered on the cluster node as this is not " +
-                                    "owner for {}", l2DeviceName);
-                        }
-                    }
-
-                    @Override
-                    public void onFailure(Throwable error) {
-                        LOG.error("Failed to trigger L2 Gateway device delete action", error);
-                    }
-                });
+                String hwvtepNodeId = l2GatewayDevice.getHwvtepNodeId();
+                boolean isLastL2GwConnDeleted = false;
+                L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName, hwvtepNodeId);
+                if (isLastL2GwConnBeingDeleted(elanL2GwDevice)) {
+                    LOG.debug("Elan L2Gw Conn cache removed for id {}", hwvtepNodeId);
+                    ElanL2GwCacheUtils.removeL2GatewayDeviceFromCache(elanName, hwvtepNodeId);
+                    isLastL2GwConnDeleted = true;
+                } else {
+                    Uuid l2GwConnId = input.getKey().getUuid();
+                    LOG.debug("Elan L2Gw Conn cache with id {} is being referred by other L2Gw Conns; so only " +
+                            "L2 Gw Conn {} reference is removed", hwvtepNodeId, l2GwConnId);
+                    elanL2GwDevice.removeL2GatewayId(l2GwConnId);
+                }
+
+                DisAssociateHwvtepFromElanJob disAssociateHwvtepToElanJob = new DisAssociateHwvtepFromElanJob(broker,
+                        elanL2GwDevice, elanInstance, l2Device, defaultVlan, isLastL2GwConnDeleted);
+                ElanClusterUtils.runOnlyInLeaderNode(disAssociateHwvtepToElanJob.getJobKey(),
+                        "remove l2gw connection job ",
+                        disAssociateHwvtepToElanJob);
             } else {
-                LOG.error("could not handle connection delete L2 Gateway device with id {} is not present",
-                        l2DeviceName);
+                LOG.info("L2GwConn delete is not handled for device with id {} as it's not connected", l2DeviceName);
             }
         }
     }
 
-    private static void associateHwvtepsToElan(final DataBroker broker, EntityOwnershipService entityOwnershipService,
-            BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, final ElanInstance elanInstance,
-            L2gateway l2Gateway, final Integer defaultVlan, String l2GwDeviceName) {
-        final String elanName = elanInstance.getElanInstanceName();
+    private static void associateHwvtepsToElan(ElanInstance elanInstance,
+            L2gateway l2Gateway, L2gatewayConnection input, String l2GwDeviceName) {
+        String elanName = elanInstance.getElanInstanceName();
+        Integer defaultVlan = input.getSegmentId();
+        Uuid l2GwConnId = input.getKey().getUuid();
         List<Devices> l2Devices = l2Gateway.getDevices();
-        for (final Devices l2Device : l2Devices) {
-            final String l2DeviceName = l2Device.getDeviceName();
+
+        if (LOG.isTraceEnabled()) {
+            LOG.trace("Associating ELAN {} with L2Gw Conn Id {} having below L2Gw devices {}", elanName, l2GwConnId,
+                    l2Devices);
+        }
+
+        for (Devices l2Device : l2Devices) {
+            String l2DeviceName = l2Device.getDeviceName();
             // L2gateway can have more than one L2 Gw devices. Configure Logical Switch, VLAN mappings,...
             // only on the switch which has come up just now and exclude all other devices from
             // preprovisioning/re-provisioning
             if (l2GwDeviceName != null && !l2GwDeviceName.equals(l2DeviceName)) {
+                LOG.debug("Associating Hwvtep to ELAN is not been processed for {}; as only {} got connected now!",
+                        l2DeviceName, l2GwDeviceName);
                 continue;
             }
-            final L2GatewayDevice l2GatewayDevice = L2GatewayCacheUtils.getL2DeviceFromCache(l2DeviceName);
+            L2GatewayDevice l2GatewayDevice = L2GatewayCacheUtils.getL2DeviceFromCache(l2DeviceName);
             if (isL2GwDeviceConnected(l2GatewayDevice)) {
+                NodeId hwvtepNodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
+
+                // Delete pending delete logical switch task if scheduled
+                ElanL2GatewayUtils.cancelDeleteLogicalSwitch(hwvtepNodeId,
+                        ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName));
+
                 // Add L2 Gateway device to 'ElanL2GwDevice' cache
-                final boolean createLogicalSwitch;
+                boolean createLogicalSwitch;
                 LogicalSwitches logicalSwitch = HwvtepUtils.getLogicalSwitch(broker, LogicalDatastoreType.OPERATIONAL,
-                        new NodeId(l2GatewayDevice.getHwvtepNodeId()), elanName);
+                        hwvtepNodeId, elanName);
                 if (logicalSwitch == null) {
-                    final HwvtepLogicalSwitchListener hwVTEPLogicalSwitchListener = new HwvtepLogicalSwitchListener(
-                            l2GatewayDevice, elanName, l2Device, defaultVlan);
+                    HwvtepLogicalSwitchListener hwVTEPLogicalSwitchListener = new HwvtepLogicalSwitchListener(
+                            l2GatewayDevice, elanName, l2Device, defaultVlan, l2GwConnId);
                     hwVTEPLogicalSwitchListener.registerListener(LogicalDatastoreType.OPERATIONAL, broker);
                     createLogicalSwitch = true;
                 } else {
-                    addL2DeviceToElanL2GwCache(elanName, l2GatewayDevice);
+                    addL2DeviceToElanL2GwCache(elanName, l2GatewayDevice, l2GwConnId);
                     createLogicalSwitch = false;
                 }
-                final String hwvtepId = l2GatewayDevice.getHwvtepNodeId();
-                InstanceIdentifier<Node> iid = HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(hwvtepId));
-                ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
-                        entityOwnershipService, HwvtepSouthboundConstants.HWVTEP_ENTITY_TYPE,
-                        bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid));
-                Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
-                    @Override
-                    public void onSuccess(Boolean isOwner) {
-                        if (isOwner) {
-                            LOG.info("Creating Logical switch on {} connected to cluster owner node", l2DeviceName);
-
-                            // Create DataStoreJobCoordinator jobs to create Logical
-                            // switches on all physical switches
-                            // which are part of L2 Gateway
-                            DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
-                            AssociateHwvtepToElan associateHwvtepToElan = new AssociateHwvtepToElan(broker,
-                                    l2GatewayDevice, elanInstance, l2Device, defaultVlan, createLogicalSwitch);
-                            String jobKey = ElanL2GatewayUtils.getL2GatewayConnectionJobKey(hwvtepId, elanName);
-                            dataStoreCoordinator.enqueueJob(jobKey, associateHwvtepToElan,
-                                    SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
-                        } else {
-                            LOG.info("Logical switch creation is not triggered on the cluster node as this is not " +
-                                    "owner for {}", l2DeviceName);
-                        }
-                    }
-
-                    @Override
-                    public void onFailure(Throwable error) {
-                        LOG.error("Failed to trigger Logical switch creation action", error);
-                    }
-                });
-            } else {
-                LOG.error("L2 Gateway device with id {} is not present", l2DeviceName);
-            }
-        }
-    }
-
-    public static void addL2DeviceToElanL2GwCache(String elanName, L2GatewayDevice l2GatewayDevice) {
-        L2GatewayDevice elanL2GwDevice = new L2GatewayDevice();
-        elanL2GwDevice.setHwvtepNodeId(l2GatewayDevice.getHwvtepNodeId());
-        elanL2GwDevice.setDeviceName(l2GatewayDevice.getDeviceName());
-        elanL2GwDevice.setTunnelIps(l2GatewayDevice.getTunnelIps());
-        ElanL2GwCacheUtils.addL2GatewayDeviceToCache(elanName, elanL2GwDevice);
-    }
-
-    private static boolean isL2GwDeviceConnected(L2GatewayDevice l2GwDevice) {
-        return (l2GwDevice != null && l2GwDevice.getHwvtepNodeId() != null && l2GwDevice.isConnected());
-    }
-
-    private static class AssociateHwvtepToElan implements Callable<List<ListenableFuture<Void>>> {
-        DataBroker broker;
-        L2GatewayDevice l2GatewayDevice;
-        ElanInstance elanInstance;
-        Devices l2Device;
-        Integer defaultVlan;
-        boolean createLogicalSwitch;
-
-        public AssociateHwvtepToElan(DataBroker broker, L2GatewayDevice l2GatewayDevice, ElanInstance elanInstance,
-                Devices l2Device, Integer defaultVlan, boolean createLogicalSwitch) {
-            this.broker = broker;
-            this.l2GatewayDevice = l2GatewayDevice;
-            this.elanInstance = elanInstance;
-            this.l2Device = l2Device;
-            this.defaultVlan = defaultVlan;
-            this.createLogicalSwitch = createLogicalSwitch;
-        }
-
-        @Override
-        public List<ListenableFuture<Void>> call() throws Exception {
-            List<ListenableFuture<Void>> futures = new ArrayList<>();
+                AssociateHwvtepToElanJob associateHwvtepToElanJob = new AssociateHwvtepToElanJob(broker,
+                        l2GatewayDevice, elanInstance, l2Device, defaultVlan, createLogicalSwitch);
 
-            final String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanInstance.getElanInstanceName());
+                ElanClusterUtils.runOnlyInLeaderNode( associateHwvtepToElanJob.getJobKey() ,
+                        "create logical switch in hwvtep topo",
+                        associateHwvtepToElanJob);
 
-            // Create Logical Switch if it's not created already in
-            // the device
-            if (createLogicalSwitch) {
-                ListenableFuture<Void> lsCreateFuture = createLogicalSwitch(l2GatewayDevice, elanInstance, l2Device);
-                futures.add(lsCreateFuture);
             } else {
-                // Logical switch is already created; do the rest of
-                // configuration
-                futures.add(ElanL2GatewayUtils.updateVlanBindingsInL2GatewayDevice(
-                        new NodeId(l2GatewayDevice.getHwvtepNodeId()), logicalSwitchName, l2Device, defaultVlan));
-                futures.add(ElanL2GatewayMulticastUtils.handleMcastForElanL2GwDeviceAdd(logicalSwitchName, l2GatewayDevice));
-                HwvtepRemoteMcastMacListener list = new HwvtepRemoteMcastMacListener(ElanUtils.getDataBroker(),
-                        logicalSwitchName, l2GatewayDevice,
-                        new Callable<List<ListenableFuture<Void>>>() {
-
-                        @Override
-                        public List<ListenableFuture<Void>> call() {
-                            List<ListenableFuture<Void>> futures = new ArrayList<>();
-                            futures.add(ElanL2GatewayUtils.installElanMacsInL2GatewayDevice(
-                                    logicalSwitchName, l2GatewayDevice));
-                            return futures;
-                        }}
-                    );
+                LOG.info("L2GwConn create is not handled for device with id {} as it's not connected", l2DeviceName);
             }
-
-            return futures;
         }
+    }
 
-        private ListenableFuture<Void> createLogicalSwitch(L2GatewayDevice l2GatewayDevice, ElanInstance elanInstance,
-                Devices l2Device) {
-            final String logicalSwitchName = ElanL2GatewayUtils
-                    .getLogicalSwitchFromElan(elanInstance.getElanInstanceName());
-            String segmentationId = elanInstance.getVni().toString();
-
-            // Register for Logical switch update in opearational DS
-            final HwvtepLogicalSwitchListener hwVTEPLogicalSwitchListener = new HwvtepLogicalSwitchListener(
-                    l2GatewayDevice, logicalSwitchName, l2Device, defaultVlan);
-            hwVTEPLogicalSwitchListener.registerListener(LogicalDatastoreType.OPERATIONAL, broker);
-
-            NodeId hwvtepNodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
-            InstanceIdentifier<LogicalSwitches> path = HwvtepSouthboundUtils
-                    .createLogicalSwitchesInstanceIdentifier(hwvtepNodeId, new HwvtepNodeName(logicalSwitchName));
-            LogicalSwitches logicalSwitch = HwvtepSouthboundUtils.createLogicalSwitch(logicalSwitchName,
-                    elanInstance.getDescription(), segmentationId);
-
-            ListenableFuture<Void> lsCreateFuture = HwvtepUtils.addLogicalSwitch(broker, hwvtepNodeId, logicalSwitch);
-            Futures.addCallback(lsCreateFuture, new FutureCallback<Void>() {
-                @Override
-                public void onSuccess(Void noarg) {
-                    // Listener will be closed after all configuration completed
-                    // on hwvtep by
-                    // listener itself
-                    if (LOG.isTraceEnabled()) {
-                        LOG.trace("Successful in initiating logical switch {} creation", logicalSwitchName);
-                    }
-                }
+    public static L2GatewayDevice addL2DeviceToElanL2GwCache(String elanName, L2GatewayDevice l2GatewayDevice,
+            Uuid l2GwConnId) {
+        String l2gwDeviceNodeId = l2GatewayDevice.getHwvtepNodeId();
+        L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName, l2gwDeviceNodeId);
+        if (elanL2GwDevice == null) {
+            elanL2GwDevice = new L2GatewayDevice();
+            elanL2GwDevice.setHwvtepNodeId(l2gwDeviceNodeId);
+            elanL2GwDevice.setDeviceName(l2GatewayDevice.getDeviceName());
+            elanL2GwDevice.setTunnelIps(l2GatewayDevice.getTunnelIps());
+            ElanL2GwCacheUtils.addL2GatewayDeviceToCache(elanName, elanL2GwDevice);
+            LOG.debug("Elan L2GwConn cache created for hwvtep id {}", l2gwDeviceNodeId);
+        } else {
+            LOG.debug("Elan L2GwConn cache already exists for hwvtep id {}; updating L2GwConn id {} to it",
+                    l2gwDeviceNodeId, l2GwConnId);
+        }
+        elanL2GwDevice.addL2GatewayId(l2GwConnId);
 
-                @Override
-                public void onFailure(Throwable error) {
-                    LOG.error("Failed logical switch {} creation", logicalSwitchName, error);
-                    try {
-                        hwVTEPLogicalSwitchListener.close();
-                    } catch (final Exception e) {
-                        LOG.error("Error when cleaning up DataChangeListener.", e);
-                    }
-                }
-            });
-            return lsCreateFuture;
+        if (LOG.isTraceEnabled()) {
+            LOG.trace("Elan L2GwConn cache updated with below details: {}", elanL2GwDevice);
         }
+        return elanL2GwDevice;
     }
 
-    private static class DisAssociateHwvtepFromElan implements Callable<List<ListenableFuture<Void>>> {
-        DataBroker broker;
-        L2GatewayDevice l2GatewayDevice;
-        ElanInstance elanInstance;
-        Devices l2Device;
-        Integer defaultVlan;
-
-        public DisAssociateHwvtepFromElan(DataBroker broker, L2GatewayDevice l2GatewayDevice, ElanInstance elanInstance,
-                Devices l2Device, Integer defaultVlan) {
-            this.broker = broker;
-            this.l2GatewayDevice = l2GatewayDevice;
-            this.elanInstance = elanInstance;
-            this.l2Device = l2Device;
-            this.defaultVlan = defaultVlan;
-        }
+    private static boolean isL2GwDeviceConnected(L2GatewayDevice l2GwDevice) {
+        return (l2GwDevice != null && l2GwDevice.getHwvtepNodeId() != null && l2GwDevice.isConnected());
+    }
 
-        @Override
-        public List<ListenableFuture<Void>> call() throws Exception {
-            List<ListenableFuture<Void>> futures = new ArrayList<>();
-
-            // Remove remote MACs and vlan mappings from physical port
-            // Once all above configurations are deleted, delete logical
-            // switch
-            NodeId hwvtepNodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
-            String elanName = elanInstance.getElanInstanceName();
-            futures.add(ElanL2GatewayUtils.deleteElanMacsFromL2GatewayDevice(l2GatewayDevice, elanName));
-            futures.addAll(ElanL2GatewayMulticastUtils.handleMcastForElanL2GwDeviceDelete(elanInstance,
-                    l2GatewayDevice));
-            futures.addAll(ElanL2GatewayUtils.deleteL2GatewayDeviceUcastLocalMacsFromElan(l2GatewayDevice, elanName));
-            futures.add(ElanL2GatewayUtils.deleteVlanBindingsFromL2GatewayDevice(hwvtepNodeId, l2Device, defaultVlan));
-            Thread.sleep(30000);
-            futures.add(HwvtepUtils.deleteLogicalSwitch(this.broker, hwvtepNodeId, elanName));
-
-            return futures;
-        }
+    protected static boolean isLastL2GwConnBeingDeleted(L2GatewayDevice l2GwDevice) {
+        return (l2GwDevice.getL2GatewayIds().size() == 1);
     }
 }
diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/utils/ElanClusterUtils.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/utils/ElanClusterUtils.java
new file mode 100644 (file)
index 0000000..ee4f4d6
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.vpnservice.elan.utils;
+
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
+import org.opendaylight.vpnservice.utils.SystemPropertyReader;
+import org.opendaylight.vpnservice.utils.clustering.ClusteringUtils;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+
+public class ElanClusterUtils {
+    private static final Logger logger = LoggerFactory.getLogger(ElanClusterUtils.class);
+
+    private static EntityOwnershipService eos;
+
+    static DataStoreJobCoordinator dataStoreJobCoordinator;
+
+    public static void setDataStoreJobCoordinator(DataStoreJobCoordinator ds) {
+        dataStoreJobCoordinator = ds;
+    }
+
+    public static void setEntityOwnershipService(EntityOwnershipService entityOwnershipService) {
+        eos = entityOwnershipService;
+    }
+
+    public static void runOnlyInLeaderNode(Runnable job) {
+        runOnlyInLeaderNode(job, "");
+    }
+
+    public static void runOnlyInLeaderNode(final Runnable job, final String jobDescription) {
+        ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
+                eos, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+                HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
+        Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
+            @Override
+            public void onSuccess(Boolean isOwner) {
+                if (isOwner) {
+                    job.run();
+                } else {
+                    logger.trace("job is not run as i m not cluster owner desc :{} ", jobDescription);
+                }
+            }
+            @Override
+            public void onFailure(Throwable error) {
+                logger.error("Failed to identity cluster owner ", error);
+            }
+        });
+    }
+
+    public static void runOnlyInLeaderNode(String jobKey, Callable<List<ListenableFuture<Void>>> dataStoreJob) {
+        runOnlyInLeaderNode(jobKey, "", dataStoreJob);
+    }
+
+    public static void runOnlyInLeaderNode(final String jobKey, final String jobDescription,
+                                           final Callable<List<ListenableFuture<Void>>> dataStoreJob) {
+        ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
+                eos, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+                HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
+        Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
+            @Override
+            public void onSuccess(Boolean isOwner) {
+                if (isOwner) {
+                    logger.trace("scheduling job {} ", jobDescription);
+                    dataStoreJobCoordinator.enqueueJob(jobKey, dataStoreJob,
+                            SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
+                } else {
+                    logger.trace("job is not run as i m not cluster owner desc :{} ", jobDescription);
+                }
+            }
+            @Override
+            public void onFailure(Throwable error) {
+                logger.error("Failed to identity cluster owner for job "+jobDescription, error);
+            }
+        });
+    }
+}
index 51aff882abcfd5ced15831e57d04a9a506537239..e317d14526082eb2a09bafc64aee45cb5260965a 100755 (executable)
@@ -33,4 +33,5 @@ public class ElanConstants {
 
     public static final String L2GATEWAY_DS_JOB_NAME = "L2GW";
     public static final String UNKNOWN_DMAC = "00:00:00:00:00:00";
+    public static final int JOB_MAX_RETRIES = 3;
 }
index e81a2759ee653435b2e881606772ff8d095ee3ac..c53bff81a3027ff1bb504eac54b88c98b68f5b6a 100644 (file)
@@ -9,10 +9,12 @@ package org.opendaylight.vpnservice.elan.utils;
 
 import java.math.BigInteger;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 
+import org.apache.commons.lang3.StringUtils;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
@@ -33,6 +35,10 @@ import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
 import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
 import org.opendaylight.vpnservice.mdsalutil.NwConstants;
 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
@@ -90,13 +96,19 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007.IfIndexesInterfaceMap;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._if.indexes._interface.map.IfIndexInterface;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._if.indexes._interface.map.IfIndexInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeGre;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeVxlan;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.ExternalTunnelList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TunnelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.external.tunnel.list.ExternalTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.external.tunnel.list.ExternalTunnelKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.CreateTerminatingServiceActionsInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.CreateTerminatingServiceActionsInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetExternalTunnelInterfaceNameInput;
@@ -110,6 +122,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev1512
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.RemoveTerminatingServiceActionsInputBuilder;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -122,8 +135,6 @@ import com.google.common.util.concurrent.ListenableFuture;
 
 public class ElanUtils {
 
-    private static final ArrayList EMPTY_LIST = new ArrayList();
-
     private static OdlInterfaceRpcService interfaceMgrRpcService;
 
     private static ItmRpcService itmRpcService;
@@ -571,7 +582,6 @@ public class ElanUtils {
         synchronized (macAddress) {
             logger.info("Acquired lock for mac : " + macAddress + ". Proceeding with install operation.");
             setupKnownSmacFlow(elanInfo, interfaceInfo, macTimeout, macAddress, mdsalMgr);
-            setupTermDmacFlows(interfaceInfo, mdsalMgr);
             setupOrigDmacFlows(elanInfo, interfaceInfo, macAddress, mdsalMgr, dataBroker);
         }
     }
@@ -633,7 +643,7 @@ public class ElanUtils {
      * @param interfaceInfo
      * @param mdsalApiManager
      */
-    private static void setupTermDmacFlows(InterfaceInfo interfaceInfo, IMdsalApiManager mdsalApiManager) {
+    public static void setupTermDmacFlows(InterfaceInfo interfaceInfo, IMdsalApiManager mdsalApiManager) {
         BigInteger dpId = interfaceInfo.getDpId();
         int lportTag = interfaceInfo.getInterfaceTag();
         Flow flow = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
@@ -788,7 +798,7 @@ public class ElanUtils {
     public static List<DpnInterfaces> getInvolvedDpnsInElan(String elanName) {
         List<DpnInterfaces> dpns = ElanInstanceManager.getElanInstanceManager().getElanDPNByName(elanName);
         if (dpns == null) {
-            return EMPTY_LIST;
+            return Collections.emptyList();
         }
         return dpns;
     }
@@ -932,8 +942,6 @@ public class ElanUtils {
                 }
                 mdsalMgr.removeFlow(srcdpId, MDSALUtil.buildFlow(ElanConstants.ELAN_DMAC_TABLE,
                         getKnownDynamicmacFlowRef(ElanConstants.ELAN_DMAC_TABLE, srcdpId, ifTag, macAddress, elanTag)));
-                RemoveTerminatingServiceActionsInput removeTerminatingServiceActionsInput = new RemoveTerminatingServiceActionsInputBuilder().setServiceId(interfaceInfo.getInterfaceTag()).setDpnId(srcdpId).build();
-                itmRpcService.removeTerminatingServiceActions(removeTerminatingServiceActionsInput);
                 if (logger.isDebugEnabled()) {
                     logger.debug("All the required flows deleted for elan:{}, logical Interface port:{} and mac address:{} on dpn:{}", elanInstanceName, interfaceInfo.getPortName(), macAddress, srcdpId);
                 }
@@ -1058,7 +1066,7 @@ public class ElanUtils {
      * @return the list
      */
     public static List<Action> buildItmEgressActions(String tunnelIfaceName, Long tunnelKey) {
-        List<Action> result = EMPTY_LIST;
+        List<Action> result = Collections.emptyList();
         if (tunnelIfaceName != null && !tunnelIfaceName.isEmpty()) {
             GetEgressActionsForInterfaceInput getEgressActInput = new GetEgressActionsForInterfaceInputBuilder()
                     .setIntfName(tunnelIfaceName).setTunnelKey(tunnelKey).build();
@@ -1096,10 +1104,10 @@ public class ElanUtils {
      * @return the external itm egress action
      */
     public static List<Action> getExternalItmEgressAction(BigInteger srcDpnId, NodeId torNode, long vni ) {
-        List<Action> result = EMPTY_LIST;
+        List<Action> result = Collections.emptyList();
 
         GetExternalTunnelInterfaceNameInput input = new GetExternalTunnelInterfaceNameInputBuilder()
-                .setDestinationNode(torNode.getValue()).setSourceNode(srcDpnId.toString()).build();
+                .setDestinationNode(torNode.getValue()).setSourceNode(srcDpnId.toString()).setTunnelType(TunnelTypeVxlan.class).build();
         Future<RpcResult<GetExternalTunnelInterfaceNameOutput>> output =
                 itmRpcService.getExternalTunnelInterfaceName(input);
         try {
@@ -1136,13 +1144,13 @@ public class ElanUtils {
      */
     public static List<Action> getInternalItmEgressAction(BigInteger sourceDpnId, BigInteger destinationDpnId,
             long serviceTag) {
-        List<Action> result = EMPTY_LIST;
+        List<Action> result = Collections.emptyList();
 
         logger.debug("In getInternalItmEgressAction Action source {}, destination {}, elanTag {}",
                      sourceDpnId, destinationDpnId, serviceTag);
-
+        Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
         GetTunnelInterfaceNameInput input = new GetTunnelInterfaceNameInputBuilder()
-                .setDestinationDpid(destinationDpnId).setSourceDpid(sourceDpnId).build();
+                .setDestinationDpid(destinationDpnId).setSourceDpid(sourceDpnId).setTunnelType(tunType).build();
         Future<RpcResult<GetTunnelInterfaceNameOutput>> output = itmRpcService.getTunnelInterfaceName(input);
         try {
             if (output.get().isSuccessful()) {
@@ -1199,6 +1207,69 @@ public class ElanUtils {
         return null;
     }
 
+    /**
+     * Gets the external tunnel.
+     *
+     * @param sourceDevice
+     *            the source device
+     * @param destinationDevice
+     *            the destination device
+     * @param datastoreType
+     *            the datastore type
+     * @return the external tunnel
+     */
+    public static ExternalTunnel getExternalTunnel(String sourceDevice, String destinationDevice,
+            LogicalDatastoreType datastoreType) {
+        ExternalTunnel externalTunnel = null;
+        Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class ;
+        InstanceIdentifier<ExternalTunnel> iid = InstanceIdentifier.builder(ExternalTunnelList.class)
+                .child(ExternalTunnel.class, new ExternalTunnelKey(destinationDevice, sourceDevice, tunType)).build();
+        Optional<ExternalTunnel> tunnelList = read(dataBroker, datastoreType, iid);
+        if (tunnelList.isPresent()) {
+            externalTunnel = tunnelList.get();
+        }
+        return externalTunnel;
+    }
+
+    /**
+     * Gets the external tunnel.
+     *
+     * @param interfaceName
+     *            the interface name
+     * @param datastoreType
+     *            the datastore type
+     * @return the external tunnel
+     */
+    public static ExternalTunnel getExternalTunnel(String interfaceName, LogicalDatastoreType datastoreType) {
+        ExternalTunnel externalTunnel = null;
+        List<ExternalTunnel> externalTunnels = getAllExternalTunnels(datastoreType);
+        for (ExternalTunnel tunnel : externalTunnels) {
+            if (StringUtils.equalsIgnoreCase(interfaceName, tunnel.getTunnelInterfaceName())) {
+                externalTunnel = tunnel;
+                break;
+            }
+        }
+        return externalTunnel;
+    }
+
+    /**
+     * Gets the all external tunnels.
+     *
+     * @return the all external tunnels
+     */
+    public static List<ExternalTunnel> getAllExternalTunnels(LogicalDatastoreType datastoreType) {
+        List<ExternalTunnel> result = null;
+        InstanceIdentifier<ExternalTunnelList> iid = InstanceIdentifier.builder(ExternalTunnelList.class).build();
+        Optional<ExternalTunnelList> tunnelList = read(dataBroker, datastoreType, iid);
+        if (tunnelList.isPresent()) {
+            result = tunnelList.get().getExternalTunnel();
+        }
+        if (result == null) {
+            result = Collections.emptyList();
+        }
+        return result;
+    }
+
     /**
      * Installs a Flow in a DPN's DMAC table. The Flow is for a MAC that is
      * connected remotely in another CSS and accessible through an internal
@@ -1464,5 +1535,63 @@ public class ElanUtils {
         return dpId;
     }
 
+    /**
+     * Checks if is interface operational.
+     *
+     * @param interfaceName
+     *            the interface name
+     * @param dataBroker
+     *            the data broker
+     * @return true, if is interface operational
+     */
+    public static boolean isInterfaceOperational(String interfaceName, DataBroker dataBroker) {
+        if (StringUtils.isBlank(interfaceName)) {
+            return false;
+        }
+        Interface ifState = getInterfaceStateFromOperDS(interfaceName, dataBroker);
+        if (ifState == null) {
+            return false;
+        }
+        return ((ifState.getOperStatus() == OperStatus.Up) && (ifState.getAdminStatus() == AdminStatus.Up));
+    }
+
+    /**
+     * Gets the interface state from operational ds.
+     *
+     * @param interfaceName
+     *            the interface name
+     * @param dataBroker
+     *            the data broker
+     * @return the interface state from oper ds
+     */
+    public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface getInterfaceStateFromOperDS(
+            String interfaceName, DataBroker dataBroker) {
+        InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> ifStateId = createInterfaceStateInstanceIdentifier(
+                interfaceName);
+        Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> ifStateOptional = MDSALUtil
+                .read(dataBroker, LogicalDatastoreType.OPERATIONAL, ifStateId);
+        if (ifStateOptional.isPresent()) {
+            return ifStateOptional.get();
+        }
+        return null;
+    }
+
+    /**
+     * Creates the interface state instance identifier.
+     *
+     * @param interfaceName
+     *            the interface name
+     * @return the instance identifier
+     */
+    public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> createInterfaceStateInstanceIdentifier(
+            String interfaceName) {
+        InstanceIdentifierBuilder<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> idBuilder = InstanceIdentifier
+                .builder(InterfacesState.class)
+                .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class,
+                        new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey(
+                                interfaceName));
+        return idBuilder.build();
+    }
+
 }
 
index 82b13ea413f4a65cb896e7a9393c4b35c0ed9f66..6017e2d21489b416ecfb4282266b17c765e0cc7f 100644 (file)
@@ -40,7 +40,6 @@ public class ElanServiceImplModule extends org.opendaylight.yang.gen.v1.urn.open
         provider.setItmManager(getItmmanagerDependency());
         provider.setIdManager(idManager);
         provider.setEntityOwnershipService(getEntityOwnershipServiceDependency());
-        provider.setBindingNormalizedNodeSerializer(getBindingNormalizedNodeSerializerDependency());
         getBrokerDependency().registerProvider(provider);
         return provider;
     }
index 90ff11504c73f96f630272a00f185e5b4a4a1b51..15df3ee7088cefbb31ff446da4243b44279c2be7 100644 (file)
@@ -85,14 +85,6 @@ module elanservice-impl {
                     }
                 }
             }
-            container binding-normalized-node-serializer {
-                uses config:service-ref {
-                    refine type {
-                        mandatory true;
-                        config:required-identity md-sal-binding:binding-normalized-node-serializer;
-                    }
-                }
-            }
         }
     }
 }
\ No newline at end of file
index 311efac7983d77d16a22f8d6d79a478b4b832966..b73c4f580c9e578913b0d3a2c0ea93421de0d32f 100644 (file)
@@ -27,6 +27,18 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 
 public class ClusteringUtils {
 
+    static DataStoreJobCoordinator dataStoreJobCoordinator;
+
+    static DataStoreJobCoordinator getDataStoreJobCoordinator() {
+        if (dataStoreJobCoordinator == null) {
+            dataStoreJobCoordinator = DataStoreJobCoordinator.getInstance();
+        }
+        return dataStoreJobCoordinator;
+    }
+    public static void setDataStoreJobCoordinator(DataStoreJobCoordinator ds) {
+        dataStoreJobCoordinator = ds;
+    }
+
     public static ListenableFuture<Boolean> checkNodeEntityOwner(EntityOwnershipService entityOwnershipService,
             String entityType, String nodeId) {
         return checkNodeEntityOwner(entityOwnershipService, new Entity(entityType, nodeId),
@@ -42,10 +54,9 @@ public class ClusteringUtils {
     public static ListenableFuture<Boolean> checkNodeEntityOwner(EntityOwnershipService entityOwnershipService,
             Entity entity, long sleepBetweenRetries, int maxRetries) {
         SettableFuture<Boolean> checkNodeEntityfuture = SettableFuture.create();
-        DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
         CheckEntityOwnerTask checkEntityOwnerTask = new CheckEntityOwnerTask(entityOwnershipService, entity,
                 checkNodeEntityfuture, sleepBetweenRetries, maxRetries);
-        dataStoreCoordinator.enqueueJob(entityOwnershipService.toString(), checkEntityOwnerTask);
+        getDataStoreJobCoordinator().enqueueJob(entityOwnershipService.toString(), checkEntityOwnerTask);
         return checkNodeEntityfuture;
     }
 
diff --git a/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/clustering/EntityOwnerUtils.java b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/clustering/EntityOwnerUtils.java
new file mode 100644 (file)
index 0000000..3d2d870
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.vpnservice.utils.clustering;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
+import org.opendaylight.controller.md.sal.common.api.clustering.*;
+import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
+import org.opendaylight.vpnservice.utils.SystemPropertyReader;
+import org.opendaylight.vpnservice.utils.cache.CacheUtil;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentMap;
+
+public class EntityOwnerUtils {
+    public static final String ENTITY_OWNER_CACHE = "entity.owner.cache";
+    private static final Logger LOG = LoggerFactory.getLogger(EntityOwnerUtils.class);
+
+    static {
+        createEntityOwnerCache();
+    }
+    private static void createEntityOwnerCache() {
+        if (CacheUtil.getCache(ENTITY_OWNER_CACHE) == null) {
+            CacheUtil.createCache(ENTITY_OWNER_CACHE);
+        }
+    }
+
+    private static String getEntity(String entityType, String entityName) {
+        return entityType;
+    }
+
+    private static void updateEntityOwner(String entityType, String entityName, Boolean isOwner) {
+        ConcurrentMap<String, Boolean> entityOwnerCache =
+                (ConcurrentMap<String, Boolean>) CacheUtil.getCache(ENTITY_OWNER_CACHE);
+        String entity = getEntity(entityType, entityName);
+        if (entityOwnerCache != null) {
+            LOG.trace("updating entity owner "+isOwner+ " "+entity );
+            entityOwnerCache.put(entity, isOwner);
+        }
+    }
+
+    public static boolean amIEntityOwner(String entityType, String entityName) {
+        ConcurrentMap<String, Boolean> entityOwnerCache =
+                (ConcurrentMap<String, Boolean>) CacheUtil.getCache(ENTITY_OWNER_CACHE);
+        String entity = getEntity(entityType, entityName);
+        boolean ret = false;
+        if (entityOwnerCache != null) {
+            if (entityOwnerCache.get(entity) != null) {
+                ret = entityOwnerCache.get(entity);
+            }
+        } else {
+            LOG.error("entity owner cache null");
+        }
+        LOG.trace("get entity owner result {} for type {}" ,ret ,entity);
+        return ret;
+    }
+
+    /**
+     * Registers the entityName for ownership for given entityType
+     * adds a local listener which takes care of updating the cached entity status
+     * @param entityOwnershipService
+     * @param entityType
+     * @param entityName
+     * @param listener also adds this listener for ownership events if provided
+     * @throws CandidateAlreadyRegisteredException
+     */
+    public static void registerEntityCandidateForOwnerShip  (
+            EntityOwnershipService entityOwnershipService,
+            String entityType, String entityName, EntityOwnershipListener listener)
+            throws CandidateAlreadyRegisteredException {
+        LOG.info("registering for entity ownership for type "+entityType);
+        Entity candidateEntity = new Entity(entityType, entityName);
+        EntityOwnershipCandidateRegistration candidateRegistration = entityOwnershipService.registerCandidate(
+                candidateEntity);
+        EntityOwnershipListenerRegistration listenerRegistration = entityOwnershipService.registerListener(entityType,
+                entityOwnershipListener);
+        if (listener != null) {
+            entityOwnershipService.registerListener(entityType, listener);
+        }
+        LOG.info("registered for entity ownership for type "+entityType);
+        //TODO track registrations for closing
+    }
+
+    private static Listener entityOwnershipListener = new Listener();
+    static class Listener implements EntityOwnershipListener {
+
+        @Override
+        public void ownershipChanged(EntityOwnershipChange ownershipChange) {
+            String entityType = ownershipChange.getEntity().getType();
+            String entityName = ownershipChange.getEntity().getId().toString();
+            LOG.info("entity ownership changed for "+entityType);
+            if (ownershipChange.hasOwner() && ownershipChange.isOwner()) {
+                LOG.info("entity ownership change became owner for type "+entityType);
+                updateEntityOwner(entityType, entityName, Boolean.TRUE);
+            } else {
+                LOG.info("entity ownership lost ownership for type "+entityType);
+                updateEntityOwner(entityType, entityName, Boolean.FALSE);
+            }
+        }
+    }
+}
\ No newline at end of file
index 33eecd9af84f8988c373eb1dccc07ed563f7ed25..ec4bc5c881fb5d322bf77689902f3384f04af1e5 100644 (file)
@@ -21,5 +21,7 @@ public class HwvtepSouthboundConstants {
     public static final Object PSWITCH_URI_PREFIX = "physicalswitch";
     public static final ImmutableBiMap<Class<? extends EncapsulationTypeBase>, String> ENCAPS_TYPE_MAP = new ImmutableBiMap.Builder<Class<? extends EncapsulationTypeBase>, String>()
             .put(EncapsulationTypeVxlanOverIpv4.class, "vxlan_over_ipv4").build();
-
+    public static final String ELAN_ENTITY_TYPE = "elan";
+    public static final String ELAN_ENTITY_NAME = "elan";
+    public static final String TEP_PREFIX = "vxlan_over_ipv4:";
 }
index c1dae6c417673aa25c052c77f0b3977ea11a4102..cdb26525ef0b108049936fd3dbe6be5f0cf49365 100644 (file)
@@ -82,6 +82,11 @@ public class HwvtepSouthboundUtils {
                 .child(Node.class, new NodeKey(nodeId));
     }
 
+
+    public static InstanceIdentifier<TerminationPoint> createTerminationPointId(NodeId nodeId,
+                                                                                TerminationPointKey tpKey) {
+        return createInstanceIdentifier(nodeId).child(TerminationPoint.class, tpKey);
+    }
     /**
      * Creates the logical switches instance identifier.
      *
@@ -374,4 +379,21 @@ public class HwvtepSouthboundUtils {
         return vbBuilder.build();
     }
 
+    public static TerminationPointKey getTerminationPointKey(String ipAddress) {
+        TerminationPointKey tpKey = null;
+        String tpKeyStr = getTerminationPointKeyString(ipAddress);
+        if(tpKeyStr != null) {
+            tpKey = new TerminationPointKey(new TpId(tpKeyStr));
+        }
+        return tpKey;
+    }
+    public static String getTerminationPointKeyString(String ipAddress) {
+        String tpKeyStr = null;
+        if(ipAddress != null) {
+            tpKeyStr = new StringBuilder(HwvtepSouthboundConstants.TEP_PREFIX).
+                    append(ipAddress).toString();
+        }
+        return tpKeyStr;
+    }
+
 }
index 64756366626aab8df3cc988559ff9d75819a8d12..f4d6b4473ea07cff04b01b02c251e692c66098c0 100644 (file)
@@ -8,6 +8,7 @@
 
 package org.opendaylight.vpnservice.utils.hwvtep;
 
+import java.util.ArrayList;
 import java.util.List;
 
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
@@ -16,6 +17,7 @@ import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
@@ -64,10 +66,17 @@ public final class HwvtepUtils {
     public static ListenableFuture<Void> addLogicalSwitch(DataBroker broker, NodeId nodeId,
             LogicalSwitches logicalSwitch) {
         WriteTransaction transaction = broker.newWriteOnlyTransaction();
-        putLogicalSwitch(transaction, nodeId, logicalSwitch);
+        putLogicalSwitch(transaction,LogicalDatastoreType.CONFIGURATION, nodeId, logicalSwitch);
         return transaction.submit();
     }
 
+    public static ListenableFuture<Void> addLogicalSwitch(DataBroker broker, LogicalDatastoreType logicalDatastoreType,
+                                                          NodeId nodeId,
+                                                          LogicalSwitches logicalSwitch) {
+        WriteTransaction transaction = broker.newWriteOnlyTransaction();
+        putLogicalSwitch(transaction,logicalDatastoreType, nodeId, logicalSwitch);
+        return transaction.submit();
+    }
     /**
      * Put the logical switches in the transaction.
      *
@@ -82,7 +91,7 @@ public final class HwvtepUtils {
             final List<LogicalSwitches> lstSwitches) {
         if (lstSwitches != null) {
             for (LogicalSwitches logicalSwitch : lstSwitches) {
-                putLogicalSwitch(transaction, nodeId, logicalSwitch);
+                putLogicalSwitch(transaction,LogicalDatastoreType.CONFIGURATION, nodeId, logicalSwitch);
             }
         }
     }
@@ -97,11 +106,11 @@ public final class HwvtepUtils {
      * @param logicalSwitch
      *            the logical switch
      */
-    public static void putLogicalSwitch(final WriteTransaction transaction, final NodeId nodeId,
-            final LogicalSwitches logicalSwitch) {
+    public static void putLogicalSwitch(final WriteTransaction transaction,LogicalDatastoreType logicalDatastoreType,
+                                        final NodeId nodeId, final LogicalSwitches logicalSwitch) {
         InstanceIdentifier<LogicalSwitches> iid = HwvtepSouthboundUtils.createLogicalSwitchesInstanceIdentifier(nodeId,
                 logicalSwitch.getHwvtepNodeName());
-        transaction.put(LogicalDatastoreType.CONFIGURATION, iid, logicalSwitch, true);
+        transaction.put(logicalDatastoreType, iid, logicalSwitch, true);
     }
 
     /**
@@ -430,6 +439,13 @@ public final class HwvtepUtils {
         transaction.put(LogicalDatastoreType.CONFIGURATION, iid, remoteMcastMac, true);
     }
 
+    public static void putRemoteMcastMac(final WriteTransaction transaction,LogicalDatastoreType logicalDatastoreType,
+                                         final NodeId nodeId,
+                                         RemoteMcastMacs remoteMcastMac) {
+        InstanceIdentifier<RemoteMcastMacs> iid = HwvtepSouthboundUtils.createRemoteMcastMacsInstanceIdentifier(nodeId,
+                remoteMcastMac.getKey());
+        transaction.put(logicalDatastoreType, iid, remoteMcastMac, true);
+    }
     /**
      * Gets the remote mcast mac.
      *
@@ -605,4 +621,37 @@ public final class HwvtepUtils {
         }
         return null;
     }
+
+    /**
+     * Installs a list of Mac Addresses as remote Ucast address in an external
+     * device using the hwvtep-southbound.
+     *
+     * @param deviceNodeId
+     *            NodeId if the ExternalDevice where the macs must be installed
+     *            in.
+     * @param macAddresses
+     *            List of Mac addresses to be installed in the external device.
+     * @param logicalSwitchName
+     *            the logical switch name
+     * @param remoteVtepIp
+     *            VTEP's IP in this CSS used for the tunnel with external
+     *            device.
+     */
+    public static ListenableFuture<Void> installUcastMacs(DataBroker broker,
+                                                          String deviceNodeId, List<PhysAddress> macAddresses,
+                                                          String logicalSwitchName, IpAddress remoteVtepIp) {
+        NodeId nodeId = new NodeId(deviceNodeId);
+        HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
+                .createHwvtepPhysicalLocatorAugmentation(String.valueOf(remoteVtepIp.getValue()));
+        List<RemoteUcastMacs> macs = new ArrayList<RemoteUcastMacs>();
+        for (PhysAddress mac : macAddresses) {
+            // TODO: Query ARP cache to get IP address corresponding to
+            // the MAC
+            IpAddress ipAddress = null;
+            macs.add(HwvtepSouthboundUtils.createRemoteUcastMac(nodeId, mac.getValue(), ipAddress, logicalSwitchName,
+                    phyLocatorAug));
+        }
+        return HwvtepUtils.addRemoteUcastMacs(broker, nodeId, macs);
+    }
+
 }
index e8c777e8d28f71bff10a87397352a61bb7d483c7..2bda4dee5c27064a9395df811b18f5ebd96407e0 100644 (file)
@@ -39,14 +39,6 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
                         </type>
                         <name>mdsalutil-service</name>
                     </mdsalutil>
-                    <entity-ownership-service>
-                        <type xmlns:entity-ownership="urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:entity-ownership-service">entity-ownership:entity-ownership-service</type>
-                        <name>entity-ownership-service</name>
-                    </entity-ownership-service>
-                    <binding-normalized-node-serializer>
-                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-normalized-node-serializer</type>
-                        <name>runtime-mapping-singleton</name>
-                    </binding-normalized-node-serializer>
                     <notification-publish-service>
                         <type xmlns:bindingimpl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">bindingimpl:binding-new-notification-publish-service</type>
                         <name>binding-notification-publish-adapter</name>
@@ -55,6 +47,10 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
                         <type xmlns:bindingimpl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">bindingimpl:binding-new-notification-service</type>
                         <name>binding-notification-adapter</name>
                     </notification-service>
+                    <entity-ownership-service>
+                        <type xmlns:entity-ownership="urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:entity-ownership-service">entity-ownership:entity-ownership-service</type>
+                        <name>entity-ownership-service</name>
+                    </entity-ownership-service>
                 </module>
             </modules>
             <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
index a374e1de30cb5b43f840f359ca7baf39c72924c9..f9a4dcd2909b87995581c1e307d56b98f1e180fd 100644 (file)
@@ -10,12 +10,11 @@ package org.opendaylight.vpnservice.neutronvpn;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
 import org.opendaylight.controller.md.sal.binding.api.NotificationService;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
-import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
 import org.opendaylight.vpnservice.neutronvpn.interfaces.INeutronVpnManager;
 import org.opendaylight.vpnservice.neutronvpn.l2gw.L2GatewayProvider;
@@ -44,10 +43,9 @@ public class NeutronvpnProvider implements BindingAwareProvider, INeutronVpnMana
     private NeutronPortChangeListener portListener;
     private RpcProviderRegistry rpcProviderRegistry;
     private L2GatewayProvider l2GatewayProvider;
-    private EntityOwnershipService entityOwnershipService;
-    private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
     private NotificationPublishService notificationPublishService;
     private NotificationService notificationService;
+    private EntityOwnershipService entityOwnershipService;
 
     public NeutronvpnProvider(RpcProviderRegistry rpcRegistry,NotificationPublishService notificationPublishService,
                               NotificationService notificationService) {
@@ -76,10 +74,6 @@ public class NeutronvpnProvider implements BindingAwareProvider, INeutronVpnMana
         this.entityOwnershipService = entityOwnershipService;
     }
 
-    public void setBindingNormalizedNodeSerializer(BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer) {
-        this.bindingNormalizedNodeSerializer = bindingNormalizedNodeSerializer;
-    }
-
     @Override
     public void onSessionInitiated(ProviderContext session) {
         try {
@@ -94,8 +88,7 @@ public class NeutronvpnProvider implements BindingAwareProvider, INeutronVpnMana
             portListener = new NeutronPortChangeListener(dbx, nvManager,notificationPublishService,notificationService);
             portListener.setLockManager(lockManager);
             nvManager.setLockManager(lockManager);
-            l2GatewayProvider = new L2GatewayProvider(dbx, rpcProviderRegistry, entityOwnershipService,
-                    bindingNormalizedNodeSerializer);
+            l2GatewayProvider = new L2GatewayProvider(dbx, rpcProviderRegistry, entityOwnershipService);
 
             LOG.info("NeutronvpnProvider Session Initiated");
         } catch (Exception e) {
index f62d3f43014eb155ac1b8e657ad69dc9dc0644be..9ab162505506e0fb1dc09d194e19cf710c67ef4f 100644 (file)
@@ -13,7 +13,6 @@ import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 
-import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
@@ -54,15 +53,12 @@ public class L2GatewayListener extends AsyncClusteredDataChangeListenerBase<L2ga
     private final DataBroker broker;
     private ItmRpcService itmRpcService;
     private EntityOwnershipService entityOwnershipService;
-    private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
 
     public L2GatewayListener(final DataBroker db, RpcProviderRegistry rpcRegistry,
-            EntityOwnershipService entityOwnershipService,
-            BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer) {
+            EntityOwnershipService entityOwnershipService) {
         super(L2gateway.class, L2GatewayListener.class);
         broker = db;
         this.entityOwnershipService = entityOwnershipService;
-        this.bindingNormalizedNodeSerializer = bindingNormalizedNodeSerializer;
         itmRpcService = rpcRegistry.getRpcService(ItmRpcService.class);
         registerListener(db);
     }
@@ -135,8 +131,8 @@ public class L2GatewayListener extends AsyncClusteredDataChangeListenerBase<L2ga
                 final String hwvtepId = l2GwDevice.getHwvtepNodeId();
                 InstanceIdentifier<Node> iid = HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(hwvtepId));
                 ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
-                        entityOwnershipService, HwvtepSouthboundConstants.HWVTEP_ENTITY_TYPE,
-                        bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid));
+                        entityOwnershipService, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+                        HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
                 final List<IpAddress> tunnelIps = l2GwDevice.getTunnelIps();
                 Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
                     @Override
@@ -184,8 +180,8 @@ public class L2GatewayListener extends AsyncClusteredDataChangeListenerBase<L2ga
                     final String hwvtepId = l2GwDevice.getHwvtepNodeId();
                     InstanceIdentifier<Node> iid = HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(hwvtepId));
                     ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
-                            entityOwnershipService, HwvtepSouthboundConstants.HWVTEP_ENTITY_TYPE,
-                            bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid));
+                            entityOwnershipService, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+                            HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
                     final List<IpAddress> tunnelIps = l2GwDevice.getTunnelIps();
                     Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
                         @Override
index 2da2a4599fa52da40f0cb660d3fd43c03dd928bd..e0d5445bcea50a1fc9a28f4045453d109cbae1d7 100644 (file)
@@ -12,7 +12,6 @@ import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
 import org.opendaylight.vpnservice.neutronvpn.api.l2gw.utils.L2GatewayCacheUtils;
 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
-import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -22,11 +21,9 @@ public class L2GatewayProvider {
     private L2GatewayListener l2GatewayListener;
 
     public L2GatewayProvider(DataBroker broker, RpcProviderRegistry rpcRegistry,
-            EntityOwnershipService entityOwnershipService,
-            BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer) {
+            EntityOwnershipService entityOwnershipService) {
         L2GatewayCacheUtils.createL2DeviceCache();
-        l2GatewayListener = new L2GatewayListener(broker, rpcRegistry, entityOwnershipService,
-                bindingNormalizedNodeSerializer);
+        l2GatewayListener = new L2GatewayListener(broker, rpcRegistry, entityOwnershipService);
         LOG.info("L2GatewayProvider Initialized");
     }
 
index 90198d70a213a238f85e0e3ac0081a0fc2c8e876..35087e850649d9ac35bd11468d654ced943d7e88 100644 (file)
@@ -39,7 +39,6 @@ public class NeutronvpnImplModule extends org.opendaylight.yang.gen.v1.urn.opend
         provider.setMdsalManager(getMdsalutilDependency());
         provider.setLockManager(lockManagerService);
         provider.setEntityOwnershipService(getEntityOwnershipServiceDependency());
-        provider.setBindingNormalizedNodeSerializer(getBindingNormalizedNodeSerializerDependency());
         getBrokerDependency().registerProvider(provider);
         return provider;
     }
index 33a3b0368c9c02e8f4f2fcf1919e4b6423cb5c3b..b1ef1420cf9e48a57a33ce0a06c696b81bd35609 100644 (file)
@@ -51,24 +51,6 @@ module neutronvpn-impl {
                     }
                 }
             }
-            container entity-ownership-service {
-                uses config:service-ref {
-                    refine type {
-                        mandatory true;
-                        config:required-identity eos:entity-ownership-service;
-                    }
-                }
-            }
-
-            container binding-normalized-node-serializer {
-                uses config:service-ref {
-                    refine type {
-                        mandatory true;
-                        config:required-identity md-sal-binding:binding-normalized-node-serializer;
-                    }
-                }
-            }
-
             container notification-publish-service {
                 uses config:service-ref {
                     refine type {
@@ -83,6 +65,15 @@ module neutronvpn-impl {
                          mandatory true;
                          config:required-identity md-sal-binding-impl:binding-new-notification-service;
                          }
+                    }
+            }
+
+            container entity-ownership-service {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity eos:entity-ownership-service;
+                    }
                 }
             }
         }