Ensure External Connectivity for NAPT Switch 70/75570/23
authorAswin Suryanarayanan <asuryana@redhat.com>
Thu, 30 Aug 2018 14:27:58 +0000 (19:57 +0530)
committerAswin Suryanarayanan <asuryana@redhat.com>
Mon, 8 Oct 2018 11:40:19 +0000 (11:40 +0000)
Currently, Netvirt code assumes that all the Compute Nodes in the
deployment have external network connectivity (via provider mappings).
However, we could have a deployment scenario where provider mappings
are configured on only few compute nodes. In such a deployment, SNAT
and FIP use-cases for FLAT/VLAN provider networks have to be
appropriately handled.

This patch does the following.
1. NAPT Switch will be scheduled only on the Compute Nodes that have
   the external network connectivity.
2. For a VM with Floating ip, if the compute node (hosting the VM)
   does not have the provider mappings (for external network), traffic
   would be routed from the Compute Node to the NAPT Switch (which is
   selected based on the provider-mappings) and then sent out to the
   External network using the floatingip.
3. When SNAT is disabled on a router only the flows related to NAPT is
removed. The centralized switch is not released and the flows in to send
the packet to the centralized switch and vice versa is retained.

Change-Id: I5908f44cfbdbc74c9a8ee1218931fed9297e65a9
Signed-off-by: Aswin Suryanarayanan <asuryana@redhat.com>
Signed-off-by: Sridhar Gaddam <sgaddam@redhat.com>
(cherry picked from commit 8172c9796e5cba81ec78581f8ca66fefbf0a01e0)

17 files changed:
natservice/api/src/main/java/org/opendaylight/netvirt/natservice/api/CentralizedSwitchScheduler.java
natservice/api/src/main/java/org/opendaylight/netvirt/natservice/api/SnatServiceListener.java
natservice/api/src/main/java/org/opendaylight/netvirt/natservice/api/SnatServiceManager.java
natservice/api/src/main/yang/odl-nat.yang
natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/ha/SnatCentralizedSwitchChangeListener.java
natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/ha/SnatNodeEventListener.java
natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/ha/WeightedCentralizedSwitchScheduler.java
natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/AbstractSnatService.java
natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/ConntrackBasedSnatService.java
natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/FloatingIPListener.java
natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NaptSwitchHA.java
natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatTunnelInterfaceStateListener.java
natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatUtil.java
natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/RouterDpnChangeListener.java
natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/SnatExternalRoutersListener.java
natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/SnatServiceManagerImpl.java
natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/VxlanGreConntrackBasedSnatService.java

index dc01d12e0206d952688bacd0ca85f6a466fdce3d..c5875af28f90d3f74e7c93d454467be0ec127c5c 100644 (file)
@@ -41,7 +41,7 @@ public interface CentralizedSwitchScheduler {
      * @param routerName the router name.
      * @return success/failure
      */
-    boolean getCentralizedSwitch(String routerName);
+    BigInteger getCentralizedSwitch(String routerName);
 
     /**
      * Adds a switch to the scheduler pool.
@@ -57,4 +57,12 @@ public interface CentralizedSwitchScheduler {
      */
     boolean removeSwitch(BigInteger dpnId);
 
+    /**
+     * Check whether the switch has external bridge mappings.
+     * @param dpnId the switch id.
+     * @param providerNet the provider network.
+     * @return whether connected to provider network or not.
+     */
+    boolean isSwitchConnectedToExternal(BigInteger dpnId, String providerNet);
+
 }
index 8fed4756faef381452c391416e1da02d47510c93..7588c4ffab26f00e0c5a13051e0408726fa419db 100644 (file)
@@ -33,7 +33,7 @@ public interface SnatServiceListener {
      * @param confTx The transaction to use.
      * @param routers the router.
      * @param primarySwitchId the primaryswitchId.
-     * @param dpnId the dpnId for which the flows needs to be added/removed.
+     * @param dpnId the dpnId for which the flows needs to be added.
      * @return returns success/failure.
      */
     boolean addSnat(TypedReadWriteTransaction<Configuration> confTx, Routers routers, BigInteger primarySwitchId,
@@ -56,10 +56,52 @@ public interface SnatServiceListener {
      * @param confTx The transaction to use.
      * @param routers the router.
      * @param primarySwitchId the primaryswitchId.
-     * @param dpnId the dpnId for which the flows needs to be added/removed.
+     * @param dpnId the dpnId for which the flows needs to be removed.
      * @return returns success/failure.
      */
     boolean removeSnat(TypedReadWriteTransaction<Configuration> confTx, Routers routers, BigInteger primarySwitchId,
         BigInteger dpnId) throws ExecutionException, InterruptedException;
 
+    /**
+     * Adds flows for centralized switch for all dpns having ports on the router subnet.
+     * @param confTx The transaction to use.
+     * @param routers the router.
+     * @param primarySwitchId the primaryswitchId.
+     * @return returns success/failure.
+     */
+    boolean addCentralizedRouterAllSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
+            BigInteger primarySwitchId);
+
+    /**
+     * Adds flows for centralized switch for the dpnId.
+     * @param confTx The transaction to use.
+     * @param routers the router.
+     * @param primarySwitchId the primaryswitchId.
+     * @param dpnId the dpnId for which the flows needs to be added.
+     * @return returns success/failure.
+     */
+    boolean addCentralizedRouter(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
+            BigInteger primarySwitchId, BigInteger dpnId);
+
+    /**
+     * Removes flows for centralized switch for all dpns having ports on the router subnet.
+     * @param confTx The transaction to use.
+     * @param routers the router.
+     * @param primarySwitchId the primaryswitchId.
+     * @return returns success/failure.
+     */
+    boolean removeCentralizedRouterAllSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
+            BigInteger primarySwitchId)  throws ExecutionException, InterruptedException ;
+
+    /**
+     * Removes flows for centralized switch for the dpnId.
+     * @param confTx The transaction to use.
+     * @param routers the router.
+     * @param primarySwitchId the primaryswitchId.
+     * @param dpnId the dpnId for which the flows needs to be removed.
+     * @return returns success/failure.
+     */
+    boolean removeCentralizedRouter(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
+            BigInteger primarySwitchId, BigInteger dpnId) throws ExecutionException, InterruptedException;
+
 }
index 0154516c598b25cd15b0d9833378effa2d2321f8..ef8b8a4b43e173b6a37a7968c7cbf1a7281d1a78 100644 (file)
@@ -20,7 +20,11 @@ public interface SnatServiceManager {
         SNAT_ALL_SWITCH_ENBL,
         SNAT_ALL_SWITCH_DISBL,
         SNAT_ROUTER_ENBL,
-        SNAT_ROUTER_DISBL
+        SNAT_ROUTER_DISBL,
+        CNT_ROUTER_ALL_SWITCH_ENBL,
+        CNT_ROUTER_ALL_SWITCH_DISBL,
+        CNT_ROUTER_ENBL,
+        CNT_ROUTER_DISBL
     }
 
     void addNatServiceListener(SnatServiceListener aclServiceListner);
@@ -28,7 +32,7 @@ public interface SnatServiceManager {
     void removeNatServiceListener(SnatServiceListener aclServiceListner);
 
     void notify(TypedReadWriteTransaction<Configuration> confTx,
-        Routers router, BigInteger primarySwitchId, BigInteger dpnId, Action action)
+        Routers router, Routers oldRouter, BigInteger primarySwitchId, BigInteger dpnId, Action action)
         throws ExecutionException, InterruptedException;
 
 }
index d06444c5027e94d6b02d23f727df484f7c03aa84..b65163b66d57fea5573d9962c334f6ef0a7c0f92 100644 (file)
@@ -87,6 +87,7 @@ module odl-nat {
             key router-name;
             leaf router-name { type string; }
             leaf primary-switch-id { type uint64; }
+            leaf enable-snat { type boolean; }
         }
     }
 
index aa6940248cb060d2f27cf865dec977dadf395d4b..1b326d2e5ce7e19098f2f13ebda18bf4fb5f8df2 100644 (file)
@@ -82,7 +82,7 @@ public class SnatCentralizedSwitchChangeListener
         Routers router = natDataUtil.getRouter(routerToNaptSwitch.getRouterName());
         if (router != null) {
             ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
-                confTx -> snatServiceManger.notify(confTx, router, primarySwitchId, null,
+                confTx -> snatServiceManger.notify(confTx, router, null, primarySwitchId, null,
                     SnatServiceManager.Action.SNAT_ALL_SWITCH_DISBL)), LOG,
                 "error handling SNAT centralized switch removal");
             natDataUtil.removeFromRouterMap(router);
@@ -94,19 +94,47 @@ public class SnatCentralizedSwitchChangeListener
             RouterToNaptSwitch updatedRouterToNaptSwitch) {
         LOG.debug("Updating old {} new {}", origRouterToNaptSwitch, updatedRouterToNaptSwitch);
         BigInteger origPrimarySwitchId = origRouterToNaptSwitch.getPrimarySwitchId();
+        BigInteger updatedPrimarySwitchId = updatedRouterToNaptSwitch.getPrimarySwitchId();
         ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
             Routers origRouter = NatUtil.getRoutersFromConfigDS(confTx, origRouterToNaptSwitch.getRouterName());
-            if (origRouter != null) {
-                snatServiceManger.notify(confTx, origRouter, origPrimarySwitchId, null,
-                    SnatServiceManager.Action.SNAT_ALL_SWITCH_DISBL);
-                natDataUtil.removeFromRouterMap(origRouter);
-            }
-            BigInteger updatedPrimarySwitchId = updatedRouterToNaptSwitch.getPrimarySwitchId();
             Routers updatedRouter = NatUtil.getRoutersFromConfigDS(confTx, updatedRouterToNaptSwitch.getRouterName());
-            if (updatedRouter != null) {
-                natDataUtil.updateRouterMap(updatedRouter);
-                snatServiceManger.notify(confTx, updatedRouter, updatedPrimarySwitchId, null,
-                    SnatServiceManager.Action.SNAT_ALL_SWITCH_ENBL);
+            if (origPrimarySwitchId != updatedPrimarySwitchId) {
+                if (origRouter != null) {
+                    snatServiceManger.notify(confTx, origRouter, null, origPrimarySwitchId, null,
+                            SnatServiceManager.Action.CNT_ROUTER_ALL_SWITCH_DISBL);
+                    if (origRouterToNaptSwitch.isEnableSnat()) {
+                        snatServiceManger.notify(confTx, origRouter, null, origPrimarySwitchId, null,
+                                SnatServiceManager.Action.SNAT_ALL_SWITCH_DISBL);
+                    }
+                    natDataUtil.removeFromRouterMap(origRouter);
+                }
+                if (updatedRouter != null) {
+                    natDataUtil.updateRouterMap(updatedRouter);
+                    snatServiceManger.notify(confTx, updatedRouter, null, updatedPrimarySwitchId, null,
+                            SnatServiceManager.Action.CNT_ROUTER_ALL_SWITCH_ENBL);
+                    if (updatedRouterToNaptSwitch.isEnableSnat()) {
+                        snatServiceManger.notify(confTx, updatedRouter, null, updatedPrimarySwitchId, null,
+                                SnatServiceManager.Action.SNAT_ALL_SWITCH_ENBL);
+                    }
+                }
+            } else {
+                boolean origIsSnatEnabled = false;
+                boolean updatedIsSnatEnabled = false;
+                if (origRouterToNaptSwitch.isEnableSnat() != null) {
+                    origIsSnatEnabled = origRouterToNaptSwitch.isEnableSnat();
+                }
+                if (updatedRouterToNaptSwitch.isEnableSnat() != null) {
+                    updatedIsSnatEnabled = updatedRouterToNaptSwitch.isEnableSnat();
+                }
+                if (origIsSnatEnabled != updatedIsSnatEnabled) {
+                    if (updatedRouterToNaptSwitch.isEnableSnat()) {
+                        snatServiceManger.notify(confTx, updatedRouter, null, updatedPrimarySwitchId, null,
+                                SnatServiceManager.Action.SNAT_ALL_SWITCH_ENBL);
+                    } else {
+                        snatServiceManger.notify(confTx, origRouter, null, origPrimarySwitchId, null,
+                                SnatServiceManager.Action.SNAT_ALL_SWITCH_DISBL);
+                    }
+                }
             }
         }), LOG, "Error handling SNAT centralized switch update");
     }
@@ -117,6 +145,12 @@ public class SnatCentralizedSwitchChangeListener
         BigInteger primarySwitchId = routerToNaptSwitch.getPrimarySwitchId();
         String routerName = routerToNaptSwitch.getRouterName();
         Routers router = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
+        final boolean isEnableSnat;
+        if (routerToNaptSwitch.isEnableSnat() != null) {
+            isEnableSnat = routerToNaptSwitch.isEnableSnat();
+        } else {
+            isEnableSnat = false;
+        }
         long vpnId = NatUtil.getVpnId(dataBroker, routerName);
         if (vpnId == NatConstants.INVALID_ID) {
             LOG.warn("VpnId not unavailable for router {} yet", routerName);
@@ -124,7 +158,8 @@ public class SnatCentralizedSwitchChangeListener
                 NatUtil.getVpnInstanceToVpnIdIdentifier(routerName), (unused, newVpnId) -> {
                     ListenableFutures.addErrorLogging(
                         txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
-                            innerConfTx -> handleAdd(innerConfTx, routerName, router, primarySwitchId)), LOG,
+                            innerConfTx -> handleAdd(innerConfTx, routerName, router, primarySwitchId,
+                                    isEnableSnat)), LOG,
                         "Error handling router addition");
                     return DataTreeEventCallbackRegistrar.NextAction.UNREGISTER;
                 }, Duration.ofSeconds(5), iid -> LOG.error("VpnId not found for router {}", routerName));
@@ -132,17 +167,21 @@ public class SnatCentralizedSwitchChangeListener
         }
         ListenableFutures.addErrorLogging(
             txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
-                confTx -> handleAdd(confTx, routerName, router, primarySwitchId)), LOG,
-            "Error handling router addition");
+                confTx -> handleAdd(confTx, routerName, router, primarySwitchId,
+                        isEnableSnat)), LOG, "Error handling router addition");
     }
 
     private void handleAdd(TypedReadWriteTransaction<Datastore.Configuration> confTx,
-            String routerName, Routers router, BigInteger primarySwitchId)
+            String routerName, Routers router, BigInteger primarySwitchId, boolean isSnatEnabled)
             throws ExecutionException, InterruptedException {
         if (router != null) {
             natDataUtil.addtoRouterMap(router);
-            snatServiceManger.notify(confTx, router, primarySwitchId, null,
-                SnatServiceManager.Action.SNAT_ALL_SWITCH_ENBL);
+            snatServiceManger.notify(confTx, router, null, primarySwitchId, null,
+                    SnatServiceManager.Action.CNT_ROUTER_ALL_SWITCH_ENBL);
+            if (isSnatEnabled) {
+                snatServiceManger.notify(confTx, router, null, primarySwitchId, null,
+                        SnatServiceManager.Action.SNAT_ALL_SWITCH_ENBL);
+            }
         } else {
             LOG.error("Router {} not found for primarySwitch {}", routerName, primarySwitchId);
         }
index 866add0b8ac3f3504e5e93da26736a0289181e39..081280c0ae0e11498b3518188c8a92058f52b380 100644 (file)
@@ -22,7 +22,6 @@ import org.opendaylight.serviceutils.tools.mdsal.listener.AbstractClusteredAsync
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -35,32 +34,23 @@ import org.slf4j.LoggerFactory;
 public class SnatNodeEventListener  extends AbstractClusteredAsyncDataTreeChangeListener<Node> {
     private static final Logger LOG = LoggerFactory.getLogger(SnatNodeEventListener.class);
     private final CentralizedSwitchScheduler  centralizedSwitchScheduler;
-    private final NatserviceConfig.NatMode natMode;
 
     @Inject
     public SnatNodeEventListener(final DataBroker dataBroker,
-            final CentralizedSwitchScheduler centralizedSwitchScheduler,
-            final NatserviceConfig config) {
+            final CentralizedSwitchScheduler centralizedSwitchScheduler) {
 
         super(dataBroker,new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL, InstanceIdentifier
                 .create(Nodes.class).child(Node.class)),
                 Executors.newSingleThreadExecutor());
         this.centralizedSwitchScheduler = centralizedSwitchScheduler;
-        if (config != null) {
-            this.natMode = config.getNatMode();
-        } else {
-            this.natMode = NatserviceConfig.NatMode.Controller;
-        }
     }
 
     @Override
     public void remove(Node dataObjectModification) {
-        if (natMode == NatserviceConfig.NatMode.Conntrack) {
-            NodeKey nodeKey = dataObjectModification.key();
-            BigInteger dpnId = MDSALUtil.getDpnIdFromNodeName(nodeKey.getId());
-            LOG.info("Dpn removed {}", dpnId);
-            centralizedSwitchScheduler.removeSwitch(dpnId);
-        }
+        NodeKey nodeKey = dataObjectModification.key();
+        BigInteger dpnId = MDSALUtil.getDpnIdFromNodeName(nodeKey.getId());
+        LOG.info("Dpn removed {}", dpnId);
+        centralizedSwitchScheduler.removeSwitch(dpnId);
     }
 
     @Override
@@ -71,11 +61,9 @@ public class SnatNodeEventListener  extends AbstractClusteredAsyncDataTreeChange
 
     @Override
     public void add(Node dataObjectModification) {
-        if (natMode == NatserviceConfig.NatMode.Conntrack) {
-            NodeKey nodeKey = dataObjectModification.key();
-            BigInteger dpnId = MDSALUtil.getDpnIdFromNodeName(nodeKey.getId());
-            LOG.info("Dpn added {}", dpnId);
-            centralizedSwitchScheduler.addSwitch(dpnId);
-        }
+        NodeKey nodeKey = dataObjectModification.key();
+        BigInteger dpnId = MDSALUtil.getDpnIdFromNodeName(nodeKey.getId());
+        LOG.info("Dpn added {}", dpnId);
+        centralizedSwitchScheduler.addSwitch(dpnId);
     }
 }
index 5fdf97769077e5130e9f3e332b7b918278e53ef4..dce1357832b52e3c6fe648f1299711bf65f612f7 100644 (file)
@@ -12,6 +12,7 @@ import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
 import static org.opendaylight.genius.infra.Datastore.OPERATIONAL;
 
 import com.google.common.base.Optional;
+
 import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -21,8 +22,10 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutionException;
+
 import javax.inject.Inject;
 import javax.inject.Singleton;
+
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
@@ -36,6 +39,7 @@ import org.opendaylight.netvirt.natservice.internal.NatUtil;
 import org.opendaylight.netvirt.vpnmanager.api.IVpnFootprintService;
 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.natservice.config.rev170206.NatserviceConfig;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExtRouters;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.NaptSwitches;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
@@ -56,26 +60,33 @@ public class WeightedCentralizedSwitchScheduler implements CentralizedSwitchSche
     private static final Logger LOG = LoggerFactory.getLogger(WeightedCentralizedSwitchScheduler.class);
     private static final Integer INITIAL_SWITCH_WEIGHT = Integer.valueOf(0);
 
-    private final Map<BigInteger,Integer> switchWeightsMap = new ConcurrentHashMap<>();
+    private final Map<String, Map<BigInteger,Integer>> providerSwitchWeightsMap = new ConcurrentHashMap<>();
     private final Map<String,String> subnetIdToRouterPortMap = new ConcurrentHashMap<>();
     private final Map<String,String> subnetIdToElanInstanceMap = new ConcurrentHashMap<>();
     private final DataBroker dataBroker;
     private final ManagedNewTransactionRunner txRunner;
     private final OdlInterfaceRpcService interfaceManager;
     private final IVpnFootprintService vpnFootprintService;
+    private final NatserviceConfig.NatMode natMode;
 
     @Inject
     public WeightedCentralizedSwitchScheduler(DataBroker dataBroker, OdlInterfaceRpcService interfaceManager,
-            IVpnFootprintService vpnFootprintService) {
+            IVpnFootprintService vpnFootprintService, final NatserviceConfig config) {
         this.dataBroker = dataBroker;
         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
         this.interfaceManager = interfaceManager;
         this.vpnFootprintService = vpnFootprintService;
+        if (config != null) {
+            this.natMode = config.getNatMode();
+        } else {
+            this.natMode = NatserviceConfig.NatMode.Controller;
+        }
     }
 
     @Override
     public boolean scheduleCentralizedSwitch(Routers router) {
-        BigInteger nextSwitchId = getSwitchWithLowestWeight();
+        String providerNet = NatUtil.getElanInstancePhysicalNetwok(router.getNetworkId().getValue(),dataBroker);
+        BigInteger nextSwitchId = getSwitchWithLowestWeight(providerNet);
         if (nextSwitchId == BigInteger.valueOf(0)) {
             LOG.error("In scheduleCentralizedSwitch, unable to schedule the router {} as there is no available switch.",
                     router.getRouterName());
@@ -86,12 +97,14 @@ public class WeightedCentralizedSwitchScheduler implements CentralizedSwitchSche
         String routerName = router.getRouterName();
         RouterToNaptSwitchBuilder routerToNaptSwitchBuilder =
                 new RouterToNaptSwitchBuilder().setRouterName(routerName);
-        RouterToNaptSwitch id = routerToNaptSwitchBuilder.setPrimarySwitchId(nextSwitchId).build();
+        RouterToNaptSwitch id = routerToNaptSwitchBuilder.setPrimarySwitchId(nextSwitchId)
+                .setEnableSnat(router.isEnableSnat()).build();
         addToDpnMaps(routerName, router.getSubnetIds(), nextSwitchId);
         try {
             SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
                     getNaptSwitchesIdentifier(routerName), id);
-            switchWeightsMap.put(nextSwitchId,switchWeightsMap.get(nextSwitchId) + 1);
+            Map<BigInteger,Integer> switchWeightMap = providerSwitchWeightsMap.get(providerNet);
+            switchWeightMap.put(nextSwitchId,switchWeightMap.get(nextSwitchId) + 1);
 
         } catch (TransactionCommitFailedException e) {
             LOG.error("ScheduleCentralizedSwitch failed for {}", routerName);
@@ -109,19 +122,47 @@ public class WeightedCentralizedSwitchScheduler implements CentralizedSwitchSche
         BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, newRouter.getRouterName());
         addToDpnMaps(routerName, addedSubnetIds, primarySwitchId);
         deleteFromDpnMaps(routerName, deletedSubnetIds, primarySwitchId);
+        try {
+            InstanceIdentifier<RouterToNaptSwitch> id  = NatUtil.buildNaptSwitchIdentifier(routerName);
+            RouterToNaptSwitch routerToNaptSwitch = SingleTransactionDataBroker.syncRead(dataBroker,
+                    LogicalDatastoreType.CONFIGURATION, id);
+            boolean isSnatEnabled = newRouter.isEnableSnat();
+            List<ExternalIps> updateExternalIps = newRouter.getExternalIps();
+            if (updateExternalIps == null || updateExternalIps.isEmpty()) {
+                isSnatEnabled = false;
+            }
+            if (isSnatEnabled != routerToNaptSwitch.isEnableSnat()) {
+                RouterToNaptSwitchBuilder routerToNaptSwitchBuilder =
+                        new RouterToNaptSwitchBuilder(routerToNaptSwitch);
+                routerToNaptSwitchBuilder.setEnableSnat(isSnatEnabled);
+                SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
+                        getNaptSwitchesIdentifier(routerName), routerToNaptSwitchBuilder.build());
+            }
+        } catch (ReadFailedException e) {
+            LOG.error("updateCentralizedSwitch ReadFailedException for {}", routerName);
+        } catch (TransactionCommitFailedException e) {
+            LOG.error("updateCentralizedSwitch TransactionCommitFailedException for {}", routerName);
+        }
         return true;
     }
 
     @Override
     public boolean releaseCentralizedSwitch(Routers router) {
+        String providerNet = NatUtil.getElanInstancePhysicalNetwok(router.getNetworkId().getValue(),dataBroker);
         String routerName = router.getRouterName();
         BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
+        if (primarySwitchId == null || primarySwitchId == BigInteger.valueOf(0)) {
+            LOG.info("releaseCentralizedSwitch: NAPT Switch is not allocated for router {}", router.getRouterName());
+            return false;
+        }
+
         LOG.info("releaseCentralizedSwitch for router {} from switch {}", router.getRouterName(), primarySwitchId);
         deleteFromDpnMaps(routerName, router.getSubnetIds(), primarySwitchId);
         try {
             SingleTransactionDataBroker.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION,
                     getNaptSwitchesIdentifier(routerName));
-            switchWeightsMap.put(primarySwitchId,switchWeightsMap.get(primarySwitchId) - 1);
+            Map<BigInteger,Integer> switchWeightMap = providerSwitchWeightsMap.get(providerNet);
+            switchWeightMap.put(primarySwitchId, switchWeightMap.get(primarySwitchId) - 1);
         } catch (TransactionCommitFailedException e) {
             return false;
         }
@@ -201,11 +242,19 @@ public class WeightedCentralizedSwitchScheduler implements CentralizedSwitchSche
     @Override
     public boolean addSwitch(BigInteger dpnId) {
         /* Initialize the switch in the map with weight 0 */
-        LOG.info("addSwitch: Adding {} dpnId to switchWeightsMap", dpnId);
-        boolean scheduleRouters = (switchWeightsMap.size() == 0) ? true : false;
-        switchWeightsMap.put(dpnId, INITIAL_SWITCH_WEIGHT);
-
-        if (scheduleRouters) {
+        LOG.info("addSwitch: Retrieving the provider config for {}", dpnId);
+        boolean scheduleRouters = (providerSwitchWeightsMap.size() == 0) ? true : false;
+        Map<String, String> providerMappingsMap = NatUtil.getOpenvswitchOtherConfigMap(dpnId, dataBroker);
+        for (String providerNet : providerMappingsMap.keySet()) {
+            Map<BigInteger,Integer> switchWeightMap = providerSwitchWeightsMap.get(providerNet);
+            if (providerSwitchWeightsMap.get(providerNet) == null) {
+                switchWeightMap = new ConcurrentHashMap<>();
+                providerSwitchWeightsMap.put(providerNet, switchWeightMap);
+            }
+            LOG.info("addSwitch: Adding {} dpnId with provider mapping {} to switchWeightsMap", dpnId, providerNet);
+            switchWeightMap.put(dpnId, INITIAL_SWITCH_WEIGHT);
+        }
+        if (natMode == NatserviceConfig.NatMode.Conntrack && scheduleRouters) {
             Optional<ExtRouters> optRouters;
             try {
                 optRouters = SingleTransactionDataBroker.syncReadOptional(dataBroker,
@@ -251,33 +300,40 @@ public class WeightedCentralizedSwitchScheduler implements CentralizedSwitchSche
     @Override
     public boolean removeSwitch(BigInteger dpnId) {
         LOG.info("removeSwitch: Removing {} dpnId to switchWeightsMap", dpnId);
-        if (!INITIAL_SWITCH_WEIGHT.equals(switchWeightsMap.get(dpnId))) {
-            NaptSwitches naptSwitches = getNaptSwitches(dataBroker);
-            for (RouterToNaptSwitch routerToNaptSwitch : naptSwitches.getRouterToNaptSwitch()) {
-                if (dpnId.equals(routerToNaptSwitch.getPrimarySwitchId())) {
-                    Routers router = NatUtil.getRoutersFromConfigDS(dataBroker, routerToNaptSwitch.getRouterName());
-                    releaseCentralizedSwitch(router);
-                    switchWeightsMap.remove(dpnId);
-                    scheduleCentralizedSwitch(router);
-                    break;
+        for (Map.Entry<String,Map<BigInteger,Integer>> providerNet : providerSwitchWeightsMap.entrySet()) {
+            Map<BigInteger,Integer> switchWeightMap = providerNet.getValue();
+            if (natMode == NatserviceConfig.NatMode.Conntrack
+                    && !INITIAL_SWITCH_WEIGHT.equals(switchWeightMap.get(dpnId))) {
+                NaptSwitches naptSwitches = getNaptSwitches();
+                for (RouterToNaptSwitch routerToNaptSwitch : naptSwitches.getRouterToNaptSwitch()) {
+                    if (dpnId.equals(routerToNaptSwitch.getPrimarySwitchId())) {
+                        Routers router = NatUtil.getRoutersFromConfigDS(dataBroker, routerToNaptSwitch.getRouterName());
+                        releaseCentralizedSwitch(router);
+                        scheduleCentralizedSwitch(router);
+                        break;
+                    }
                 }
             }
-        } else {
-            switchWeightsMap.remove(dpnId);
+            switchWeightMap.remove(dpnId);
         }
         return true;
     }
 
-    public static NaptSwitches getNaptSwitches(DataBroker dataBroker) {
+    private NaptSwitches getNaptSwitches() {
         InstanceIdentifier<NaptSwitches> id = InstanceIdentifier.builder(NaptSwitches.class).build();
         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
                 LogicalDatastoreType.CONFIGURATION, id).orNull();
     }
 
-    private BigInteger getSwitchWithLowestWeight() {
+    private BigInteger getSwitchWithLowestWeight(String providerNet) {
         int lowestWeight = Integer.MAX_VALUE;
         BigInteger nextSwitchId = BigInteger.valueOf(0);
-        for (Entry<BigInteger, Integer> entry : switchWeightsMap.entrySet()) {
+        Map<BigInteger,Integer> switchWeightMap = providerSwitchWeightsMap.get(providerNet);
+        if (null == switchWeightMap) {
+            LOG.error("No switch have the provider mapping {}", providerNet);
+            return nextSwitchId;
+        }
+        for (Entry<BigInteger, Integer> entry : switchWeightMap.entrySet()) {
             BigInteger dpnId = entry.getKey();
             Integer weight = entry.getValue();
             if (lowestWeight > weight) {
@@ -286,7 +342,7 @@ public class WeightedCentralizedSwitchScheduler implements CentralizedSwitchSche
             }
         }
         LOG.info("getSwitchWithLowestWeight: switchWeightsMap {}, returning nextSwitchId {} ",
-                switchWeightsMap, nextSwitchId);
+                providerSwitchWeightsMap, nextSwitchId);
         return nextSwitchId;
     }
 
@@ -300,9 +356,28 @@ public class WeightedCentralizedSwitchScheduler implements CentralizedSwitchSche
                 new SubnetmapKey(subnetId)).build();
     }
 
+    public BigInteger getCentralizedSwitch(String routerName) {
+        try {
+            Optional<RouterToNaptSwitch> naptSwitches = SingleTransactionDataBroker
+                    .syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
+                            getNaptSwitchesIdentifier(routerName));
+            if (!naptSwitches.isPresent()) {
+                LOG.info("No Napt switch is scheduled for {}", routerName);
+                return null;
+            }
+            return naptSwitches.get().getPrimarySwitchId();
+        } catch (ReadFailedException e) {
+            LOG.error("Error reading RouterToNaptSwitch model", e);
+            return null;
+        }
+    }
+
     @Override
-    public boolean getCentralizedSwitch(String routerName) {
-        // TODO Auto-generated method stub
+    public boolean isSwitchConnectedToExternal(BigInteger dpnId, String providerNet) {
+        Map<BigInteger,Integer> switchWeightMap = providerSwitchWeightsMap.get(providerNet);
+        if (switchWeightMap != null) {
+            return switchWeightMap.containsKey(dpnId);
+        }
         return false;
     }
 
index a1d1de1215d4af1e7ac608a1e09db07d1e0be894..9d53b33cd673aa2ef8a9c67e25e3764f146ce590 100644 (file)
@@ -145,7 +145,7 @@ public abstract class AbstractSnatService implements SnatServiceListener {
     @Override
     public boolean addSnatAllSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
         BigInteger primarySwitchId) {
-        LOG.info("handleSnatAllSwitch : Handle Snat in all switches for router {}", routers.getRouterName());
+        LOG.info("addSnatAllSwitch : Handle Snat in all switches for router {}", routers.getRouterName());
         String routerName = routers.getRouterName();
         List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
         /*
@@ -164,27 +164,19 @@ public abstract class AbstractSnatService implements SnatServiceListener {
     @Override
     public boolean removeSnatAllSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
             BigInteger primarySwitchId) throws ExecutionException, InterruptedException {
-        LOG.info("handleSnatAllSwitch : Handle Snat in all switches for router {}", routers.getRouterName());
+        LOG.info("removeSnatAllSwitch : Handle Snat in all switches for router {}", routers.getRouterName());
         String routerName = routers.getRouterName();
         List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
         /*
          * Primary switch handled separately since the pseudo port created may
          * not be present in the switch list on delete.
          */
-        boolean isLastRouterDelete =
-            NatUtil.isLastExternalRouter(routers.getNetworkId().getValue(), routers.getRouterName(), natDataUtil);
-        LOG.info("handleSnatAllSwitch : action is delete for router {} and isLastRouterDelete is {}",
-            routers.getRouterName(), isLastRouterDelete);
         removeSnat(confTx, routers, primarySwitchId, primarySwitchId);
         for (BigInteger dpnId : switches) {
             if (!Objects.equals(primarySwitchId, dpnId)) {
                 removeSnat(confTx, routers, primarySwitchId, dpnId);
             }
         }
-        if (isLastRouterDelete) {
-            removeLearntIpPorts(routers);
-            removeMipAdjacencies(routers);
-        }
         return true;
     }
 
@@ -194,11 +186,11 @@ public abstract class AbstractSnatService implements SnatServiceListener {
 
         // Handle non NAPT switches and NAPT switches separately
         if (!dpnId.equals(primarySwitchId)) {
-            LOG.info("handleSnat : Handle non NAPT switch {} for router {}", dpnId, routers.getRouterName());
+            LOG.info("addSnat : Handle non NAPT switch {} for router {}", dpnId, routers.getRouterName());
             addSnatCommonEntriesForNonNaptSwitch(confTx, routers, primarySwitchId, dpnId);
             addSnatSpecificEntriesForNonNaptSwitch(confTx, routers, dpnId);
         } else {
-            LOG.info("handleSnat : Handle NAPT switch {} for router {}", dpnId, routers.getRouterName());
+            LOG.info("addSnat : Handle NAPT switch {} for router {}", dpnId, routers.getRouterName());
             addSnatCommonEntriesForNaptSwitch(confTx, routers, dpnId);
             addSnatSpecificEntriesForNaptSwitch(confTx, routers, dpnId);
         }
@@ -211,11 +203,11 @@ public abstract class AbstractSnatService implements SnatServiceListener {
 
         // Handle non NAPT switches and NAPT switches separately
         if (!dpnId.equals(primarySwitchId)) {
-            LOG.info("handleSnat : Handle non NAPT switch {} for router {}", dpnId, routers.getRouterName());
+            LOG.info("removeSnat : Handle non NAPT switch {} for router {}", dpnId, routers.getRouterName());
             removeSnatCommonEntriesForNonNaptSwitch(confTx, routers, dpnId);
             removeSnatSpecificEntriesForNonNaptSwitch(confTx, routers, dpnId);
         } else {
-            LOG.info("handleSnat : Handle NAPT switch {} for router {}", dpnId, routers.getRouterName());
+            LOG.info("removeSnat : Handle NAPT switch {} for router {}", dpnId, routers.getRouterName());
             removeSnatCommonEntriesForNaptSwitch(confTx, routers, dpnId);
             removeSnatSpecificEntriesForNaptSwitch(confTx, routers, dpnId);
 
@@ -223,11 +215,115 @@ public abstract class AbstractSnatService implements SnatServiceListener {
         return true;
     }
 
+    @Override
+    public boolean addCentralizedRouterAllSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
+            BigInteger primarySwitchId) {
+        LOG.info("addCentralizedRouterAllSwitch : Handle Snat in all switches for router {}",
+                routers.getRouterName());
+        String routerName = routers.getRouterName();
+        List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
+        addCentralizedRouter(confTx, routers, primarySwitchId, primarySwitchId);
+        for (BigInteger dpnId : switches) {
+            if (primarySwitchId != dpnId) {
+                addCentralizedRouter(confTx, routers, primarySwitchId, dpnId);
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public boolean removeCentralizedRouterAllSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
+            BigInteger primarySwitchId)  throws ExecutionException, InterruptedException {
+        LOG.info("removeCentralizedRouterAllSwitch : Handle Snat in all switches for router {}",
+                routers.getRouterName());
+        boolean isLastRouterDelete = false;
+        isLastRouterDelete = NatUtil.isLastExternalRouter(routers.getNetworkId()
+                .getValue(), routers.getRouterName(), natDataUtil);
+        LOG.info("removeCentralizedRouterAllSwitch : action is delete for router {} and isLastRouterDelete is {}",
+                routers.getRouterName(), isLastRouterDelete);
+        removeCentralizedRouter(confTx, routers, primarySwitchId, primarySwitchId);
+        String routerName = routers.getRouterName();
+        List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
+        for (BigInteger dpnId : switches) {
+            if (primarySwitchId != dpnId) {
+                removeCentralizedRouter(confTx, routers, primarySwitchId, dpnId);
+            }
+        }
+        if (isLastRouterDelete) {
+            removeLearntIpPorts(routers);
+            removeMipAdjacencies(routers);
+        }
+        return true;
+    }
+
+    @Override
+    public boolean addCentralizedRouter(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
+            BigInteger primarySwitchId, BigInteger dpnId) {
+        if (!dpnId.equals(primarySwitchId)) {
+            LOG.info("addCentralizedRouter : Handle non NAPT switch {} for router {}",
+                    dpnId, routers.getRouterName());
+            addCommonEntriesForNonNaptSwitch(confTx, routers, primarySwitchId, dpnId);
+        } else {
+            LOG.info("addCentralizedRouter : Handle NAPT switch {} for router {}", dpnId, routers.getRouterName());
+            addCommonEntriesForNaptSwitch(confTx, routers, dpnId);
+        }
+        return true;
+    }
+
+    @Override
+    public boolean removeCentralizedRouter(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
+            BigInteger primarySwitchId, BigInteger dpnId) throws ExecutionException, InterruptedException {
+        if (!dpnId.equals(primarySwitchId)) {
+            LOG.info("removeCentralizedRouter : Handle non NAPT switch {} for router {}",
+                    dpnId, routers.getRouterName());
+            removeCommonEntriesForNonNaptSwitch(confTx, routers, primarySwitchId, dpnId);
+        } else {
+            LOG.info("removeCentralizedRouter : Handle NAPT switch {} for router {}", dpnId, routers.getRouterName());
+            removeCommonEntriesForNaptSwitch(confTx, routers, dpnId);
+        }
+        return true;
+    }
+
+    protected void addCommonEntriesForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
+            BigInteger dpnId) {
+        String routerName = routers.getRouterName();
+        Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+        addDefaultFibRouteForSNAT(confTx, dpnId, routerId);
+        int elanId = NatUtil.getElanInstanceByName(routers.getNetworkId().getValue(), getDataBroker())
+                .getElanTag().intValue();
+        for (ExternalIps externalIp : routers.getExternalIps()) {
+            if (!NWUtil.isIpv4Address(externalIp.getIpAddress())) {
+                // In this class we handle only IPv4 use-cases.
+                continue;
+            }
+            //The logic now handle only one external IP per router, others if present will be ignored.
+            long extSubnetId = NatUtil.getExternalSubnetVpnId(dataBroker, externalIp.getSubnetId());
+            addInboundTerminatingServiceTblEntry(confTx, dpnId, routerId, extSubnetId);
+            addTerminatingServiceTblEntry(confTx, dpnId, routerId, elanId);
+            break;
+        }
+    }
+
+    protected void removeCommonEntriesForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
+            BigInteger dpnId) throws ExecutionException, InterruptedException {
+        String routerName = routers.getRouterName();
+        Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+        removeDefaultFibRouteForSNAT(confTx, dpnId, routerId);
+        for (ExternalIps externalIp : routers.getExternalIps()) {
+            if (!NWUtil.isIpv4Address(externalIp.getIpAddress())) {
+                // In this class we handle only IPv4 use-cases.
+                continue;
+            }
+            removeInboundTerminatingServiceTblEntry(confTx, dpnId, routerId);
+            removeTerminatingServiceTblEntry(confTx, dpnId, routerId);
+            break;
+        }
+    }
+
     protected void addSnatCommonEntriesForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
         BigInteger dpnId) {
         String routerName = routers.getRouterName();
         Long routerId = NatUtil.getVpnId(dataBroker, routerName);
-        addDefaultFibRouteForSNAT(confTx, dpnId, routerId);
         String externalGwMac = routers.getExtGwMacAddress();
         for (ExternalIps externalIp : routers.getExternalIps()) {
             if (!NWUtil.isIpv4Address(externalIp.getIpAddress())) {
@@ -238,7 +334,6 @@ public abstract class AbstractSnatService implements SnatServiceListener {
             long extSubnetId = NatUtil.getExternalSubnetVpnId(dataBroker, externalIp.getSubnetId());
             addInboundFibEntry(confTx, dpnId, externalIp.getIpAddress(), routerId, extSubnetId,
                 routers.getNetworkId().getValue(), externalIp.getSubnetId().getValue(), externalGwMac);
-            addInboundTerminatingServiceTblEntry(confTx, dpnId, routerId, extSubnetId);
             break;
         }
     }
@@ -247,7 +342,6 @@ public abstract class AbstractSnatService implements SnatServiceListener {
             Routers routers, BigInteger dpnId) throws ExecutionException, InterruptedException {
         String routerName = routers.getRouterName();
         Long routerId = NatUtil.getVpnId(confTx, routerName);
-        removeDefaultFibRouteForSNAT(confTx, dpnId, routerId);
         for (ExternalIps externalIp : routers.getExternalIps()) {
             if (!NWUtil.isIpv4Address(externalIp.getIpAddress())) {
                 // In this class we handle only IPv4 use-cases.
@@ -256,25 +350,35 @@ public abstract class AbstractSnatService implements SnatServiceListener {
             //The logic now handle only one external IP per router, others if present will be ignored.
             removeInboundFibEntry(confTx, dpnId, externalIp.getIpAddress(), routerId,
                 externalIp.getSubnetId().getValue());
-            removeInboundTerminatingServiceTblEntry(confTx, dpnId, routerId);
             break;
         }
     }
 
-    protected void addSnatCommonEntriesForNonNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
-        Routers routers, BigInteger primarySwitchId, BigInteger dpnId) {
+
+    protected void addCommonEntriesForNonNaptSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
+            BigInteger primarySwitchId, BigInteger dpnId) {
         String routerName = routers.getRouterName();
         Long routerId = NatUtil.getVpnId(dataBroker, routerName);
-        addDefaultFibRouteForSNAT(confTx, dpnId, routerId);
         addSnatMissEntry(confTx, dpnId, routerId, routerName, primarySwitchId);
+        addDefaultFibRouteForSNAT(confTx, dpnId, routerId);
     }
 
-    protected void removeSnatCommonEntriesForNonNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
-            Routers routers, BigInteger dpnId) throws ExecutionException, InterruptedException {
+    protected void removeCommonEntriesForNonNaptSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
+            BigInteger primarySwitchId, BigInteger dpnId) throws ExecutionException, InterruptedException {
         String routerName = routers.getRouterName();
         Long routerId = NatUtil.getVpnId(dataBroker, routerName);
-        removeDefaultFibRouteForSNAT(confTx, dpnId, routerId);
         removeSnatMissEntry(confTx, dpnId, routerId, routerName);
+        removeDefaultFibRouteForSNAT(confTx, dpnId, routerId);
+    }
+
+    protected void addSnatCommonEntriesForNonNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
+        Routers routers, BigInteger primarySwitchId, BigInteger dpnId) {
+        /* Nothing to do here*/
+    }
+
+    protected void removeSnatCommonEntriesForNonNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
+            Routers routers, BigInteger dpnId) throws ExecutionException, InterruptedException {
+        /* Nothing to do here*/
     }
 
     protected abstract void addSnatSpecificEntriesForNaptSwitch(TypedReadWriteTransaction<Configuration> confTx,
@@ -333,6 +437,36 @@ public abstract class AbstractSnatService implements SnatServiceListener {
         NatUtil.deletePrefixToInterface(dataBroker, NatUtil.getVpnId(dataBroker, subNetId), ipPrefix);
     }
 
+
+    protected void addTerminatingServiceTblEntry(TypedWriteTransaction<Configuration> confTx, BigInteger dpnId,
+        Long routerId, int elanId) {
+        LOG.info("addTerminatingServiceTblEntry : creating entry for Terminating Service Table "
+                + "for switch {}, routerId {}", dpnId, routerId);
+        List<MatchInfo> matches = new ArrayList<>();
+        matches.add(MatchEthernetType.IPV4);
+        matches.add(new MatchTunnelId(BigInteger.valueOf(routerId)));
+
+        List<ActionInfo> actionsInfos = new ArrayList<>();
+        ActionNxLoadMetadata actionLoadMeta = new ActionNxLoadMetadata(MetaDataUtil
+                .getVpnIdMetadata(routerId), LOAD_START, LOAD_END);
+        actionsInfos.add(actionLoadMeta);
+        actionsInfos.add(new ActionNxResubmit(NwConstants.PSNAT_TABLE));
+        List<InstructionInfo> instructions = new ArrayList<>();
+        instructions.add(new InstructionApplyActions(actionsInfos));
+        String flowRef = getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId);
+        addFlow(confTx, dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef, NatConstants.DEFAULT_TS_FLOW_PRIORITY,
+            flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
+    }
+
+    protected void removeTerminatingServiceTblEntry(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
+            Long routerId) throws ExecutionException, InterruptedException {
+        LOG.info("removeTerminatingServiceTblEntry : creating entry for Terminating Service Table "
+            + "for switch {}, routerId {}", dpnId, routerId);
+
+        String flowRef = getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId);
+        removeFlow(confTx, dpnId,  NwConstants.INTERNAL_TUNNEL_TABLE, flowRef);
+    }
+
     protected void addSnatMissEntry(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
         Long routerId, String routerName, BigInteger primarySwitchId)  {
         LOG.debug("installSnatMissEntry : Installing SNAT miss entry in switch {}", dpnId);
@@ -423,7 +557,7 @@ public abstract class AbstractSnatService implements SnatServiceListener {
         ActionNxLoadMetadata actionLoadMeta = new ActionNxLoadMetadata(MetaDataUtil
                 .getVpnIdMetadata(extSubnetId), LOAD_START, LOAD_END);
         actionsInfos.add(actionLoadMeta);
-        actionsInfos.add(new ActionNxResubmit(NwConstants.INBOUND_NAPT_TABLE));
+        actionsInfos.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
         List<InstructionInfo> instructions = new ArrayList<>();
         instructions.add(new InstructionApplyActions(actionsInfos));
         String flowRef = getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId.longValue()) + "INBOUND";
index 3a66f86828c72a73b07686df3819f9b011233712..0c933f6ece224f200c98f5bef47ea695ee0710a1 100644 (file)
@@ -38,7 +38,6 @@ import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
 import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Destination;
 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
-import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
 import org.opendaylight.genius.mdsalutil.nxmatches.NxMatchCtState;
 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
 import org.opendaylight.netvirt.natservice.ha.NatDataUtil;
@@ -93,7 +92,6 @@ public abstract class ConntrackBasedSnatService extends AbstractSnatService {
         /* Install Outbound NAT entries */
 
         addSnatMissEntryForPrimrySwch(confTx, dpnId, routerId, elanId);
-        addTerminatingServiceTblEntry(confTx, dpnId, routerId, elanId);
 
         String extGwMacAddress = NatUtil.getExtGwMacAddFromRouterName(confTx, routerName);
         addOutboundTblTrackEntry(confTx, dpnId, routerId, extGwMacAddress);
@@ -138,7 +136,6 @@ public abstract class ConntrackBasedSnatService extends AbstractSnatService {
         /* Remove Outbound NAT entries */
 
         removeSnatMissEntryForPrimrySwch(confTx, dpnId, routerId);
-        removeTerminatingServiceTblEntry(confTx, dpnId, routerId);
 
         removeOutboundTblTrackEntry(confTx, dpnId, routerId);
         for (ExternalIps externalIp : routers.getExternalIps()) {
@@ -209,40 +206,6 @@ public abstract class ConntrackBasedSnatService extends AbstractSnatService {
         removeFlow(confTx, dpnId, NwConstants.PSNAT_TABLE, flowRef);
     }
 
-    protected void addTerminatingServiceTblEntry(TypedWriteTransaction<Configuration> confTx, BigInteger dpnId,
-        Long routerId, int elanId) {
-        LOG.info("installTerminatingServiceTblEntry : creating entry for Terminating Service Table "
-                + "for switch {}, routerId {}", dpnId, routerId);
-        List<MatchInfo> matches = new ArrayList<>();
-        matches.add(MatchEthernetType.IPV4);
-        matches.add(new MatchTunnelId(BigInteger.valueOf(routerId)));
-
-        List<ActionInfo> actionsInfos = new ArrayList<>();
-        List<NxCtAction> ctActionsList = new ArrayList<>();
-        NxCtAction nxCtAction = new ActionNxConntrack.NxNat(0, 0, 0,null, null,0, 0);
-        ctActionsList.add(nxCtAction);
-        ActionNxConntrack actionNxConntrack = new ActionNxConntrack(0, 0, elanId, NwConstants
-                .OUTBOUND_NAPT_TABLE,ctActionsList);
-        ActionNxLoadMetadata actionLoadMeta = new ActionNxLoadMetadata(MetaDataUtil
-                .getVpnIdMetadata(routerId), LOAD_START, LOAD_END);
-        actionsInfos.add(actionLoadMeta);
-        actionsInfos.add(actionNxConntrack);
-        List<InstructionInfo> instructions = new ArrayList<>();
-        instructions.add(new InstructionApplyActions(actionsInfos));
-        String flowRef = getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId);
-        addFlow(confTx, dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef, NatConstants.DEFAULT_TS_FLOW_PRIORITY,
-            flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
-    }
-
-    protected void removeTerminatingServiceTblEntry(TypedReadWriteTransaction<Configuration> confTx, BigInteger dpnId,
-            Long routerId) throws ExecutionException, InterruptedException {
-        LOG.info("installTerminatingServiceTblEntry : creating entry for Terminating Service Table "
-            + "for switch {}, routerId {}", dpnId, routerId);
-
-        String flowRef = getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId);
-        removeFlow(confTx, dpnId,  NwConstants.INTERNAL_TUNNEL_TABLE, flowRef);
-    }
-
     protected void addOutboundTblTrackEntry(TypedWriteTransaction<Configuration> confTx, BigInteger dpnId,
         Long routerId, String extGwMacAddress) {
         LOG.info("createOutboundTblTrackEntry : called for switch {}, routerId {}", dpnId, routerId);
index 6420bddd8bd6181f093848a60385068263566d9e..f9e0ec2a40c2a77fc0962616b23e4d9d57d65cb8 100644 (file)
@@ -50,6 +50,7 @@ import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Source;
 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
+import org.opendaylight.netvirt.natservice.api.CentralizedSwitchScheduler;
 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.Uuid;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
@@ -79,13 +80,15 @@ public class FloatingIPListener extends AsyncDataTreeChangeListenerBase<Internal
     private final FloatingIPHandler floatingIPHandler;
     private final SNATDefaultRouteProgrammer defaultRouteProgrammer;
     private final JobCoordinator coordinator;
+    private final CentralizedSwitchScheduler centralizedSwitchScheduler;
 
     @Inject
     public FloatingIPListener(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
                               final OdlInterfaceRpcService interfaceManager,
                               final FloatingIPHandler floatingIPHandler,
                               final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer,
-                              final JobCoordinator coordinator) {
+                              final JobCoordinator coordinator,
+                              final CentralizedSwitchScheduler centralizedSwitchScheduler) {
         super(InternalToExternalPortMap.class, FloatingIPListener.class);
         this.dataBroker = dataBroker;
         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
@@ -94,6 +97,7 @@ public class FloatingIPListener extends AsyncDataTreeChangeListenerBase<Internal
         this.floatingIPHandler = floatingIPHandler;
         this.defaultRouteProgrammer = snatDefaultRouteProgrammer;
         this.coordinator = coordinator;
+        this.centralizedSwitchScheduler = centralizedSwitchScheduler;
     }
 
     @Override
@@ -425,6 +429,39 @@ public class FloatingIPListener extends AsyncDataTreeChangeListenerBase<Internal
         return getInetAddress(mapping.getInternalIp()) != null && getInetAddress(mapping.getExternalIp()) != null;
     }
 
+    private BigInteger getAssociatedDpnWithExternalInterface(final String routerName, Uuid extNwId, BigInteger dpnId,
+            String interfaceName) {
+        //Get the DPN on which this interface resides
+        if (dpnId == null) {
+            dpnId = NatUtil.getDpnForInterface(interfaceManager, interfaceName);
+        }
+        BigInteger updatedDpnId = dpnId;
+        if (updatedDpnId.equals(BigInteger.ZERO)) {
+            LOG.debug("getAssociatedDpnWithExternalInterface : The interface {} is not associated with any dpn",
+                    interfaceName);
+            return updatedDpnId;
+        }
+        ProviderTypes providerType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, extNwId);
+        if (providerType == null) {
+            LOG.warn("getAssociatedDpnWithExternalInterface : Provider Network Type for router {} and"
+                    + " externalNetwork {} is missing.", routerName, extNwId);
+            return updatedDpnId;
+        }
+
+        // For FLAT and VLAN provider networks, we have to ensure that dpn hosting the VM has connectivity
+        // to External Network via provider_mappings. In case the dpn does not have the provider mappings,
+        // traffic from the VM has to be forwarded to the NAPT Switch (which is scheduled based on the provider
+        // mappings) and then sent out on the external Network.
+        if (providerType == ProviderTypes.FLAT || providerType == ProviderTypes.VLAN) {
+            String providerNet = NatUtil.getElanInstancePhysicalNetwok(extNwId.getValue(), dataBroker);
+            boolean isDpnConnected = centralizedSwitchScheduler.isSwitchConnectedToExternal(updatedDpnId, providerNet);
+            if (!isDpnConnected) {
+                updatedDpnId = centralizedSwitchScheduler.getCentralizedSwitch(routerName);
+            }
+        }
+        return updatedDpnId;
+    }
+
     void createNATFlowEntries(String interfaceName, final InternalToExternalPortMap mapping,
                               final InstanceIdentifier<RouterPorts> portIid, final String routerName, BigInteger dpnId,
             TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
@@ -433,14 +470,19 @@ public class FloatingIPListener extends AsyncDataTreeChangeListenerBase<Internal
             return;
         }
 
-        //Get the DPN on which this interface resides
-        if (dpnId == null) {
-            dpnId = NatUtil.getDpnForInterface(interfaceManager, interfaceName);
+        Uuid extNwId = getExtNetworkId(portIid, LogicalDatastoreType.CONFIGURATION);
+        if (extNwId == null) {
+            LOG.error("createNATFlowEntries : External network associated with interface {} could not be retrieved",
+                    interfaceName);
+            return;
         }
 
-        if (dpnId.equals(BigInteger.ZERO)) {
+        // For Overlay Networks, get the DPN on which this interface resides.
+        // For FLAT/VLAN Networks, get the DPN with provider_mappings for external network.
+        dpnId = getAssociatedDpnWithExternalInterface(routerName, extNwId, dpnId, interfaceName);
+        if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
             LOG.warn("createNATFlowEntries : No DPN for interface {}. NAT flow entries for ip mapping {} will "
-                + "not be installed", interfaceName, mapping);
+                    + "not be installed", interfaceName, mapping);
             return;
         }
 
@@ -464,12 +506,6 @@ public class FloatingIPListener extends AsyncDataTreeChangeListenerBase<Internal
             //routerId = associatedVpnId;
         }
 
-        Uuid extNwId = getExtNetworkId(portIid, LogicalDatastoreType.CONFIGURATION);
-        if (extNwId == null) {
-            LOG.error("createNATFlowEntries : External network associated with interface {} could not be retrieved",
-                interfaceName);
-            return;
-        }
         long vpnId = getVpnId(extNwId, mapping.getExternalId());
         if (vpnId < 0) {
             LOG.error("createNATFlowEntries : No VPN associated with Ext nw {}. Unable to create SNAT table entry "
@@ -571,12 +607,19 @@ public class FloatingIPListener extends AsyncDataTreeChangeListenerBase<Internal
                               InstanceIdentifier<RouterPorts> portIid, final String routerName, BigInteger dpnId,
                               TypedReadWriteTransaction<Configuration> removeFlowInvTx)
             throws ExecutionException, InterruptedException {
-        String internalIp = mapping.getInternalIp();
-        String externalIp = mapping.getExternalIp();
-        //Get the DPN on which this interface resides
+        Uuid extNwId = getExtNetworkId(portIid, LogicalDatastoreType.OPERATIONAL);
+        if (extNwId == null) {
+            LOG.error("removeNATFlowEntries : External network associated with interface {} could not be retrieved",
+                    interfaceName);
+            return;
+        }
+
+        // For Overlay Networks, get the DPN on which this interface resides.
+        // For FLAT/VLAN Networks, get the DPN with provider_mappings for external network.
         if (dpnId == null) {
-            dpnId = NatUtil.getDpnForInterface(interfaceManager, interfaceName);
-            if (dpnId.equals(BigInteger.ZERO)) {
+            dpnId = getAssociatedDpnWithExternalInterface(routerName, extNwId,
+                    NatUtil.getDpnForInterface(interfaceManager, interfaceName), interfaceName);
+            if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
                 LOG.warn("removeNATFlowEntries: Abort processing Floating ip configuration. No DPN for port: {}",
                         interfaceName);
                 return;
@@ -590,15 +633,12 @@ public class FloatingIPListener extends AsyncDataTreeChangeListenerBase<Internal
             return;
         }
 
+        String internalIp = mapping.getInternalIp();
+        String externalIp = mapping.getExternalIp();
+
         //Delete the DNAT and SNAT table entries
         removeDNATTblEntry(dpnId, internalIp, externalIp, routerId, removeFlowInvTx);
 
-        Uuid extNwId = getExtNetworkId(portIid, LogicalDatastoreType.OPERATIONAL);
-        if (extNwId == null) {
-            LOG.error("removeNATFlowEntries : External network associated with interface {} could not be retrieved",
-                interfaceName);
-            return;
-        }
         long vpnId = getVpnId(extNwId, mapping.getExternalId());
         if (vpnId < 0) {
             LOG.error("removeNATFlowEntries : No VPN associated with ext nw {}. Unable to delete SNAT table "
index 0e7e6a65b1d80907e4a9bebe009107c7cb935261..e7db4423be620ea615788ca43c1ca9e0646d0c27 100644 (file)
@@ -406,9 +406,18 @@ public class NaptSwitchHA {
         naptSwitch = naptSwitchSelector.selectNewNAPTSwitch(routerName);
         if (natMode == NatMode.Conntrack) {
             Routers extRouters = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
-            natServiceManager.notify(confTx, extRouters, dpnId, dpnId, SnatServiceManager.Action.SNAT_ALL_SWITCH_DISBL);
-            natServiceManager.notify(confTx, extRouters, naptSwitch, naptSwitch,
-                    SnatServiceManager.Action.SNAT_ALL_SWITCH_ENBL);
+            natServiceManager.notify(confTx, extRouters, null, dpnId, dpnId,
+                    SnatServiceManager.Action.CNT_ROUTER_ALL_SWITCH_DISBL);
+            if (extRouters.isEnableSnat()) {
+                natServiceManager.notify(confTx, extRouters, null, dpnId, dpnId,
+                        SnatServiceManager.Action.SNAT_ALL_SWITCH_DISBL);
+            }
+            natServiceManager.notify(confTx, extRouters, null, naptSwitch, naptSwitch,
+                    SnatServiceManager.Action.CNT_ROUTER_ALL_SWITCH_ENBL);
+            if (extRouters.isEnableSnat()) {
+                natServiceManager.notify(confTx, extRouters, null, naptSwitch, naptSwitch,
+                        SnatServiceManager.Action.SNAT_ALL_SWITCH_ENBL);
+            }
         } else {
             if (naptSwitch.equals(BigInteger.ZERO)) {
                 LOG.warn("isNaptSwitchDown : No napt switch is elected since all the switches for router {}"
index 915eaa095059700f7fdbec7f461188da53b226ae..455ecdd0ebeec481c3fa14e1f7e03158b356f10c 100644 (file)
@@ -529,8 +529,13 @@ public class NatTunnelInterfaceStateListener
             return;
         }
         if (natMode == NatMode.Conntrack) {
-            natServiceManager.notify(writeFlowInvTx, routerData.get(), naptId, srcDpnId,
-                    SnatServiceManager.Action.SNAT_ROUTER_ENBL);
+            Routers extRouter = routerData.get();
+            natServiceManager.notify(writeFlowInvTx, extRouter, null, naptId, srcDpnId,
+                    SnatServiceManager.Action.CNT_ROUTER_ALL_SWITCH_ENBL);
+            if (extRouter.isEnableSnat()) {
+                natServiceManager.notify(writeFlowInvTx, extRouter, null, naptId, srcDpnId,
+                        SnatServiceManager.Action.SNAT_ROUTER_ENBL);
+            }
         } else {
             Uuid bgpVpnUuId = NatUtil.getVpnForRouter(dataBroker, routerName);
             //Check if the DPN having the router is the NAPT switch
@@ -971,8 +976,13 @@ public class NatTunnelInterfaceStateListener
             return;
         }
         if (natMode == NatMode.Conntrack) {
-            natServiceManager.notify(confTx, routerData.get(), naptId, dpnId,
-                SnatServiceManager.Action.SNAT_ROUTER_DISBL);
+            Routers extRouter = routerData.get();
+            natServiceManager.notify(confTx, extRouter, null, naptId, dpnId,
+                    SnatServiceManager.Action.CNT_ROUTER_DISBL);
+            if (extRouter.isEnableSnat()) {
+                natServiceManager.notify(confTx,extRouter, null, naptId, dpnId,
+                        SnatServiceManager.Action.SNAT_ROUTER_DISBL);
+            }
         } else {
 
 
index fb544a028fbdd69f2972482cdc0d1a6a752cb38e..b527cfef0da72499993bd827b3a792a5cddd61c0 100644 (file)
@@ -13,6 +13,9 @@ import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
 
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
+import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
+
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import java.math.BigInteger;
 import java.net.InetAddress;
@@ -98,6 +101,9 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.BridgeRefInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntryKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceOutput;
@@ -118,7 +124,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanDpnInterfaces;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
@@ -243,6 +248,10 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev14
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.add.group.input.buckets.bucket.action.action.NxActionResubmitRpcAddGroupCase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionRegLoadNodesNodeTableFlowApplyActionsCase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.load.grouping.NxRegLoad;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.OpenvswitchOtherConfigs;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
@@ -253,6 +262,9 @@ public final class NatUtil {
 
     private static String OF_URI_SEPARATOR = ":";
     private static final Logger LOG = LoggerFactory.getLogger(NatUtil.class);
+    private static final String OTHER_CONFIG_PARAMETERS_DELIMITER = ",";
+    private static final String OTHER_CONFIG_KEY_VALUE_DELIMITER = ":";
+    private static final String PROVIDER_MAPPINGS = "provider_mappings";
 
     private NatUtil() { }
 
@@ -2380,7 +2392,8 @@ public final class NatUtil {
     }
 
     public static InstanceIdentifier<Group> getGroupInstanceId(BigInteger dpnId, long groupId) {
-        return InstanceIdentifier.builder(Nodes.class).child(Node.class, new NodeKey(new NodeId("openflow:" + dpnId)))
+        return InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight
+                .inventory.rev130819.nodes.Node.class, new NodeKey(new NodeId("openflow:" + dpnId)))
                 .augmentation(FlowCapableNode.class).child(Group.class, new GroupKey(new GroupId(groupId))).build();
     }
 
@@ -2405,9 +2418,10 @@ public final class NatUtil {
     public static boolean getSwitchStatus(DataBroker broker, BigInteger switchId) {
         NodeId nodeId = new NodeId("openflow:" + switchId);
         LOG.debug("getSwitchStatus : Querying switch with dpnId {} is up/down", nodeId);
-        InstanceIdentifier<Node> nodeInstanceId = InstanceIdentifier.builder(Nodes.class)
-            .child(Node.class, new NodeKey(nodeId)).build();
-        Optional<Node> nodeOptional =
+        InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node> nodeInstanceId
+            = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight
+                    .inventory.rev130819.nodes.Node.class, new NodeKey(nodeId)).build();
+        Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node> nodeOptional =
                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
                         LogicalDatastoreType.OPERATIONAL, nodeInstanceId);
         if (nodeOptional.isPresent()) {
@@ -2428,4 +2442,100 @@ public final class NatUtil {
         }
         return false;
     }
+
+    public static String getElanInstancePhysicalNetwok(String elanInstanceName, DataBroker broker) {
+
+        ElanInstance elanInstance =  getElanInstanceByName(elanInstanceName, broker);
+        if (null != elanInstance) {
+            return elanInstance.getPhysicalNetworkName();
+        }
+        return null;
+
+    }
+
+    public static Map<String, String> getOpenvswitchOtherConfigMap(BigInteger dpnId, DataBroker dataBroker) {
+        String otherConfigVal = getProviderMappings(dpnId, dataBroker);
+        return getMultiValueMap(otherConfigVal);
+    }
+
+    public static Map<String, String> getMultiValueMap(String multiKeyValueStr) {
+        if (Strings.isNullOrEmpty(multiKeyValueStr)) {
+            return Collections.emptyMap();
+        }
+
+        Map<String, String> valueMap = new HashMap<>();
+        Splitter splitter = Splitter.on(OTHER_CONFIG_PARAMETERS_DELIMITER);
+        for (String keyValue : splitter.split(multiKeyValueStr)) {
+            String[] split = keyValue.split(OTHER_CONFIG_KEY_VALUE_DELIMITER, 2);
+            if (split.length == 2) {
+                valueMap.put(split[0], split[1]);
+            }
+        }
+
+        return valueMap;
+    }
+
+    public static Optional<Node> getBridgeRefInfo(BigInteger dpnId, DataBroker dataBroker) {
+        InstanceIdentifier<BridgeRefEntry> bridgeRefInfoPath = InstanceIdentifier.create(BridgeRefInfo.class)
+                .child(BridgeRefEntry.class, new BridgeRefEntryKey(dpnId));
+
+        Optional<BridgeRefEntry> bridgeRefEntry =
+                SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
+                        LogicalDatastoreType.OPERATIONAL, bridgeRefInfoPath);
+        if (!bridgeRefEntry.isPresent()) {
+            LOG.info("getBridgeRefInfo : bridgeRefEntry is not present for {}", dpnId);
+            return Optional.absent();
+        }
+
+        InstanceIdentifier<Node> nodeId =
+                bridgeRefEntry.get().getBridgeReference().getValue().firstIdentifierOf(Node.class);
+
+        return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
+                LogicalDatastoreType.OPERATIONAL, nodeId);
+    }
+
+    public static String getProviderMappings(BigInteger dpId, DataBroker dataBroker) {
+        return getBridgeRefInfo(dpId, dataBroker).toJavaUtil().map(node -> getOpenvswitchOtherConfigs(node,
+                PROVIDER_MAPPINGS, dataBroker)).orElse(null);
+    }
+
+    public static String getOpenvswitchOtherConfigs(Node node, String key, DataBroker dataBroker) {
+        OvsdbNodeAugmentation ovsdbNode = node.augmentation(OvsdbNodeAugmentation.class);
+        if (ovsdbNode == null) {
+            Optional<Node> nodeFromReadOvsdbNode = readOvsdbNode(node, dataBroker);
+            if (nodeFromReadOvsdbNode.isPresent()) {
+                ovsdbNode = nodeFromReadOvsdbNode.get().augmentation(OvsdbNodeAugmentation.class);
+            }
+        }
+
+        if (ovsdbNode != null && ovsdbNode.getOpenvswitchOtherConfigs() != null) {
+            for (OpenvswitchOtherConfigs openvswitchOtherConfigs : ovsdbNode.getOpenvswitchOtherConfigs()) {
+                if (openvswitchOtherConfigs.getOtherConfigKey().equals(key)) {
+                    return openvswitchOtherConfigs.getOtherConfigValue();
+                }
+            }
+        }
+        LOG.info("getOpenvswitchOtherConfigs : OtherConfigs is not present for ovsdbNode {}", node.getNodeId());
+        return null;
+    }
+
+    @Nonnull
+    public static Optional<Node> readOvsdbNode(Node bridgeNode, DataBroker dataBroker) {
+        OvsdbBridgeAugmentation bridgeAugmentation = extractBridgeAugmentation(bridgeNode);
+        if (bridgeAugmentation != null) {
+            InstanceIdentifier<Node> ovsdbNodeIid =
+                    (InstanceIdentifier<Node>) bridgeAugmentation.getManagedBy().getValue();
+            return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
+                    LogicalDatastoreType.OPERATIONAL, ovsdbNodeIid);
+        }
+        return Optional.absent();
+
+    }
+
+    public static OvsdbBridgeAugmentation extractBridgeAugmentation(Node node) {
+        if (node == null) {
+            return null;
+        }
+        return node.augmentation(OvsdbBridgeAugmentation.class);
+    }
 }
index a79ec096c82c342f81a63b4ba441550580e275f3..11401b3efda7a3018ad796a4cb85fc820a07b6b5 100644 (file)
@@ -143,8 +143,14 @@ public class RouterDpnChangeListener
                         return;
                     }
                     ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
-                        confTx -> natServiceManager.notify(confTx, router, naptSwitch, dpnId,
-                            SnatServiceManager.Action.SNAT_ROUTER_ENBL)), LOG, "Error notifying NAT service manager");
+                        confTx -> {
+                            natServiceManager.notify(confTx, router, null, naptSwitch, dpnId,
+                                    SnatServiceManager.Action.CNT_ROUTER_ENBL);
+                            if (router.isEnableSnat()) {
+                                natServiceManager.notify(confTx, router, null, naptSwitch, naptSwitch,
+                                        SnatServiceManager.Action.SNAT_ROUTER_ENBL);
+                            }
+                        }), LOG, "Error notifying NAT service manager");
                 } else {
                     Long routerId = NatUtil.getVpnId(dataBroker, routerUuid);
                     if (routerId == NatConstants.INVALID_ID) {
@@ -244,8 +250,14 @@ public class RouterDpnChangeListener
                         return;
                     }
                     ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
-                        confTx -> natServiceManager.notify(confTx, router, naptSwitch, dpnId,
-                            SnatServiceManager.Action.SNAT_ROUTER_DISBL)), LOG, "Error notifying NAT service manager");
+                        confTx -> {
+                            natServiceManager.notify(confTx, router, null, naptSwitch, dpnId,
+                                    SnatServiceManager.Action.CNT_ROUTER_DISBL);
+                            if (router.isEnableSnat()) {
+                                natServiceManager.notify(confTx, router, null, naptSwitch, naptSwitch,
+                                        SnatServiceManager.Action.SNAT_ROUTER_DISBL);
+                            }
+                        }), LOG, "Error notifying NAT service manager");
                 } else {
                     coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + routerUuid, () -> {
                         LOG.debug("remove : Router {} is associated with ext nw {}", routerUuid, networkId);
index e2f625dd25aa62a6bcce01f26680790592883c3b..aefb091ccf15ab8cda9248dbd01967f4a9c007e1 100644 (file)
@@ -7,8 +7,6 @@
  */
 package org.opendaylight.netvirt.natservice.internal;
 
-import java.util.List;
-import java.util.Objects;
 import javax.annotation.PostConstruct;
 import javax.inject.Inject;
 import javax.inject.Singleton;
@@ -24,7 +22,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.r
 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.ExtRouters;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.routers.ExternalIps;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -94,12 +91,8 @@ public class SnatExternalRoutersListener extends AsyncDataTreeChangeListenerBase
             // Router associated to BGPVPN, ignoring it.
             return;
         }
-
-        List<ExternalIps> externalIps = routers.getExternalIps();
         // Allocate Primary NAPTSwitch for this router
-        if (routers.isEnableSnat() && externalIps != null && !externalIps.isEmpty()) {
-            centralizedSwitchScheduler.scheduleCentralizedSwitch(routers);
-        }
+        centralizedSwitchScheduler.scheduleCentralizedSwitch(routers);
     }
 
     @Override
@@ -117,26 +110,7 @@ public class SnatExternalRoutersListener extends AsyncDataTreeChangeListenerBase
         LOG.info("update :called for router {} with originalSNATStatus {} and updatedSNATStatus {}",
                 routerName, originalSNATEnabled, updatedSNATEnabled);
         if (!upgradeState.isUpgradeInProgress()) {
-            if (originalSNATEnabled != updatedSNATEnabled) {
-                if (originalSNATEnabled) {
-                    //SNAT is disabled for the router
-                    LOG.debug("update : SNAT disabled on router {}, release NAPT Switch", routerName);
-                    centralizedSwitchScheduler.releaseCentralizedSwitch(update);
-                } else {
-                    LOG.debug("update : SNAT enabled on router {}, schedule NAPT Switch", routerName);
-                    centralizedSwitchScheduler.scheduleCentralizedSwitch(update);
-                }
-            } else if (updatedSNATEnabled) {
-                centralizedSwitchScheduler.updateCentralizedSwitch(original, update);
-            }
-
-            List<ExternalIps> originalExternalIps = original.getExternalIps();
-            List<ExternalIps> updateExternalIps = update.getExternalIps();
-            if (!Objects.equals(originalExternalIps, updateExternalIps)) {
-                if (originalExternalIps == null || originalExternalIps.isEmpty()) {
-                    centralizedSwitchScheduler.scheduleCentralizedSwitch(update);
-                }
-            }
+            centralizedSwitchScheduler.scheduleCentralizedSwitch(update);
         }
     }
 
@@ -148,9 +122,7 @@ public class SnatExternalRoutersListener extends AsyncDataTreeChangeListenerBase
         }
 
         LOG.info("remove : external router event for {}", router.getRouterName());
-        if (router.isEnableSnat()) {
-            centralizedSwitchScheduler.releaseCentralizedSwitch(router);
-        }
+        centralizedSwitchScheduler.releaseCentralizedSwitch(router);
     }
 
     @Override
index a0275b1d7c5e862b00eff5ce9eb289c1f1409d54..942b094f780459da0c4fe8577071c59bf8152f21 100644 (file)
@@ -52,11 +52,12 @@ public class SnatServiceManagerImpl implements SnatServiceManager {
 
     @Override
     public void notify(TypedReadWriteTransaction<Datastore.Configuration> confTx,
-            Routers router, BigInteger primarySwitchId, BigInteger dpnId, Action action)
+            Routers router,  Routers oldRouter, BigInteger primarySwitchId, BigInteger dpnId, Action action)
             throws ExecutionException, InterruptedException {
         for (SnatServiceListener snatServiceListener : snatServiceListeners) {
             boolean result = false;
             switch (action) {
+                //Enables or disables SNAT specific flows in the NAPT and NON-NAPT switches
                 case SNAT_ALL_SWITCH_ENBL:
                     result = snatServiceListener.addSnatAllSwitch(confTx, router, primarySwitchId);
                     break;
@@ -73,6 +74,25 @@ public class SnatServiceManagerImpl implements SnatServiceManager {
                     result = snatServiceListener.removeSnat(confTx, router, primarySwitchId, dpnId);
                     break;
 
+                //Enables or disables flows to send the traffic to the NAT tables in NAPT switch and
+                //the flows to send the traffic to the NAPT switch from a NON-NAPT switch.
+                case CNT_ROUTER_ALL_SWITCH_ENBL:
+                    result = snatServiceListener.addCentralizedRouterAllSwitch(confTx, router, primarySwitchId);
+                    break;
+
+                case CNT_ROUTER_ALL_SWITCH_DISBL:
+                    result = snatServiceListener.removeCentralizedRouterAllSwitch(confTx, router, primarySwitchId);
+                    break;
+
+                case CNT_ROUTER_ENBL:
+                    result = snatServiceListener.addCentralizedRouter(confTx, router, primarySwitchId, dpnId);
+                    break;
+
+                case CNT_ROUTER_DISBL:
+                    result = snatServiceListener.removeCentralizedRouter(confTx, router, primarySwitchId, dpnId);
+                    break;
+
+
                 default:
                     break;
             }
index e58a8ca9e6f991887e9a12e854fb813dc5b0d0b8..03b96c3d8f80d67b2855af876381c50ecff52ffa 100644 (file)
@@ -103,6 +103,52 @@ public class VxlanGreConntrackBasedSnatService extends ConntrackBasedSnatService
         return super.removeSnatAllSwitch(confTx, routers, primarySwitchId);
     }
 
+    public boolean addCentralizedRouterAllSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
+            BigInteger primarySwitchId) {
+        ProviderTypes extNwProviderType = NatUtil.getProviderTypefromNetworkId(dataBroker, routers.getNetworkId());
+        LOG.debug("VxlanGreConntrackBasedSnatService: handleCentralizedRouterAllSwitch ProviderTypes {}",
+                extNwProviderType);
+        if (extNwProviderType == ProviderTypes.FLAT || extNwProviderType == ProviderTypes.VLAN) {
+            LOG.debug("handleCentralizedRouterAllSwitch : Skip FLAT/VLAN provider networks.");
+            return true;
+        }
+        return super.addCentralizedRouterAllSwitch(confTx, routers, primarySwitchId);
+    }
+
+    public boolean removeCentralizedRouterAllSwitch(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
+            BigInteger primarySwitchId)  throws ExecutionException, InterruptedException {
+        ProviderTypes extNwProviderType = NatUtil.getProviderTypefromNetworkId(dataBroker, routers.getNetworkId());
+        LOG.debug("VxlanGreConntrackBasedSnatService: handleCentralizedRouterAllSwitch ProviderTypes {}",
+                extNwProviderType);
+        if (extNwProviderType == ProviderTypes.FLAT || extNwProviderType == ProviderTypes.VLAN) {
+            LOG.debug("handleCentralizedRouterAllSwitch : Skip FLAT/VLAN provider networks.");
+            return true;
+        }
+        return super.removeCentralizedRouterAllSwitch(confTx, routers, primarySwitchId);
+    }
+
+    public boolean addCentralizedRouter(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
+            BigInteger primarySwitchId, BigInteger dpnId) {
+        ProviderTypes extNwProviderType = NatUtil.getProviderTypefromNetworkId(dataBroker, routers.getNetworkId());
+        LOG.debug("VxlanGreConntrackBasedSnatService: handleCentralizedRouter ProviderTypes {}", extNwProviderType);
+        if (extNwProviderType == ProviderTypes.FLAT || extNwProviderType == ProviderTypes.VLAN) {
+            LOG.debug("handleCentralizedRouter : Skip FLAT/VLAN provider networks.");
+            return true;
+        }
+        return super.addCentralizedRouter(confTx, routers, primarySwitchId, dpnId);
+    }
+
+    public boolean removeCentralizedRouter(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
+            BigInteger primarySwitchId, BigInteger dpnId)  throws ExecutionException, InterruptedException {
+        ProviderTypes extNwProviderType = NatUtil.getProviderTypefromNetworkId(dataBroker, routers.getNetworkId());
+        LOG.debug("VxlanGreConntrackBasedSnatService: handleCentralizedRouter ProviderTypes {}", extNwProviderType);
+        if (extNwProviderType == ProviderTypes.FLAT || extNwProviderType == ProviderTypes.VLAN) {
+            LOG.debug("handleCentralizedRouter : Skip FLAT/VLAN provider networks.");
+            return true;
+        }
+        return super.removeCentralizedRouter(confTx, routers, primarySwitchId, dpnId);
+    }
+
     @Override
     public boolean addSnat(TypedReadWriteTransaction<Configuration> confTx, Routers routers,
         BigInteger primarySwitchId, BigInteger dpnId) {