Retain NAPT Switch after Upgrade for SNAT 62/72062/21
authorxcheara <chetan.arakere@altencalsoftlabs.com>
Thu, 22 Mar 2018 07:19:31 +0000 (12:49 +0530)
committerSam Hague <shague@redhat.com>
Sat, 28 Jul 2018 11:54:35 +0000 (11:54 +0000)
Test Scenario1: All OVS are connected back after upgrade.

1) Take the back-up of the Config DS and bring down the controller.
2) Disconnect OVS(by blocking port 6640 & 6653)
3) Upgrade ODL, set upgrade-flag=true and reload the config DS.
4) Start connecting back the OVS with first connecting non-napt
switches followed by Napt-Switches.
5) set upgrade-flag=false once all the OVS are connected by to ODL.
6) Verify earlier Napt Switches continues to work as Napt Switches
and all earlier on-going SNAT session and new sessions are not
impacted.

Test Scenario2: Few OVS(which are elected as Napt) are not
connected back after upgrade.

1) Take the back-up of the Config DS and bring down the controller.
2) Disconnect OVS(by blocking port 6640 & 6653)
3) Upgrade ODL, set upgrade-flag=true and reload the config DS.
4) Start connecting back the OVS with first connecting non-napt
switches and do not connect few OVS elected as Napt Switches earlier.
5) set upgrade-flag=false.
6) Verify a new Napt Switch is elected for those router whose Napt
Switches are not been connected back after upgrade.
7) Verify new SNAT sessions are established and earlier on-going SNAT
session gets migrated to newly elected Napt Switch.

JIRA: NETVIRT-1222

Change-Id: I194124596e987c43703be37707235a6c88c91013
Signed-off-by: xcheara <chetan.arakere@altencalsoftlabs.com>
Signed-off-by: shaik <shaik.b@altencalsoftlabs.com>
Signed-off-by: xcheara <chetan.arakere@altencalsoftlabs.com>
natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/cli/DisplayNaptSwithcesCli.java
natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/ha/SnatNodeEventListener.java
natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/ExternalRoutersListener.java
natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NaptSwitchHA.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/UpgradeStateListener.java

index 12d38d74f5de83053ac1fca1ae414d9a83dcb392..ee6eb228b9ae49abe21190241588aa08667bf7ba 100644 (file)
@@ -17,6 +17,7 @@ import org.apache.karaf.shell.console.OsgiCommandSupport;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
+import org.opendaylight.netvirt.natservice.internal.NatUtil;
 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;
@@ -41,8 +42,7 @@ public class DisplayNaptSwithcesCli extends OsgiCommandSupport {
     @Override
     protected Object doExecute() throws Exception {
         PrintStream ps = session.getConsole();
-        Optional<NaptSwitches> npatSwitches = SingleTransactionDataBroker.syncReadOptional(dataBroker,
-                LogicalDatastoreType.CONFIGURATION, getNaptSwitchesIdentifier());
+        Optional<NaptSwitches> npatSwitches = NatUtil.getAllPrimaryNaptSwitches(dataBroker);
         ps.printf(String.format(" %-36s  %-20s  %-20s %n", "Router Id ", "Datapath Node Id", "Managment Ip Address"));
         ps.printf("-------------------------------------------------------------------------------------------%n");
         if (npatSwitches.isPresent()) {
@@ -54,10 +54,6 @@ public class DisplayNaptSwithcesCli extends OsgiCommandSupport {
         return null;
     }
 
-    private InstanceIdentifier<NaptSwitches> getNaptSwitchesIdentifier() {
-        return InstanceIdentifier.builder(NaptSwitches.class).build();
-    }
-
     @SuppressWarnings("unchecked")
     private Optional<Node> getPortsNode(BigInteger dpnId) {
         InstanceIdentifier<BridgeRefEntry> bridgeRefInfoPath = InstanceIdentifier.create(BridgeRefInfo.class)
index 4eb71a587f2059f409aa08ef548cadeff68c636c..866add0b8ac3f3504e5e93da26736a0289181e39 100644 (file)
@@ -22,6 +22,7 @@ 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;
@@ -34,23 +35,32 @@ 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 CentralizedSwitchScheduler centralizedSwitchScheduler,
+            final NatserviceConfig config) {
 
         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) {
-        NodeKey nodeKey = dataObjectModification.key();
-        BigInteger dpnId = MDSALUtil.getDpnIdFromNodeName(nodeKey.getId());
-        LOG.info("Dpn removed {}", dpnId);
-        centralizedSwitchScheduler.removeSwitch(dpnId);
+        if (natMode == NatserviceConfig.NatMode.Conntrack) {
+            NodeKey nodeKey = dataObjectModification.key();
+            BigInteger dpnId = MDSALUtil.getDpnIdFromNodeName(nodeKey.getId());
+            LOG.info("Dpn removed {}", dpnId);
+            centralizedSwitchScheduler.removeSwitch(dpnId);
+        }
     }
 
     @Override
@@ -61,10 +71,11 @@ public class SnatNodeEventListener  extends AbstractClusteredAsyncDataTreeChange
 
     @Override
     public void add(Node dataObjectModification) {
-        NodeKey nodeKey = dataObjectModification.key();
-        BigInteger dpnId = MDSALUtil.getDpnIdFromNodeName(nodeKey.getId());
-        LOG.info("Dpn added {}", dpnId);
-        centralizedSwitchScheduler.addSwitch(dpnId);
-
+        if (natMode == NatserviceConfig.NatMode.Conntrack) {
+            NodeKey nodeKey = dataObjectModification.key();
+            BigInteger dpnId = MDSALUtil.getDpnIdFromNodeName(nodeKey.getId());
+            LOG.info("Dpn added {}", dpnId);
+            centralizedSwitchScheduler.addSwitch(dpnId);
+        }
     }
 }
index bf52adda1b724b64c4ec4b460df9518b8e4b3027..5aabff42513615faaf51ea443aeb7e24ba4268b8 100644 (file)
@@ -270,28 +270,26 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         NatUtil.createRouterIdsConfigDS(dataBroker, routerId, routerName);
         Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
         try {
-            coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + routers.key(),
-                () -> Collections.singletonList(
-                    txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
-                        LOG.info("add : Installing NAT default route on all dpns part of router {}", routerName);
-                        long bgpVpnId = NatConstants.INVALID_ID;
-                        if (bgpVpnUuid != null) {
-                            bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
-                        }
-                        addOrDelDefFibRouteToSNAT(routerName, routerId, bgpVpnId, bgpVpnUuid, true, confTx);
-                        // Allocate Primary Napt Switch for this router
-                        BigInteger primarySwitchId = getPrimaryNaptSwitch(routerName);
-                        if (primarySwitchId != null && !primarySwitchId.equals(BigInteger.ZERO)) {
-                            if (!routers.isEnableSnat()) {
-                                LOG.info("add : SNAT is disabled for external router {} ", routerName);
-                                /* If SNAT is disabled on ext-router though L3_FIB_TABLE(21) -> PSNAT_TABLE(26) flow
-                                 * is required for DNAT. Hence writeFlowInvTx object submit is required.
-                                 */
-                                return;
+            if (routers.isEnableSnat()) {
+                coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + routers.key(),
+                    () -> Collections.singletonList(
+                        txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
+                            LOG.info("add : Installing NAT default route on all dpns part of router {}", routerName);
+                            long bgpVpnId = NatConstants.INVALID_ID;
+                            if (bgpVpnUuid != null) {
+                                bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
+                            }
+                            addOrDelDefFibRouteToSNAT(routerName, routerId, bgpVpnId, bgpVpnUuid, true, confTx);
+                            // Allocate Primary Napt Switch for this router
+                            BigInteger primarySwitchId = getPrimaryNaptSwitch(routerName);
+                            if (primarySwitchId != null && !primarySwitchId.equals(BigInteger.ZERO)) {
+                                handleEnableSnat(routers, routerId, primarySwitchId, bgpVpnId, confTx);
                             }
-                            handleEnableSnat(routers, routerId, primarySwitchId, bgpVpnId, confTx);
                         }
-                    })), NatConstants.NAT_DJC_MAX_RETRIES);
+                    )), NatConstants.NAT_DJC_MAX_RETRIES);
+            } else {
+                LOG.info("add : SNAT is disabled for external router {} ", routerName);
+            }
         } catch (Exception ex) {
             LOG.error("add : Exception while Installing NAT flows on all dpns as part of router {}",
                     routerName, ex);
index 1a052370dee4563d951adc2db1ae94f6783414de..0e7e6a65b1d80907e4a9bebe009107c7cb935261 100644 (file)
@@ -57,10 +57,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.G
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
-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.fibmanager.rev150330.FibEntries;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
@@ -450,7 +446,7 @@ public class NaptSwitchHA {
                 return true;
             }
             //checking elected switch health status
-            if (!getSwitchStatus(naptSwitch)) {
+            if (!NatUtil.getSwitchStatus(dataBroker, naptSwitch)) {
                 LOG.error("isNaptSwitchDown : Newly elected Napt switch {} for router {} is down",
                         naptSwitch, routerName);
                 return true;
@@ -607,7 +603,7 @@ public class NaptSwitchHA {
                 SessionAddress externalAddress = new SessionAddress(externalIpAddress, extportNumber);
 
                 //checking naptSwitch status before installing flows
-                if (getSwitchStatus(newNaptSwitch)) {
+                if (NatUtil.getSwitchStatus(dataBroker, newNaptSwitch)) {
                     //Install the flow in newNaptSwitch Inbound NAPT table.
                     try {
                         naptEventHandler.buildAndInstallNatFlows(newNaptSwitch, NwConstants.INBOUND_NAPT_TABLE,
@@ -676,22 +672,6 @@ public class NaptSwitchHA {
         return NatConstants.INVALID_ID;
     }
 
-    public boolean getSwitchStatus(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 =
-                SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
-                        LogicalDatastoreType.OPERATIONAL, nodeInstanceId);
-        if (nodeOptional.isPresent()) {
-            LOG.debug("getSwitchStatus : Switch {} is up", nodeId);
-            return true;
-        }
-        LOG.debug("getSwitchStatus : Switch {} is down", nodeId);
-        return false;
-    }
-
     public List<BucketInfo> handleGroupInPrimarySwitch() {
         List<BucketInfo> listBucketInfo = new ArrayList<>();
         List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
index c5dcdef7e4e4cc45cdf31e6a759526ca17c6013d..dc28ae022a57c33c0616c0038352f9c2fa00424b 100644 (file)
@@ -47,6 +47,7 @@ import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
 import org.opendaylight.genius.mdsalutil.ActionInfo;
 import org.opendaylight.genius.mdsalutil.FlowEntity;
 import org.opendaylight.genius.mdsalutil.FlowEntityBuilder;
+import org.opendaylight.genius.mdsalutil.GroupEntity;
 import org.opendaylight.genius.mdsalutil.InstructionInfo;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
 import org.opendaylight.genius.mdsalutil.MatchInfo;
@@ -111,6 +112,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.G
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetEgressActionsForTunnelOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
@@ -520,10 +522,21 @@ public final class NatUtil {
         return rtrNaptSw;
     }
 
+    public static Optional<NaptSwitches> getAllPrimaryNaptSwitches(DataBroker broker) {
+        return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
+                LogicalDatastoreType.CONFIGURATION, getNaptSwitchesIdentifier());
+    }
+
     public static String getRouterName(DataBroker broker, Long routerId) {
         InstanceIdentifier<RouterIds> id = buildRouterIdentifier(routerId);
-        return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
-                LogicalDatastoreType.CONFIGURATION, id).toJavaUtil().map(RouterIds::getRouterName).orElse(null);
+        String routerName = SingleTransactionDataBroker
+                .syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker, LogicalDatastoreType.CONFIGURATION,
+                        id)
+                .toJavaUtil().map(RouterIds::getRouterName).orElse(null);
+        if (routerName == null) {
+            routerName = getVpnInstanceFromVpnIdentifier(broker, routerId);
+        }
+        return routerName;
     }
 
     static InstanceIdentifier<VpnInstanceOpDataEntry> getVpnInstanceOpDataIdentifier(String vrfId) {
@@ -2139,6 +2152,105 @@ public final class NatUtil {
         }), LOG, "Error installing router gateway flows");
     }
 
+    @SuppressWarnings("checkstyle:IllegalCatch")
+    public static void removeSNATFromDPN(DataBroker dataBroker, IMdsalApiManager mdsalManager,
+            IdManagerService idManager, NaptSwitchHA naptSwitchHA, BigInteger dpnId,
+            String routerName, long routerId, long routerVpnId,
+            ProviderTypes extNwProvType, TypedReadWriteTransaction<Configuration> confTx) {
+        //irrespective of naptswitch or non-naptswitch, SNAT default miss entry need to be removed
+        //remove miss entry to NAPT switch
+        //if naptswitch elect new switch and install Snat flows and remove those flows in oldnaptswitch
+
+        Collection<String> externalIpCache = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
+        if (extNwProvType == null) {
+            return;
+        }
+        //Get the external IP labels other than VXLAN provider type. Since label is not applicable for VXLAN
+        Map<String, Long> externalIpLabel;
+        if (extNwProvType == ProviderTypes.VXLAN) {
+            externalIpLabel = null;
+        } else {
+            externalIpLabel = NatUtil.getExternalIpsLabelForRouter(dataBroker, routerId);
+        }
+        BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
+        if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
+            LOG.error("removeSNATFromDPN : No naptSwitch is selected for router {}", routerName);
+            return;
+        }
+        try {
+            boolean naptStatus =
+                naptSwitchHA.isNaptSwitchDown(routerName, routerId, dpnId, naptSwitch, routerVpnId,
+                        externalIpCache, confTx);
+            if (!naptStatus) {
+                LOG.debug("removeSNATFromDPN: Switch with DpnId {} is not naptSwitch for router {}",
+                    dpnId, routerName);
+                long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
+                FlowEntity flowEntity = null;
+                try {
+                    flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId, routerVpnId,
+                        NatConstants.DEL_FLOW);
+                    if (flowEntity == null) {
+                        LOG.error("removeSNATFromDPN : Failed to populate flowentity for router:{} "
+                                + "with dpnId:{} groupId:{}", routerName, dpnId, groupId);
+                        return;
+                    }
+                    LOG.debug("removeSNATFromDPN : Removing default SNAT miss entry flow entity {}", flowEntity);
+                    mdsalManager.removeFlow(confTx, flowEntity);
+
+                } catch (Exception ex) {
+                    LOG.error("removeSNATFromDPN : Failed to remove default SNAT miss entry flow entity {}",
+                        flowEntity, ex);
+                    return;
+                }
+                LOG.debug("removeSNATFromDPN : Removed default SNAT miss entry flow for dpnID {} with routername {}",
+                    dpnId, routerName);
+
+                //remove group
+                GroupEntity groupEntity = null;
+                try {
+                    groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
+                        GroupTypes.GroupAll, Collections.emptyList() /*listBucketInfo*/);
+                    LOG.info("removeSNATFromDPN : Removing NAPT GroupEntity:{}", groupEntity);
+                    mdsalManager.removeGroup(groupEntity);
+                } catch (Exception ex) {
+                    LOG.error("removeSNATFromDPN : Failed to remove group entity {}", groupEntity, ex);
+                    return;
+                }
+                LOG.debug("removeSNATFromDPN : Removed default SNAT miss entry flow for dpnID {} with routerName {}",
+                    dpnId, routerName);
+            } else {
+                naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, routerId, naptSwitch,
+                        externalIpLabel, confTx);
+                //remove table 26 flow ppointing to table46
+                FlowEntity flowEntity = null;
+                try {
+                    flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName, routerVpnId,
+                        NatConstants.DEL_FLOW);
+                    if (flowEntity == null) {
+                        LOG.error("removeSNATFromDPN : Failed to populate flowentity for router {} with dpnId {}",
+                                routerName, dpnId);
+                        return;
+                    }
+                    LOG.debug("removeSNATFromDPN : Removing default SNAT miss entry flow entity for router {} with "
+                        + "dpnId {} in napt switch {}", routerName, dpnId, naptSwitch);
+                    mdsalManager.removeFlow(confTx, flowEntity);
+
+                } catch (Exception ex) {
+                    LOG.error("removeSNATFromDPN : Failed to remove default SNAT miss entry flow entity {}",
+                        flowEntity, ex);
+                    return;
+                }
+                LOG.debug("removeSNATFromDPN : Removed default SNAT miss entry flow for dpnID {} with routername {}",
+                    dpnId, routerName);
+
+                //best effort to check IntExt model
+                naptSwitchHA.bestEffortDeletion(routerId, routerName, externalIpLabel, confTx);
+            }
+        } catch (Exception ex) {
+            LOG.error("removeSNATFromDPN : Exception while handling naptSwitch down for router {}", routerName, ex);
+        }
+    }
+
     public static Boolean isOpenStackVniSemanticsEnforcedForGreAndVxlan(IElanService elanManager,
                                                                         ProviderTypes extNwProvType) {
         if (elanManager.isOpenStackVniSemanticsEnforced() && (extNwProvType == ProviderTypes.GRE
@@ -2303,4 +2415,20 @@ public final class NatUtil {
             LOG.error("createGroupIdPool : Failed to create PortPool for NAPT Service", e);
         }
     }
+
+    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 =
+                SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
+                        LogicalDatastoreType.OPERATIONAL, nodeInstanceId);
+        if (nodeOptional.isPresent()) {
+            LOG.debug("getSwitchStatus : Switch {} is up", nodeId);
+            return true;
+        }
+        LOG.debug("getSwitchStatus : Switch {} is down", nodeId);
+        return false;
+    }
 }
index 3e7131a47d87da3f2ed45739a71a41ca638928e8..685c3b6ce7c9133abf6388747504427814246504 100644 (file)
@@ -31,6 +31,7 @@ import org.opendaylight.genius.mdsalutil.BucketInfo;
 import org.opendaylight.genius.mdsalutil.FlowEntity;
 import org.opendaylight.genius.mdsalutil.GroupEntity;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
+import org.opendaylight.genius.mdsalutil.UpgradeState;
 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
@@ -68,6 +69,7 @@ public class RouterDpnChangeListener
     private final JobCoordinator coordinator;
     private final SnatServiceManager natServiceManager;
     private final NatMode natMode;
+    private final UpgradeState upgradeState;
 
     @Inject
     public RouterDpnChangeListener(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
@@ -79,7 +81,8 @@ public class RouterDpnChangeListener
                                    final SnatServiceManager natServiceManager,
                                    final NatserviceConfig config,
                                    final IElanService elanManager,
-                                   final JobCoordinator coordinator) {
+                                   final JobCoordinator coordinator,
+                                   final UpgradeState upgradeState) {
         super(DpnVpninterfacesList.class, RouterDpnChangeListener.class);
         this.dataBroker = dataBroker;
         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
@@ -93,6 +96,7 @@ public class RouterDpnChangeListener
         this.natServiceManager = natServiceManager;
         this.coordinator = coordinator;
         this.natMode = config != null ? config.getNatMode() : NatMode.Controller;
+        this.upgradeState = upgradeState;
     }
 
     @Override
@@ -303,8 +307,10 @@ public class RouterDpnChangeListener
         BigInteger naptSwitch;
         try {
             BigInteger naptId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
-            if (naptId == null || naptId.equals(BigInteger.ZERO) || !naptSwitchHA.getSwitchStatus(naptId)) {
-                LOG.debug("handleSNATForDPN : No NaptSwitch is selected for router {}", routerName);
+            if (naptId == null || naptId.equals(BigInteger.ZERO)
+                    || (!NatUtil.getSwitchStatus(dataBroker, naptId) && !upgradeState.isUpgradeInProgress())) {
+                LOG.debug("handleSNATForDPN : NaptSwitch is down or not selected for router {},naptId {}",
+                        routerName, naptId);
                 naptSwitch = dpnId;
                 boolean naptstatus = naptSwitchHA.updateNaptSwitch(routerName, naptSwitch);
                 if (!naptstatus) {
index f265544b62d888d86f0462c2d2e35051a4dba468..712be49a653d9ef2832a4a13f4a49b5e061d2e0a 100644 (file)
@@ -8,6 +8,12 @@
 
 package org.opendaylight.netvirt.natservice.internal;
 
+import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
+
+import com.google.common.base.Optional;
+
+import java.math.BigInteger;
+import java.util.Collections;
 import java.util.List;
 import javax.annotation.Nonnull;
 import javax.inject.Inject;
@@ -18,12 +24,23 @@ import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
+import org.opendaylight.genius.infra.Datastore.Configuration;
+import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
+import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
+import org.opendaylight.genius.infra.TypedReadWriteTransaction;
+import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
 import org.opendaylight.netvirt.natservice.api.CentralizedSwitchScheduler;
 import org.opendaylight.serviceutils.tools.mdsal.listener.AbstractClusteredSyncDataTreeChangeListener;
+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.idmanager.rev160406.IdManagerService;
 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.ProviderTypes;
 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.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitch;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsalutil.rev170830.Config;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
@@ -36,15 +53,29 @@ public class UpgradeStateListener extends AbstractClusteredSyncDataTreeChangeLis
     private final DataBroker dataBroker;
     private final CentralizedSwitchScheduler centralizedSwitchScheduler;
     private final NatserviceConfig.NatMode natMode;
+    private SNATDefaultRouteProgrammer defaultRouteProgrammer;
+    private IMdsalApiManager mdsalManager;
+    private IdManagerService idManager;
+    private NaptSwitchHA naptSwitchHA;
+    private final JobCoordinator coordinator;
+    private final ManagedNewTransactionRunner txRunner;
 
     @Inject
     public UpgradeStateListener(final DataBroker dataBroker,
                                 final CentralizedSwitchScheduler centralizedSwitchScheduler,
-                                final NatserviceConfig config) {
+                                final SNATDefaultRouteProgrammer defaultRouteProgrammer,
+                                final IMdsalApiManager mdsalManager,
+                                final IdManagerService idManager,
+                                final NaptSwitchHA naptSwitchHA,
+                                final NatserviceConfig config, final JobCoordinator coordinator) {
         super(dataBroker, new DataTreeIdentifier<>(
                 LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(Config.class)));
         this.dataBroker = dataBroker;
+        this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
         this.centralizedSwitchScheduler = centralizedSwitchScheduler;
+        this.defaultRouteProgrammer = defaultRouteProgrammer;
+        this.coordinator = coordinator;
+        this.naptSwitchHA = naptSwitchHA;
         if (config != null) {
             this.natMode = config.getNatMode();
         } else {
@@ -59,11 +90,32 @@ public class UpgradeStateListener extends AbstractClusteredSyncDataTreeChangeLis
 
     @Override
     public void remove(@Nonnull Config removedDataObject) {
+        if (natMode == NatserviceConfig.NatMode.Conntrack) {
+            return;
+        }
+        LOG.debug("Verify is all Elected Napt Switch and connected back post upgrade");
     }
 
     @Override
     public void update(@Nonnull Config original, Config updated) {
-        if (natMode != NatserviceConfig.NatMode.Conntrack) {
+        if (natMode == NatserviceConfig.NatMode.Controller) {
+            if (original.isUpgradeInProgress() && !updated.isUpgradeInProgress()) {
+                Optional<NaptSwitches> npatSwitches = NatUtil.getAllPrimaryNaptSwitches(dataBroker);
+                if (npatSwitches.isPresent()) {
+                    for (RouterToNaptSwitch routerToNaptSwitch : npatSwitches.get().getRouterToNaptSwitch()) {
+                        BigInteger primaryNaptDpnId = routerToNaptSwitch.getPrimarySwitchId();
+                        if (!NatUtil.getSwitchStatus(dataBroker, routerToNaptSwitch.getPrimarySwitchId())) {
+                            String routerUuid = routerToNaptSwitch.getRouterName();
+                            coordinator.enqueueJob((NatConstants.NAT_DJC_PREFIX + routerUuid),
+                                () -> Collections.singletonList(
+                                    txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
+                                        reElectNewNaptSwitch(routerUuid, primaryNaptDpnId, confTx);
+                                    }
+                                )), NatConstants.NAT_DJC_MAX_RETRIES);
+                        }
+                    }
+                }
+            }
             return;
         }
 
@@ -89,4 +141,67 @@ public class UpgradeStateListener extends AbstractClusteredSyncDataTreeChangeLis
             }
         }
     }
+
+    private void reElectNewNaptSwitch(String routerName, BigInteger primaryNaptDpnId,
+            TypedReadWriteTransaction<Configuration> confTx) {
+        // Check if this is externalRouter else ignore
+        InstanceIdentifier<Routers> extRoutersId = NatUtil.buildRouterIdentifier(routerName);
+        Optional<Routers> routerData =
+                SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
+                        LogicalDatastoreType.CONFIGURATION, extRoutersId);
+        if (!routerData.isPresent()) {
+            LOG.debug("reElectNewNaptSwitch : SNAT->Ignoring Re-election for router {} since its not External Router",
+                    routerName);
+            return;
+        }
+        Uuid networkId = routerData.get().getNetworkId();
+        if (networkId == null) {
+            LOG.error("hndlTepDelForSnatInEachRtr : SNAT -> Ignoring Re-election  with Napt {} for router {}"
+                    + "as external network configuraton is missing", primaryNaptDpnId, routerName);
+            return;
+        }
+        long routerId = NatUtil.getVpnId(dataBroker, routerName);
+        LOG.debug("hndlTepDelForSnatInEachRtr : SNAT->Router {} is associated with ext nw {}", routerId, networkId);
+        Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
+        Long bgpVpnId;
+        if (bgpVpnUuid == null) {
+            LOG.debug("hndlTepDelForSnatInEachRtr : SNAT->Internal VPN-ID {} associated to router {}",
+                    routerId, routerName);
+            bgpVpnId = routerId;
+        } else {
+            bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
+            if (bgpVpnId == NatConstants.INVALID_ID) {
+                LOG.error("hndlTepDelForSnatInEachRtr :SNAT->Invalid Private BGP VPN ID returned for routerName {}",
+                        routerName);
+                return;
+            }
+        }
+        defaultRouteProgrammer.removeDefNATRouteInDPN(primaryNaptDpnId, bgpVpnId, confTx);
+        if (routerData.get().isEnableSnat()) {
+            LOG.info("hndlTepDelForSnatInEachRtr : SNAT enabled for router {}", routerId);
+
+            long routerVpnId = routerId;
+            if (bgpVpnId != NatConstants.INVALID_ID) {
+                LOG.debug("hndlTepDelForSnatInEachRtr : SNAT -> Private BGP VPN ID (Internal BGP VPN ID) {} "
+                        + "associated to the router {}", bgpVpnId, routerName);
+                routerVpnId = bgpVpnId;
+            } else {
+                LOG.debug("hndlTepDelForSnatInEachRtr : SNAT -> Internal L3 VPN ID (Router ID) {} "
+                        + "associated to the router {}", routerVpnId, routerName);
+            }
+            //Re-elect the other available switch as the NAPT switch and program the NAT flows.
+            ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
+                    routerName, networkId);
+            if (extNwProvType == null) {
+                return;
+            }
+            NatUtil.removeSNATFromDPN(dataBroker, mdsalManager, idManager, naptSwitchHA, primaryNaptDpnId, routerName,
+                    routerId, routerVpnId, extNwProvType, confTx);
+
+        } else {
+            LOG.info("hndlTepDelForSnatInEachRtr : SNAT is not enabled for router {} to handle addDPN event {}",
+                    routerId, primaryNaptDpnId);
+        }
+    }
+
 }