From: Aswin Suryanarayanan Date: Thu, 7 Jun 2018 11:16:03 +0000 (+0530) Subject: SNAT Connectivity from non-FIP instances X-Git-Tag: release/fluorine~135 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=985200069c5aad188edd24bad9e3467310422f22;p=netvirt.git SNAT Connectivity from non-FIP instances 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 --- diff --git a/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanInterfaceManager.java b/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanInterfaceManager.java index cfd896c934..17fea4c86f 100644 --- a/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanInterfaceManager.java +++ b/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanInterfaceManager.java @@ -455,21 +455,24 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase 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 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 elanDpnInterfaces = ElanUtils - .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId); - Optional 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 elanDpnInterfaces = ElanUtils + .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId); + Optional existingElanDpnInterfaces = ElanUtils.read(broker, + LogicalDatastoreType.OPERATIONAL, elanDpnInterfaces); + if (ElanUtils.isVlan(elanInstance)) { + isFirstInterfaceInDpn = checkIfFirstInterface(interfaceName, + elanInstanceName, existingElanDpnInterfaces); } else { - List 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 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 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 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 switchWeightsMap = new ConcurrentHashMap<>(); private final Map subnetIdToRouterPortMap = new ConcurrentHashMap<>(); + private final Map 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); } diff --git a/natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatUtil.java b/natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatUtil.java index e99fad9750..532d5bd209 100644 --- a/natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatUtil.java +++ b/natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatUtil.java @@ -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 elanDpnInterfaceId = getElanDpnInterfaceOperationalDataPath( + elanInstanceName,dpnId); + try { + synchronized (elanInstanceName.intern()) { + Optional dpnInElanInterfaces = SingleTransactionDataBroker.syncReadOptional(dataBroker, + LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId); + List 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 elanDpnInterfaceId = getElanDpnInterfaceOperationalDataPath( + elanInstanceName,dpnId); + try { + synchronized (elanInstanceName.intern()) { + Optional dpnInElanInterfaces = SingleTransactionDataBroker.syncReadOptional(dataBroker, + LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId); + List 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 getElanDpnInterfaceOperationalDataPath(String elanInstanceName, + BigInteger dpId) { + return InstanceIdentifier.builder(ElanDpnInterfaces.class) + .child(ElanDpnInterfacesList.class, new ElanDpnInterfacesListKey(elanInstanceName)) + .child(DpnInterfaces.class, new DpnInterfacesKey(dpId)).build(); + } } diff --git a/vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/VpnUtil.java b/vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/VpnUtil.java index e34b1cff78..dd5b121ea7 100755 --- a/vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/VpnUtil.java +++ b/vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/VpnUtil.java @@ -2030,22 +2030,24 @@ public final class VpnUtil { BigInteger dpnId, DataBroker dataBroker) { InstanceIdentifier elanDpnInterfaceId = getElanDpnInterfaceOperationalDataPath( elanInstanceName,dpnId); - Optional dpnInElanInterfaces = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, - elanDpnInterfaceId); - List 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 dpnInElanInterfaces = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, + elanDpnInterfaceId); + List 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 elanDpnInterfaceId = getElanDpnInterfaceOperationalDataPath( elanInstanceName,dpnId); - Optional dpnInElanInterfaces = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, - elanDpnInterfaceId); - List 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 dpnInElanInterfaces = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, + elanDpnInterfaceId); + List 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); }