SNAT Connectivity from non-FIP instances 49/72749/11
authorAswin Suryanarayanan <asuryana@redhat.com>
Thu, 7 Jun 2018 11:16:03 +0000 (16:46 +0530)
committerSam Hague <shague@redhat.com>
Fri, 15 Jun 2018 23:33:53 +0000 (23:33 +0000)
When the NAPT switch is hosted on a node without the vlan footprint,
SNAT from the instance in the vlan on other nodes are failing.

We are now creating a vlan footprint in the NAPT switch by adding a
pseudo port in the elan-dpnlist for all the vlan added to the router
when the router g/w is set.

NETVIRT-1302 SNAT Connectivity from non-FIP instances to an external IP
fails when using VLAN setup (conntrack)

Change-Id: I55df1109a5415aa425647539d4319fce68899938
Signed-off-by: Aswin Suryanarayanan <asuryana@redhat.com>
elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanInterfaceManager.java
natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/ha/WeightedCentralizedSwitchScheduler.java
natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatUtil.java
vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/VpnUtil.java

index cfd896c9344589384d6be78d56a634931b67d003..17fea4c86fa5cd9e6806fc3d465698611c795daf 100644 (file)
@@ -455,21 +455,24 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
     private DpnInterfaces removeElanDpnInterfaceFromOperationalDataStore(String elanName, BigInteger dpId,
                                                                          String interfaceName, long elanTag,
                                                                          WriteTransaction tx) {
-        DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
-        if (dpnInterfaces != null) {
-            List<String> interfaceLists = dpnInterfaces.getInterfaces();
-            if (interfaceLists != null) {
-                interfaceLists.remove(interfaceName);
-            }
+        synchronized (elanName.intern()) {
 
-            if (interfaceLists == null || interfaceLists.isEmpty()) {
-                deleteAllRemoteMacsInADpn(elanName, dpId, elanTag);
-                deleteElanDpnInterface(elanName, dpId, tx);
-            } else {
-                dpnInterfaces = updateElanDpnInterfacesList(elanName, dpId, interfaceLists, tx);
+            DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
+            if (dpnInterfaces != null) {
+                List<String> interfaceLists = dpnInterfaces.getInterfaces();
+                if (interfaceLists != null) {
+                    interfaceLists.remove(interfaceName);
+                }
+
+                if (interfaceLists == null || interfaceLists.isEmpty()) {
+                    deleteAllRemoteMacsInADpn(elanName, dpId, elanTag);
+                    deleteElanDpnInterface(elanName, dpId, tx);
+                } else {
+                    dpnInterfaces = updateElanDpnInterfacesList(elanName, dpId, interfaceLists, tx);
+                }
             }
+            return dpnInterfaces;
         }
-        return dpnInterfaces;
     }
 
     private void deleteAllRemoteMacsInADpn(String elanName, BigInteger dpId, long elanTag) {
@@ -678,39 +681,41 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
         BigInteger dpId = interfaceInfo.getDpId();
         DpnInterfaces dpnInterfaces = null;
         if (dpId != null && !dpId.equals(ElanConstants.INVALID_DPN)) {
-            InstanceIdentifier<DpnInterfaces> elanDpnInterfaces = ElanUtils
-                    .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
-            Optional<DpnInterfaces> existingElanDpnInterfaces = ElanUtils.read(broker,
-                    LogicalDatastoreType.OPERATIONAL, elanDpnInterfaces);
-            if (ElanUtils.isVlan(elanInstance)) {
-                isFirstInterfaceInDpn =  checkIfFirstInterface(interfaceName,
-                        elanInstanceName, existingElanDpnInterfaces);
-            } else {
-                isFirstInterfaceInDpn = !existingElanDpnInterfaces.isPresent();
-            }
-            if (isFirstInterfaceInDpn) {
-                // ELAN's 1st ElanInterface added to this DPN
-                if (!existingElanDpnInterfaces.isPresent()) {
-                    dpnInterfaces = createElanInterfacesList(elanInstanceName, interfaceName, dpId, tx);
+            synchronized (elanInstanceName.intern()) {
+                InstanceIdentifier<DpnInterfaces> elanDpnInterfaces = ElanUtils
+                        .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
+                Optional<DpnInterfaces> existingElanDpnInterfaces = ElanUtils.read(broker,
+                        LogicalDatastoreType.OPERATIONAL, elanDpnInterfaces);
+                if (ElanUtils.isVlan(elanInstance)) {
+                    isFirstInterfaceInDpn =  checkIfFirstInterface(interfaceName,
+                            elanInstanceName, existingElanDpnInterfaces);
                 } else {
-                    List<String> elanInterfaces = existingElanDpnInterfaces.get().getInterfaces();
-                    elanInterfaces.add(interfaceName);
-                    dpnInterfaces = updateElanDpnInterfacesList(elanInstanceName, dpId,
-                            elanInterfaces, tx);
-                }
-                // The 1st ElanInterface in a DPN must program the Ext Tunnel
-                // table, but only if Elan has VNI
-                if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
-                    setExternalTunnelTable(dpId, elanInstance);
+                    isFirstInterfaceInDpn = !existingElanDpnInterfaces.isPresent();
                 }
-                elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance, interfaceName);
-            } else {
-                List<String> elanInterfaces = existingElanDpnInterfaces.get().getInterfaces();
-                elanInterfaces.add(interfaceName);
-                if (elanInterfaces.size() == 1) { // 1st dpn interface
+                if (isFirstInterfaceInDpn) {
+                    // ELAN's 1st ElanInterface added to this DPN
+                    if (!existingElanDpnInterfaces.isPresent()) {
+                        dpnInterfaces = createElanInterfacesList(elanInstanceName, interfaceName, dpId, tx);
+                    } else {
+                        List<String> elanInterfaces = existingElanDpnInterfaces.get().getInterfaces();
+                        elanInterfaces.add(interfaceName);
+                        dpnInterfaces = updateElanDpnInterfacesList(elanInstanceName, dpId,
+                                elanInterfaces, tx);
+                    }
+                    // The 1st ElanInterface in a DPN must program the Ext Tunnel
+                    // table, but only if Elan has VNI
+                    if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
+                        setExternalTunnelTable(dpId, elanInstance);
+                    }
                     elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance, interfaceName);
+                } else {
+                    List<String> elanInterfaces = existingElanDpnInterfaces.get().getInterfaces();
+                    elanInterfaces.add(interfaceName);
+                    if (elanInterfaces.size() == 1) { // 1st dpn interface
+                        elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance, interfaceName);
+                    }
+                    dpnInterfaces = updateElanDpnInterfacesList(elanInstanceName, dpId, elanInterfaces, tx);
                 }
-                dpnInterfaces = updateElanDpnInterfacesList(elanInstanceName, dpId, elanInterfaces, tx);
             }
         }
 
@@ -838,10 +843,18 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
         if (!existingElanDpnInterfaces.isPresent()) {
             return true;
         }
+        if (elanInterface.equals(elanInstanceName) || elanInterface.equals(routerPortUuid)) {
+            return false;
+        }
         DpnInterfaces dpnInterfaces = existingElanDpnInterfaces.get();
-
-        if (dpnInterfaces.getInterfaces().size() ==  0 || (dpnInterfaces.getInterfaces().size() == 1
-                && dpnInterfaces.getInterfaces().contains(routerPortUuid))) {
+        int dummyInterfaceCount =  0;
+        if (dpnInterfaces.getInterfaces().contains(routerPortUuid)) {
+            dummyInterfaceCount++;
+        }
+        if (dpnInterfaces.getInterfaces().contains(elanInstanceName)) {
+            dummyInterfaceCount++;
+        }
+        if (dpnInterfaces.getInterfaces().size() - dummyInterfaceCount == 0) {
             return true;
         }
         return false;
index 41d02b2cd669fa727dff3e6c83a6b0dc17f862d8..af2f2c7bf6272acae4c4d24ee0d0809afb324b06 100644 (file)
@@ -34,6 +34,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev16011
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitch;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NetworkAttributes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
@@ -48,6 +49,7 @@ public class WeightedCentralizedSwitchScheduler implements CentralizedSwitchSche
 
     private final Map<BigInteger,Integer> switchWeightsMap = 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;
@@ -126,6 +128,11 @@ public class WeightedCentralizedSwitchScheduler implements CentralizedSwitchSche
                         primarySwitchId, tx);
                 NatUtil.addToDpnRoutersMap(dataBroker, routerName, routerPortUuid.getValue(),
                         primarySwitchId, tx);
+                if (subnetMapEntry.getNetworkType().equals(NetworkAttributes.NetworkType.VLAN)) {
+                    String elanInstanceName = subnetMapEntry.getNetworkId().getValue();
+                    subnetIdToElanInstanceMap.put(subnetUuid.getValue(), elanInstanceName);
+                    NatUtil.addPseudoPortToElanDpn(elanInstanceName, elanInstanceName, primarySwitchId, dataBroker);
+                }
             }
         }), LOG, "Error adding subnets to DPN maps for {}", routerName);
     }
@@ -149,6 +156,11 @@ public class WeightedCentralizedSwitchScheduler implements CentralizedSwitchSche
                         routerPort, null, false);
                 NatUtil.removeFromNeutronRouterDpnsMap(dataBroker, routerName, primarySwitchId, tx);
                 NatUtil.removeFromDpnRoutersMap(dataBroker, routerName, routerName, interfaceManager, tx);
+                if (subnetIdToElanInstanceMap.containsKey(subnetUuid.getValue())) {
+                    String elanInstanceName = subnetIdToElanInstanceMap.remove(subnetUuid.getValue());
+                    NatUtil.removePseudoPortFromElanDpn(elanInstanceName, elanInstanceName, primarySwitchId,
+                            dataBroker);
+                }
             }
         }), LOG, "Error deleting subnets from DPN maps for {}", routerName);
     }
index e99fad97509f4f0568a92c2c5b05a1903552c11b..532d5bd209fa5c17d5cca7a54455567676e87da1 100644 (file)
@@ -97,7 +97,13 @@ 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.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanDpnInterfaces;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
@@ -2000,4 +2006,77 @@ public final class NatUtil {
         }
         return false;
     }
+
+    public static void addPseudoPortToElanDpn(String elanInstanceName, String pseudoPortId,
+            BigInteger dpnId, DataBroker dataBroker) {
+        InstanceIdentifier<DpnInterfaces> elanDpnInterfaceId = getElanDpnInterfaceOperationalDataPath(
+                elanInstanceName,dpnId);
+        try {
+            synchronized (elanInstanceName.intern()) {
+                Optional<DpnInterfaces> dpnInElanInterfaces = SingleTransactionDataBroker.syncReadOptional(dataBroker,
+                        LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId);
+                List<String> elanInterfaceList;
+                DpnInterfaces dpnInterface;
+                if (!dpnInElanInterfaces.isPresent()) {
+                    elanInterfaceList = new ArrayList<>();
+                } else {
+                    dpnInterface = dpnInElanInterfaces.get();
+                    elanInterfaceList = dpnInterface.getInterfaces();
+                }
+                if (!elanInterfaceList.contains(pseudoPortId)) {
+                    elanInterfaceList.add(pseudoPortId);
+                    dpnInterface = new DpnInterfacesBuilder().setDpId(dpnId).setInterfaces(elanInterfaceList)
+                            .withKey(new DpnInterfacesKey(dpnId)).build();
+                    SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
+                            elanDpnInterfaceId, dpnInterface);
+                }
+            }
+        } catch (ReadFailedException e) {
+            LOG.warn("Failed to read elanDpnInterface with error {}", e.getMessage());
+        } catch (TransactionCommitFailedException e) {
+            LOG.warn("Failed to add elanDpnInterface with error {}", e.getMessage());
+        }
+    }
+
+    public static void removePseudoPortFromElanDpn(String elanInstanceName, String pseudoPortId,
+            BigInteger dpnId, DataBroker dataBroker) {
+        InstanceIdentifier<DpnInterfaces> elanDpnInterfaceId = getElanDpnInterfaceOperationalDataPath(
+                elanInstanceName,dpnId);
+        try {
+            synchronized (elanInstanceName.intern()) {
+                Optional<DpnInterfaces> dpnInElanInterfaces = SingleTransactionDataBroker.syncReadOptional(dataBroker,
+                        LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId);
+                List<String> elanInterfaceList;
+                DpnInterfaces dpnInterface;
+                if (!dpnInElanInterfaces.isPresent()) {
+                    LOG.info("No interface in any dpn for {}", elanInstanceName);
+                    return;
+                } else {
+                    dpnInterface = dpnInElanInterfaces.get();
+                    elanInterfaceList = dpnInterface.getInterfaces();
+                }
+                if (!elanInterfaceList.contains(pseudoPortId)) {
+                    LOG.info("Router port not present in DPN {} for VPN {}", dpnId, elanInstanceName);
+                    return;
+                }
+                elanInterfaceList.remove(pseudoPortId);
+                dpnInterface = new DpnInterfacesBuilder().setDpId(dpnId).setInterfaces(elanInterfaceList)
+                        .withKey(new DpnInterfacesKey(dpnId)).build();
+                SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
+                        elanDpnInterfaceId, dpnInterface);
+            }
+        } catch (ReadFailedException e) {
+            LOG.warn("Failed to read elanDpnInterface with error {}", e.getMessage());
+        } catch (TransactionCommitFailedException e) {
+            LOG.warn("Failed to remove elanDpnInterface with error {}", e.getMessage());
+        }
+
+    }
+
+    public static InstanceIdentifier<DpnInterfaces> getElanDpnInterfaceOperationalDataPath(String elanInstanceName,
+            BigInteger dpId) {
+        return InstanceIdentifier.builder(ElanDpnInterfaces.class)
+                .child(ElanDpnInterfacesList.class, new ElanDpnInterfacesListKey(elanInstanceName))
+                .child(DpnInterfaces.class, new DpnInterfacesKey(dpId)).build();
+    }
 }
index e34b1cff7844e4b98a18e8457cfc3f6cb34a02a8..dd5b121ea7ef4e67fe122b34641403bfa91ce067 100755 (executable)
@@ -2030,22 +2030,24 @@ public final class VpnUtil {
             BigInteger dpnId, DataBroker dataBroker) {
         InstanceIdentifier<DpnInterfaces> elanDpnInterfaceId = getElanDpnInterfaceOperationalDataPath(
                 elanInstanceName,dpnId);
-        Optional<DpnInterfaces> dpnInElanInterfaces = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
-                elanDpnInterfaceId);
-        List<String> elanInterfaceList;
-        DpnInterfaces dpnInterface;
-        if (!dpnInElanInterfaces.isPresent()) {
-            elanInterfaceList = new ArrayList<>();
-        } else {
-            dpnInterface = dpnInElanInterfaces.get();
-            elanInterfaceList = dpnInterface.getInterfaces();
-        }
-        if (!elanInterfaceList.contains(routerInterfacePortId)) {
-            elanInterfaceList.add(routerInterfacePortId);
-            dpnInterface = new DpnInterfacesBuilder().setDpId(dpnId).setInterfaces(elanInterfaceList)
-                    .withKey(new DpnInterfacesKey(dpnId)).build();
-            VpnUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
-                    elanDpnInterfaceId, dpnInterface);
+        synchronized (elanInstanceName.intern()) {
+            Optional<DpnInterfaces> dpnInElanInterfaces = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
+                    elanDpnInterfaceId);
+            List<String> elanInterfaceList;
+            DpnInterfaces dpnInterface;
+            if (!dpnInElanInterfaces.isPresent()) {
+                elanInterfaceList = new ArrayList<>();
+            } else {
+                dpnInterface = dpnInElanInterfaces.get();
+                elanInterfaceList = dpnInterface.getInterfaces();
+            }
+            if (!elanInterfaceList.contains(routerInterfacePortId)) {
+                elanInterfaceList.add(routerInterfacePortId);
+                dpnInterface = new DpnInterfacesBuilder().setDpId(dpnId).setInterfaces(elanInterfaceList)
+                        .withKey(new DpnInterfacesKey(dpnId)).build();
+                VpnUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
+                        elanDpnInterfaceId, dpnInterface);
+            }
         }
 
     }
@@ -2054,26 +2056,28 @@ public final class VpnUtil {
             String vpnName, BigInteger dpnId, DataBroker dataBroker) {
         InstanceIdentifier<DpnInterfaces> elanDpnInterfaceId = getElanDpnInterfaceOperationalDataPath(
                 elanInstanceName,dpnId);
-        Optional<DpnInterfaces> dpnInElanInterfaces = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
-                elanDpnInterfaceId);
-        List<String> elanInterfaceList;
-        DpnInterfaces dpnInterface;
-        if (!dpnInElanInterfaces.isPresent()) {
-            LOG.info("No interface in any dpn for {}", vpnName);
-            return;
-        } else {
-            dpnInterface = dpnInElanInterfaces.get();
-            elanInterfaceList = dpnInterface.getInterfaces();
-        }
-        if (!elanInterfaceList.contains(routerInterfacePortId)) {
-            LOG.info("Router port not present in DPN {} for VPN {}", dpnId, vpnName);
-            return;
+        synchronized (elanInstanceName.intern()) {
+            Optional<DpnInterfaces> dpnInElanInterfaces = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
+                    elanDpnInterfaceId);
+            List<String> elanInterfaceList;
+            DpnInterfaces dpnInterface;
+            if (!dpnInElanInterfaces.isPresent()) {
+                LOG.info("No interface in any dpn for {}", vpnName);
+                return;
+            } else {
+                dpnInterface = dpnInElanInterfaces.get();
+                elanInterfaceList = dpnInterface.getInterfaces();
+            }
+            if (!elanInterfaceList.contains(routerInterfacePortId)) {
+                LOG.info("Router port not present in DPN {} for VPN {}", dpnId, vpnName);
+                return;
+            }
+            elanInterfaceList.remove(routerInterfacePortId);
+            dpnInterface = new DpnInterfacesBuilder().setDpId(dpnId).setInterfaces(elanInterfaceList)
+                    .withKey(new DpnInterfacesKey(dpnId)).build();
+            VpnUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
+                    elanDpnInterfaceId, dpnInterface);
         }
-        elanInterfaceList.remove(routerInterfacePortId);
-        dpnInterface = new DpnInterfacesBuilder().setDpId(dpnId).setInterfaces(elanInterfaceList)
-                .withKey(new DpnInterfacesKey(dpnId)).build();
-        VpnUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
-                elanDpnInterfaceId, dpnInterface);
 
     }