Bug9016:Using Single Transaction during NAPT SwitchOver
[netvirt.git] / vpnservice / natservice / natservice-impl / src / main / java / org / opendaylight / netvirt / natservice / internal / ExternalNetworksChangeListener.java
index c95d718814047c161b52bbab47a13de1df0525ed..bd5f5b37084fd07e571efa11096cc2e851a87805 100644 (file)
-/*\r
- * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.\r
- *\r
- * This program and the accompanying materials are made available under the\r
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
- * and is available at http://www.eclipse.org/legal/epl-v10.html\r
- */\r
-\r
-package org.opendaylight.netvirt.natservice.internal;\r
-\r
-import com.google.common.base.Optional;\r
-\r
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;\r
-import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;\r
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;\r
-import org.opendaylight.vpnservice.datastoreutils.AsyncDataTreeChangeListenerBase;\r
-import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;\r
-import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;\r
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceInput;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceInputBuilder;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceOutput;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ExternalNetworks;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.IntextIpMap;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.RouterPorts;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.Ports;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.ports.IpMapping;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMappingKey;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.NaptSwitches;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.networks.Networks;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitch;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;\r
-import org.opendaylight.yangtools.concepts.ListenerRegistration;\r
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;\r
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;\r
-import org.opendaylight.yangtools.yang.common.RpcResult;\r
-import org.slf4j.Logger;\r
-import org.slf4j.LoggerFactory;\r
-\r
-import java.math.BigInteger;\r
-import java.util.List;\r
-import java.util.concurrent.ExecutionException;\r
-import java.util.concurrent.Future;\r
-\r
-import org.opendaylight.bgpmanager.api.IBgpManager;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.FibRpcService;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.VpnRpcService;\r
-\r
-/**\r
- * Created by ESUMAMS on 1/21/2016.\r
- */\r
-public class ExternalNetworksChangeListener extends AsyncDataTreeChangeListenerBase<Networks, ExternalNetworksChangeListener>\r
-{\r
-    private static final Logger LOG = LoggerFactory.getLogger( ExternalNetworksChangeListener.class);\r
-\r
-    private ListenerRegistration<DataChangeListener> listenerRegistration;\r
-    private final DataBroker dataBroker;\r
-    private IMdsalApiManager mdsalManager;\r
-    //private VpnFloatingIpHandler vpnFloatingIpHandler;\r
-    private FloatingIPListener floatingIpListener;\r
-    private ExternalRoutersListener externalRouterListener;\r
-    private OdlInterfaceRpcService interfaceManager;\r
-    private NaptManager naptManager;\r
-\r
-    private IBgpManager bgpManager;\r
-    private VpnRpcService vpnService;\r
-    private FibRpcService fibService;\r
-\r
-\r
-    private ExternalRoutersListener externalRoutersListener;\r
-\r
-    void setMdsalManager(IMdsalApiManager mdsalManager) {\r
-        this.mdsalManager = mdsalManager;\r
-    }\r
-\r
-    void setInterfaceManager(OdlInterfaceRpcService interfaceManager) {\r
-        this.interfaceManager = interfaceManager;\r
-    }\r
-\r
-    void setFloatingIpListener(FloatingIPListener floatingIpListener) {\r
-        this.floatingIpListener = floatingIpListener;\r
-    }\r
-\r
-    void setExternalRoutersListener(ExternalRoutersListener externalRoutersListener) {\r
-        this.externalRouterListener = externalRoutersListener;\r
-    }\r
-\r
-    public void setBgpManager(IBgpManager bgpManager) {\r
-        this.bgpManager = bgpManager;\r
-    }\r
-\r
-    public void setNaptManager(NaptManager naptManager) {\r
-        this.naptManager = naptManager;\r
-    }\r
-\r
-    public void setVpnService(VpnRpcService vpnService) {\r
-        this.vpnService = vpnService;\r
-    }\r
-\r
-    public void setFibService(FibRpcService fibService) {\r
-        this.fibService = fibService;\r
-    }\r
-\r
-    public void setListenerRegistration(ListenerRegistration<DataChangeListener> listenerRegistration) {\r
-        this.listenerRegistration = listenerRegistration;\r
-    }\r
-\r
-    public ExternalNetworksChangeListener(final DataBroker dataBroker ) {\r
-        super( Networks.class, ExternalNetworksChangeListener.class );\r
-        this.dataBroker = dataBroker;\r
-    }\r
-\r
-\r
-    protected InstanceIdentifier<Networks> getWildCardPath() {\r
-        return InstanceIdentifier.create(ExternalNetworks.class).child(Networks.class);\r
-    }\r
-\r
-\r
-    @Override\r
-    protected void add(InstanceIdentifier<Networks> identifier, Networks networks) {\r
-\r
-    }\r
-\r
-    @Override\r
-    protected ExternalNetworksChangeListener getDataTreeChangeListener() {\r
-        return ExternalNetworksChangeListener.this;\r
-    }\r
-\r
-    @Override\r
-    protected void remove(InstanceIdentifier<Networks> identifier, Networks networks) {\r
-        if( identifier == null || networks == null || networks.getRouterIds().isEmpty() ) {\r
-            LOG.info( "ExternalNetworksChangeListener:remove:: returning without processing since networks/identifier is null"  );\r
-            return;\r
-        }\r
-\r
-        for( Uuid routerId: networks.getRouterIds() ) {\r
-            String routerName = routerId.toString();\r
-\r
-            InstanceIdentifier<RouterToNaptSwitch> routerToNaptSwitchInstanceIdentifier =\r
-                    getRouterToNaptSwitchInstanceIdentifier( routerName);\r
-\r
-            MDSALUtil.syncDelete( dataBroker, LogicalDatastoreType.OPERATIONAL, routerToNaptSwitchInstanceIdentifier );\r
-\r
-            LOG.debug( "ExternalNetworksChangeListener:delete:: successful deletion of data in napt-switches container" );\r
-        }\r
-    }\r
-\r
-    private static InstanceIdentifier<RouterToNaptSwitch> getRouterToNaptSwitchInstanceIdentifier( String routerName ) {\r
-\r
-        return  InstanceIdentifier.builder( NaptSwitches.class )\r
-                        .child( RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();\r
-\r
-    }\r
-\r
-    public void close() throws Exception {\r
-        if (listenerRegistration != null) {\r
-            try {\r
-                listenerRegistration.close();\r
-            }\r
-            catch (final Exception e) {\r
-                LOG.error("Error when cleaning up ExternalNetworksChangeListener.", e);\r
-            }\r
-\r
-            listenerRegistration = null;\r
-        }\r
-        LOG.debug("ExternalNetworksChangeListener Closed");\r
-    }\r
-\r
-\r
-    @Override\r
-    protected void update(InstanceIdentifier<Networks> identifier, Networks original, Networks update) {\r
-        //Check for VPN disassociation\r
-        Uuid originalVpn = original.getVpnid();\r
-        Uuid updatedVpn = update.getVpnid();\r
-        if(originalVpn == null && updatedVpn != null) {\r
-            //external network is dis-associated from L3VPN instance\r
-            associateExternalNetworkWithVPN(update);\r
-        } else if(originalVpn != null && updatedVpn == null) {\r
-            //external network is associated with vpn\r
-            disassociateExternalNetworkFromVPN(update, originalVpn.getValue());\r
-            //Remove the SNAT entries\r
-            removeSnatEntries(original, original.getId());\r
-        }\r
-    }\r
-\r
-    private void removeSnatEntries(Networks original, Uuid networkUuid) {\r
-        List<Uuid> routerUuids = original.getRouterIds();\r
-        for (Uuid routerUuid : routerUuids) {\r
-            Long routerId = NatUtil.getVpnId(dataBroker, routerUuid.getValue());\r
-            if (routerId == NatConstants.INVALID_ID) {\r
-                LOG.error("NAT Service : Invalid routerId returned for routerName {}", routerUuid.getValue());\r
-                return;\r
-            }\r
-            List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker,routerId);\r
-            externalRouterListener.handleDisableSnatInternetVpn(routerUuid.getValue(), networkUuid, externalIps, false, original.getVpnid().getValue());\r
-        }\r
-    }\r
-\r
-    private void associateExternalNetworkWithVPN(Networks network) {\r
-        List<Uuid> routerIds = network.getRouterIds();\r
-        for(Uuid routerId : routerIds) {\r
-            //long router = NatUtil.getVpnId(dataBroker, routerId.getValue());\r
-\r
-            InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerId.getValue());\r
-            Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerPortsId);\r
-            if(!optRouterPorts.isPresent()) {\r
-                LOG.debug("Could not read Router Ports data object with id: {} to handle associate ext nw {}", routerId, network.getId());\r
-                continue;\r
-            }\r
-            RouterPorts routerPorts = optRouterPorts.get();\r
-            List<Ports> interfaces = routerPorts.getPorts();\r
-            for(Ports port : interfaces) {\r
-                String portName = port.getPortName();\r
-                BigInteger dpnId = getDpnForInterface(interfaceManager, portName);\r
-                if(dpnId.equals(BigInteger.ZERO)) {\r
-                    LOG.debug("DPN not found for {}, skip handling of ext nw {} association", portName, network.getId());\r
-                    continue;\r
-                }\r
-                List<IpMapping> ipMapping = port.getIpMapping();\r
-                for(IpMapping ipMap : ipMapping) {\r
-                    String externalIp = ipMap.getExternalIp();\r
-                    //remove all VPN related entries\r
-                    floatingIpListener.createNATFlowEntries(dpnId, portName, routerId.getValue(), network.getId(), ipMap.getInternalIp(), externalIp);\r
-                }\r
-            }\r
-        }\r
-\r
-        // SNAT\r
-        for(Uuid routerId : routerIds) {\r
-            LOG.debug("NAT Service : associateExternalNetworkWithVPN() for routerId {}",  routerId);\r
-            Uuid networkId = network.getId();\r
-            if(networkId == null) {\r
-                LOG.error("NAT Service : networkId is null for the router ID {}", routerId);\r
-                return;\r
-            }\r
-            final String vpnName = network.getVpnid().getValue();\r
-            if(vpnName == null) {\r
-                LOG.error("NAT Service : No VPN associated with ext nw {} for router {}", networkId, routerId);\r
-                return;\r
-            }\r
-\r
-            BigInteger dpnId = new BigInteger("0");\r
-            InstanceIdentifier<RouterToNaptSwitch> routerToNaptSwitch = NatUtil.buildNaptSwitchRouterIdentifier(routerId.getValue());\r
-            Optional<RouterToNaptSwitch> rtrToNapt = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, routerToNaptSwitch );\r
-            if(rtrToNapt.isPresent()) {\r
-                dpnId = rtrToNapt.get().getPrimarySwitchId();\r
-            }\r
-            LOG.debug("NAT Service : got primarySwitch as dpnId{} ", dpnId);\r
-\r
-            Long routerIdentifier = NatUtil.getVpnId(dataBroker, routerId.getValue());\r
-            InstanceIdentifierBuilder<org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMapping> idBuilder =\r
-                            InstanceIdentifier.builder(IntextIpMap.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMapping.class, new org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMappingKey(routerIdentifier));\r
-            InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMapping> id = idBuilder.build();\r
-            Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMapping> ipMapping = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);\r
-            if (ipMapping.isPresent()) {\r
-                  List<IpMap> ipMaps = ipMapping.get().getIpMap();\r
-                  for (IpMap ipMap : ipMaps) {\r
-                      String externalIp = ipMap.getExternalIp();\r
-                      LOG.debug("NAT Service : got externalIp as {}", externalIp);\r
-                      LOG.debug("NAT Service : About to call advToBgpAndInstallFibAndTsFlows for dpnId {}, vpnName {} and externalIp {}", dpnId, vpnName, externalIp);\r
-                      externalRouterListener.advToBgpAndInstallFibAndTsFlows(dpnId, NatConstants.INBOUND_NAPT_TABLE, vpnName, NatUtil.getVpnId(dataBroker, routerId.getValue()), externalIp, vpnService, fibService, bgpManager, dataBroker, LOG);\r
-                  }\r
-            } else {\r
-                LOG.warn("NAT Service : No ipMapping present fot the routerId {}", routerId);\r
-            }\r
-\r
-            long vpnId = NatUtil.getVpnId(dataBroker, vpnName);\r
-            // Install 47 entry to point to 21\r
-            if(vpnId != -1) {\r
-                LOG.debug("NAT Service : Calling externalRouterListener installNaptPfibEntry for donId {} and vpnId {}", dpnId, vpnId);\r
-                externalRouterListener.installNaptPfibEntry(dpnId, vpnId);\r
-            }\r
-\r
-        }\r
-\r
-    }\r
-\r
-    private void disassociateExternalNetworkFromVPN(Networks network, String vpnName) {\r
-        List<Uuid> routerIds = network.getRouterIds();\r
-\r
-        //long vpnId = NatUtil.getVpnId(dataBroker, vpnName);\r
-        for(Uuid routerId : routerIds) {\r
-            //long router = NatUtil.getVpnId(dataBroker, routerId.getValue());\r
-\r
-            InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerId.getValue());\r
-            Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerPortsId);\r
-            if(!optRouterPorts.isPresent()) {\r
-                LOG.debug("Could not read Router Ports data object with id: {} to handle disassociate ext nw {}", routerId, network.getId());\r
-                continue;\r
-            }\r
-            RouterPorts routerPorts = optRouterPorts.get();\r
-            List<Ports> interfaces = routerPorts.getPorts();\r
-            for(Ports port : interfaces) {\r
-                String portName = port.getPortName();\r
-                BigInteger dpnId = getDpnForInterface(interfaceManager, portName);\r
-                if(dpnId.equals(BigInteger.ZERO)) {\r
-                    LOG.debug("DPN not found for {}, skip handling of ext nw {} disassociation", portName, network.getId());\r
-                    continue;\r
-                }\r
-                List<IpMapping> ipMapping = port.getIpMapping();\r
-                for(IpMapping ipMap : ipMapping) {\r
-                    String externalIp = ipMap.getExternalIp();\r
-                    floatingIpListener.removeNATFlowEntries(dpnId, portName, vpnName, routerId.getValue(), network.getId(), ipMap.getInternalIp(), externalIp);\r
-                }\r
-            }\r
-        }\r
-    }\r
-\r
-    public static BigInteger getDpnForInterface(OdlInterfaceRpcService interfaceManagerRpcService, String ifName) {\r
-        BigInteger nodeId = BigInteger.ZERO;\r
-        try {\r
-            GetDpidFromInterfaceInput\r
-                    dpIdInput =\r
-                    new GetDpidFromInterfaceInputBuilder().setIntfName(ifName).build();\r
-            Future<RpcResult<GetDpidFromInterfaceOutput>>\r
-                    dpIdOutput =\r
-                    interfaceManagerRpcService.getDpidFromInterface(dpIdInput);\r
-            RpcResult<GetDpidFromInterfaceOutput> dpIdResult = dpIdOutput.get();\r
-            if (dpIdResult.isSuccessful()) {\r
-                nodeId = dpIdResult.getResult().getDpid();\r
-            } else {\r
-                LOG.error("Could not retrieve DPN Id for interface {}", ifName);\r
-            }\r
-        } catch (InterruptedException | ExecutionException e) {\r
-            LOG.error("Exception when getting dpn for interface {}", ifName,  e);\r
-        }\r
-        return nodeId;\r
-    }\r
-\r
-}\r
+/*
+ * 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.netvirt.natservice.internal;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+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.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
+import org.opendaylight.genius.mdsalutil.MDSALUtil;
+import org.opendaylight.genius.mdsalutil.NwConstants;
+import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
+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.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig.NatMode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalNetworks;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.IntextIpMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.NaptSwitches;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.Networks;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPorts;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.Ports;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.VpnRpcService;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Singleton
+public class ExternalNetworksChangeListener
+        extends AsyncDataTreeChangeListenerBase<Networks, ExternalNetworksChangeListener> {
+    private static final Logger LOG = LoggerFactory.getLogger(ExternalNetworksChangeListener.class);
+    private final DataBroker dataBroker;
+    private final IMdsalApiManager mdsalManager;
+    private final FloatingIPListener floatingIpListener;
+    private final ExternalRoutersListener externalRouterListener;
+    private final OdlInterfaceRpcService interfaceManager;
+    private final NaptManager naptManager;
+    private final IBgpManager bgpManager;
+    private final VpnRpcService vpnService;
+    private final FibRpcService fibService;
+    private NatMode natMode = NatMode.Controller;
+
+    @Inject
+    public ExternalNetworksChangeListener(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
+                                          final FloatingIPListener floatingIpListener,
+                                          final ExternalRoutersListener externalRouterListener,
+                                          final OdlInterfaceRpcService interfaceManager,
+                                          final NaptManager naptManager,
+                                          final IBgpManager bgpManager,
+                                          final VpnRpcService vpnService,
+                                          final FibRpcService fibService,
+                                          final NatserviceConfig config) {
+        super(Networks.class, ExternalNetworksChangeListener.class);
+        this.dataBroker = dataBroker;
+        this.mdsalManager = mdsalManager;
+        this.floatingIpListener = floatingIpListener;
+        this.externalRouterListener = externalRouterListener;
+        this.interfaceManager = interfaceManager;
+        this.naptManager = naptManager;
+        this.bgpManager = bgpManager;
+        this.vpnService = vpnService;
+        this.fibService = fibService;
+        if (config != null) {
+            this.natMode = config.getNatMode();
+        }
+    }
+
+    @Override
+    @PostConstruct
+    public void init() {
+        LOG.info("{} init", getClass().getSimpleName());
+        registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
+    }
+
+    @Override
+    protected InstanceIdentifier<Networks> getWildCardPath() {
+        return InstanceIdentifier.create(ExternalNetworks.class).child(Networks.class);
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<Networks> identifier, Networks networks) {
+
+    }
+
+    @Override
+    protected ExternalNetworksChangeListener getDataTreeChangeListener() {
+        return ExternalNetworksChangeListener.this;
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<Networks> identifier, Networks networks) {
+        if (identifier == null || networks == null || networks.getRouterIds().isEmpty()) {
+            LOG.error("remove : returning without processing since networks/identifier is null");
+            return;
+        }
+
+        for (Uuid routerId: networks.getRouterIds()) {
+            String routerName = routerId.toString();
+
+            InstanceIdentifier<RouterToNaptSwitch> routerToNaptSwitchInstanceIdentifier =
+                    getRouterToNaptSwitchInstanceIdentifier(routerName);
+
+            MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, routerToNaptSwitchInstanceIdentifier);
+
+            LOG.debug("remove : successful deletion of data in napt-switches container");
+        }
+    }
+
+    private static InstanceIdentifier<RouterToNaptSwitch> getRouterToNaptSwitchInstanceIdentifier(String routerName) {
+        return  InstanceIdentifier.builder(NaptSwitches.class)
+                        .child(RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<Networks> identifier, Networks original, Networks update) {
+        //Check for VPN disassociation
+        Uuid originalVpn = original.getVpnid();
+        Uuid updatedVpn = update.getVpnid();
+        WriteTransaction writeFlowInvTx = dataBroker.newWriteOnlyTransaction();
+        List<ListenableFuture<Void>> futures = new ArrayList<>();
+        if (originalVpn == null && updatedVpn != null) {
+            //external network is dis-associated from L3VPN instance
+            associateExternalNetworkWithVPN(update, writeFlowInvTx);
+        } else if (originalVpn != null && updatedVpn == null) {
+            //external network is associated with vpn
+            disassociateExternalNetworkFromVPN(update, originalVpn.getValue());
+            //Remove the SNAT entries
+            removeSnatEntries(original, original.getId(), writeFlowInvTx);
+        }
+        futures.add(NatUtil.waitForTransactionToComplete(writeFlowInvTx));
+    }
+
+    private void removeSnatEntries(Networks original, Uuid networkUuid, WriteTransaction writeFlowInvTx) {
+        List<Uuid> routerUuids = original.getRouterIds();
+        for (Uuid routerUuid : routerUuids) {
+            Long routerId = NatUtil.getVpnId(dataBroker, routerUuid.getValue());
+            if (routerId == NatConstants.INVALID_ID) {
+                LOG.error("removeSnatEntries : Invalid routerId returned for routerName {}", routerUuid.getValue());
+                return;
+            }
+            Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker,routerId);
+            if (natMode == NatMode.Controller) {
+                externalRouterListener.handleDisableSnatInternetVpn(routerUuid.getValue(), networkUuid, externalIps,
+                        false, original.getVpnid().getValue(), writeFlowInvTx);
+            }
+        }
+    }
+
+    private void associateExternalNetworkWithVPN(Networks network, WriteTransaction writeFlowInvTx) {
+        List<Uuid> routerIds = network.getRouterIds();
+        for (Uuid routerId : routerIds) {
+            //long router = NatUtil.getVpnId(dataBroker, routerId.getValue());
+
+            InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerId.getValue());
+            Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
+                routerPortsId);
+            if (!optRouterPorts.isPresent()) {
+                LOG.debug("associateExternalNetworkWithVPN : Could not read Router Ports data object with id: {} "
+                        + "to handle associate ext nw {}", routerId, network.getId());
+                continue;
+            }
+            RouterPorts routerPorts = optRouterPorts.get();
+            List<Ports> interfaces = routerPorts.getPorts();
+            for (Ports port : interfaces) {
+                String portName = port.getPortName();
+                BigInteger dpnId = NatUtil.getDpnForInterface(interfaceManager, portName);
+                if (dpnId.equals(BigInteger.ZERO)) {
+                    LOG.debug("associateExternalNetworkWithVPN : DPN not found for {}, "
+                            + "skip handling of ext nw {} association", portName, network.getId());
+                    continue;
+                }
+                List<InternalToExternalPortMap> intExtPortMapList = port.getInternalToExternalPortMap();
+                for (InternalToExternalPortMap ipMap : intExtPortMapList) {
+                    //remove all VPN related entries
+                    floatingIpListener.createNATFlowEntries(dpnId, portName, routerId.getValue(), network.getId(),
+                            ipMap);
+                }
+            }
+        }
+
+        // SNAT
+        for (Uuid routerId : routerIds) {
+            LOG.debug("associateExternalNetworkWithVPN() : for routerId {}",  routerId);
+            Uuid networkId = network.getId();
+            if (networkId == null) {
+                LOG.error("associateExternalNetworkWithVPN : networkId is null for the router ID {}", routerId);
+                return;
+            }
+            final String vpnName = network.getVpnid().getValue();
+            if (vpnName == null) {
+                LOG.error("associateExternalNetworkWithVPN : No VPN associated with ext nw {} for router {}",
+                        networkId, routerId);
+                return;
+            }
+
+            BigInteger dpnId = new BigInteger("0");
+            InstanceIdentifier<RouterToNaptSwitch> routerToNaptSwitch =
+                NatUtil.buildNaptSwitchRouterIdentifier(routerId.getValue());
+            Optional<RouterToNaptSwitch> rtrToNapt =
+                MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerToNaptSwitch);
+            if (rtrToNapt.isPresent()) {
+                dpnId = rtrToNapt.get().getPrimarySwitchId();
+            }
+            LOG.debug("associateExternalNetworkWithVPN : got primarySwitch as dpnId{} ", dpnId);
+            if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
+                LOG.error("associateExternalNetworkWithVPN : primary napt Switch not found for router {}", routerId);
+                return;
+            }
+
+            Long routerIdentifier = NatUtil.getVpnId(dataBroker, routerId.getValue());
+            InstanceIdentifierBuilder<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice
+                .rev160111.intext.ip.map.IpMapping> idBuilder =
+                InstanceIdentifier.builder(IntextIpMap.class)
+                    .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111
+                        .intext.ip.map.IpMapping.class,
+                        new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111
+                            .intext.ip.map.IpMappingKey(routerIdentifier));
+            InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111
+                .intext.ip.map.IpMapping> id = idBuilder.build();
+            Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111
+                .intext.ip.map.IpMapping> ipMapping = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
+            if (ipMapping.isPresent()) {
+                List<IpMap> ipMaps = ipMapping.get().getIpMap();
+                for (IpMap ipMap : ipMaps) {
+                    String externalIp = ipMap.getExternalIp();
+                    LOG.debug("associateExternalNetworkWithVPN : Calling advToBgpAndInstallFibAndTsFlows for dpnId {},"
+                        + "vpnName {} and externalIp {}", dpnId, vpnName, externalIp);
+                    if (natMode == NatMode.Controller) {
+                        externalRouterListener.advToBgpAndInstallFibAndTsFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE,
+                                vpnName, NatUtil.getVpnId(dataBroker, routerId.getValue()), routerId.getValue(),
+                                externalIp, null /* external-router */, vpnService, fibService, bgpManager, dataBroker,
+                                LOG, writeFlowInvTx);
+                    }
+                }
+            } else {
+                LOG.warn("associateExternalNetworkWithVPN : No ipMapping present fot the routerId {}", routerId);
+            }
+
+            long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
+            // Install 47 entry to point to 21
+            if (natMode == NatMode.Controller) {
+                externalRouterListener.installNaptPfibEntriesForExternalSubnets(routerId.getValue(), dpnId,
+                        writeFlowInvTx);
+                if (vpnId != -1) {
+                    LOG.debug("associateExternalNetworkWithVPN : Calling externalRouterListener installNaptPfibEntry "
+                            + "for dpnId {} and vpnId {}", dpnId, vpnId);
+                    externalRouterListener.installNaptPfibEntry(dpnId, vpnId, writeFlowInvTx);
+                }
+            }
+        }
+
+    }
+
+    private void disassociateExternalNetworkFromVPN(Networks network, String vpnName) {
+        List<Uuid> routerIds = network.getRouterIds();
+
+        for (Uuid routerId : routerIds) {
+            InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerId.getValue());
+            Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
+                routerPortsId);
+            if (!optRouterPorts.isPresent()) {
+                LOG.debug("disassociateExternalNetworkFromVPN : Could not read Router Ports data object with id: {} "
+                        + "to handle disassociate ext nw {}", routerId, network.getId());
+                continue;
+            }
+            RouterPorts routerPorts = optRouterPorts.get();
+            List<Ports> interfaces = routerPorts.getPorts();
+            for (Ports port : interfaces) {
+                String portName = port.getPortName();
+                BigInteger dpnId = NatUtil.getDpnForInterface(interfaceManager, portName);
+                if (dpnId.equals(BigInteger.ZERO)) {
+                    LOG.debug("disassociateExternalNetworkFromVPN : DPN not found for {},"
+                            + "skip handling of ext nw {} disassociation", portName, network.getId());
+                    continue;
+                }
+                List<InternalToExternalPortMap> intExtPortMapList = port.getInternalToExternalPortMap();
+                for (InternalToExternalPortMap intExtPortMap : intExtPortMapList) {
+                    floatingIpListener.removeNATFlowEntries(dpnId, portName, vpnName, routerId.getValue(),
+                            intExtPortMap);
+                }
+            }
+        }
+    }
+}