Bug 6816: NAT breakage fix for GRE provider type 88/46988/7
authorYugandhar Sarraju <yugandhar.s@altencalsoftlabs.com>
Fri, 7 Oct 2016 14:32:16 +0000 (20:02 +0530)
committerSam Hague <shague@redhat.com>
Wed, 19 Oct 2016 16:07:19 +0000 (16:07 +0000)
Recent changes in NAT to support transparent vpn caused issues
for existing NAT usecase which works on GRE provider type. Fix is
provided so that provider type is checked when external network is
created.

https://git.opendaylight.org/gerrit/#/c/45133/3
https://git.opendaylight.org/gerrit/#/c/43130/

Change-Id: I0be43018dd681572496ddf7c9fa29dbfc8da2dcf
Signed-off-by: Yugandhar Sarraju <yugandhar.s@altencalsoftlabs.com>
vpnservice/natservice/natservice-api/src/main/yang/odl-nat.yang
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/FloatingIPListener.java
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatUtil.java
vpnservice/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/netvirt/neutronvpn/NeutronNetworkChangeListener.java
vpnservice/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/netvirt/neutronvpn/NeutronvpnNatManager.java
vpnservice/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/netvirt/neutronvpn/NeutronvpnUtils.java

index 6d762ab610ece791821ac22e100b40f599e6e33b..4baeb276624c80671c74d3db2ab842ae9be5f925 100644 (file)
@@ -17,6 +17,7 @@ module odl-nat {
             }
             leaf vpnid { type yang:uuid; }
             leaf-list router-ids { type yang:uuid; }
+            leaf provider-network-type { type provider-types; }
         }
    }
 
@@ -78,6 +79,15 @@ module odl-nat {
         }
     }
 
+    typedef provider-types {
+        type enumeration {
+              enum FLAT;
+              enum VLAN;
+              enum VXLAN;
+              enum GRE;
+        }
+    }
+
     container intext-ip-port-map {
         config true;
         list ip-port-mapping {
index a527c34d94b60a62707d7cedcc4bf73ddf811fd9..1f84ea29ccbfc6aa29132808100c3edb14d245d0 100644 (file)
@@ -37,6 +37,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev16011
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.Networks;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.NetworksKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalNetworks;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@@ -234,9 +235,15 @@ public class FloatingIPListener extends AbstractDataChangeListener<IpMapping> im
         return flowEntity;
     }
 
-    private FlowEntity buildSNATFlowEntity(BigInteger dpId, String internalIp, String externalIp, long vpnId) {
+    private FlowEntity buildSNATFlowEntity(BigInteger dpId, String internalIp, String externalIp, long vpnId, Uuid externalNetworkId) {
         LOG.info("Building SNAT Flow entity for ip {} ", internalIp);
 
+        ProviderTypes provType = NatUtil.getProviderTypefromNetworkId(dataBroker, externalNetworkId);
+        if (provType == null){
+            LOG.error("NAT Service : Unable to get Network Provider Type for network {}", externalNetworkId);
+            return null;
+        }
+
         List<MatchInfo> matches = new ArrayList<>();
         matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
                 MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
@@ -258,12 +265,17 @@ public class FloatingIPListener extends AbstractDataChangeListener<IpMapping> im
             LOG.warn("No MAC address found for floating IP {}", externalIp);
         }
 
-        Uuid subnetId = NatUtil.getSubnetIdForFloatingIp(port, externalIpv4Address);
-        if (subnetId != null) {
-            long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(subnetId.getValue()), idManager);
-            actionsInfo.add(new ActionInfo(ActionType.group, new String[] {String.valueOf(groupId)}));
+        if (provType != ProviderTypes.GRE){
+            Uuid subnetId = NatUtil.getSubnetIdForFloatingIp(port, externalIpv4Address);
+            if (subnetId != null) {
+                long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(subnetId.getValue()), idManager);
+                actionsInfo.add(new ActionInfo(ActionType.group, new String[] {String.valueOf(groupId)}));
+            } else {
+                LOG.warn("No neutron Subnet found for floating IP {}", externalIp);
+            }
         } else {
-            LOG.warn("No neutron Subnet found for floating IP {}", externalIp);
+            LOG.trace("NAT Service : External Network Provider Type is {}, resubmit to FIB", provType.toString());
+            actionsInfo.add(new ActionInfo(ActionType.nx_resubmit, new String[] { Integer.toString(NwConstants.L3_FIB_TABLE) }));
         }
 
         instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfo));
@@ -274,6 +286,7 @@ public class FloatingIPListener extends AbstractDataChangeListener<IpMapping> im
                 NwConstants.COOKIE_DNAT_TABLE, matches, instructions);
 
         return flowEntity;
+
     }
 
     private void createDNATTblEntry(BigInteger dpnId, String internalIp, String externalIp, long routerId, long vpnId, long associatedVpnId) {
@@ -292,11 +305,11 @@ public class FloatingIPListener extends AbstractDataChangeListener<IpMapping> im
         mdsalManager.removeFlow(flowEntity);
     }
 
-    private void createSNATTblEntry(BigInteger dpnId, String internalIp, String externalIp, long vpnId, long routerId, long associatedVpnId) {
+    private void createSNATTblEntry(BigInteger dpnId, String internalIp, String externalIp, long vpnId, long routerId, long associatedVpnId, Uuid externalNetworkId) {
         FlowEntity pFlowEntity = buildPreSNATFlowEntity(dpnId, internalIp, externalIp, vpnId , routerId, associatedVpnId);
         mdsalManager.installFlow(pFlowEntity);
 
-        FlowEntity flowEntity = buildSNATFlowEntity(dpnId, internalIp, externalIp, vpnId);
+        FlowEntity flowEntity = buildSNATFlowEntity(dpnId, internalIp, externalIp, vpnId, externalNetworkId);
         mdsalManager.installFlow(flowEntity);
 
     }
@@ -428,7 +441,7 @@ public class FloatingIPListener extends AbstractDataChangeListener<IpMapping> im
         createDNATTblEntry(dpnId, mapping.getInternalIp(), mapping.getExternalIp(), routerId, vpnId, associatedVpnId);
 
 
-        createSNATTblEntry(dpnId, mapping.getInternalIp(), mapping.getExternalIp(), vpnId, routerId, associatedVpnId);
+        createSNATTblEntry(dpnId, mapping.getInternalIp(), mapping.getExternalIp(), vpnId, routerId, associatedVpnId, extNwId);
 
         floatingIPHandler.onAddFloatingIp(dpnId, routerName, extNwId, interfaceName, mapping.getExternalIp(), mapping
                 .getInternalIp());
@@ -457,7 +470,7 @@ public class FloatingIPListener extends AbstractDataChangeListener<IpMapping> im
         //Create the DNAT and SNAT table entries
         createDNATTblEntry(dpnId, internalIp, externalIp, routerId, vpnId, associatedVpnId);
 
-        createSNATTblEntry(dpnId, internalIp, externalIp, vpnId, routerId, associatedVpnId);
+        createSNATTblEntry(dpnId, internalIp, externalIp, vpnId, routerId, associatedVpnId, externalNetworkId);
 
         floatingIPHandler.onAddFloatingIp(dpnId, routerName, externalNetworkId, interfaceName, externalIp, internalIp);
     }
@@ -489,7 +502,7 @@ public class FloatingIPListener extends AbstractDataChangeListener<IpMapping> im
         pFlowEntity = buildPreSNATFlowEntity(dpnId, internalIp, externalIp, vpnId , routerId, associatedVpnId);
         mdsalManager.installFlow(pFlowEntity);
 
-        flowEntity = buildSNATFlowEntity(dpnId, internalIp, externalIp, vpnId);
+        flowEntity = buildSNATFlowEntity(dpnId, internalIp, externalIp, vpnId, externalNetworkId);
         mdsalManager.installFlow(flowEntity);
 
     }
index 23f64df80a5cde9db218b42bab71c7d7f90468b3..8f4ae646c1f20b5adb6a500ec3afabb9a79df9b0 100644 (file)
@@ -47,6 +47,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpc
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExtRouters;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalIpsCounter;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalNetworks;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.FloatingIpInfo;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.IntextIpMap;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.IntextIpPortMap;
@@ -344,6 +345,15 @@ public class NatUtil {
         return null;
     }
 
+    public static ProviderTypes getProviderTypefromNetworkId(DataBroker broker, Uuid networkId) {
+        InstanceIdentifier<Networks> id = buildNetworkIdentifier(networkId);
+        Optional<Networks> networkData = read(broker, LogicalDatastoreType.CONFIGURATION, id);
+        if ((networkData.isPresent()) && (networkData.get() != null)) {
+            return networkData.get().getProviderNetworkType();
+        }
+        return null;
+    }
+
     public static List<Uuid> getRouterIdsfromNetworkId(DataBroker broker, Uuid networkId) {
         InstanceIdentifier<Networks> id = buildNetworkIdentifier(networkId);
         Optional<Networks> networkData = read(broker, LogicalDatastoreType.CONFIGURATION, id);
index 87e9ab2f2f0e2927c470cd596577ce46cb766f13..3b0d96ceacbb4c4d87d2b34517f01024ec619b29 100644 (file)
@@ -24,6 +24,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.ext.rev160613.QosNetworkExtension;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -68,8 +69,7 @@ public class NeutronNetworkChangeListener extends AsyncDataTreeChangeListenerBas
     protected void add(InstanceIdentifier<Network> identifier, Network input) {
         LOG.trace("Adding Network : key: {}, value={}", identifier, input);
         if (!NeutronvpnUtils.isNetworkTypeSupported(input)) {
-            //FIXME: This should be removed when support for GRE network types is added
-            LOG.error("Neutronvpn doesn't support gre network provider type for this network {}.", input);
+            LOG.error("Neutronvpn doesn't support this network provider type for this network {} and uuid {}.", input.getName(), input.getUuid());
             return;
         }
         NeutronvpnUtils.addToNetworkCache(input);
@@ -78,8 +78,16 @@ public class NeutronNetworkChangeListener extends AsyncDataTreeChangeListenerBas
         // Create ELAN interface and IETF interfaces for the physical network
         elanService.createExternalElanNetwork(elanInstance);
         if (NeutronvpnUtils.getIsExternal(input)) {
+            ProviderTypes providerNwType = NeutronvpnUtils.getProviderNetworkType(input);
+            if(providerNwType == null){
+                LOG.error("Neutron Service : Unable to get Network Provider Type for network {}", input.getUuid());
+                return;
+            }
+            LOG.trace("Neutron Service : External Network Provider Type is {}", providerNwType.getName());
             nvpnNatManager.addExternalNetwork(input);
-            nvpnManager.createL3InternalVpn(input.getUuid(), null, null, null, null, null, null, null);
+            if (providerNwType != ProviderTypes.GRE) {
+                nvpnManager.createL3InternalVpn(input.getUuid(), null, null, null, null, null, null, null);
+            }
         }
     }
 
index 52edc3ff5b7ae700332979497fb672e91940eb61..3a9dfcc0f0d03b0aefb5575b04a997ad316ea9a5 100644 (file)
@@ -29,6 +29,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev16011
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.Networks;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.NetworksBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.NetworksKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.router.ExternalGatewayInfo;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.router.external_gateway_info.ExternalFixedIps;
@@ -226,10 +227,16 @@ public class NeutronvpnNatManager implements AutoCloseable {
                         " already detected to be present");
                 return;
             }
+            ProviderTypes provType = NeutronvpnUtils.getProviderNetworkType(net);
+            if (provType == null){
+                LOG.error("Unable to get Network Provider Type for network {}",net.getUuid());
+                return;
+            }
             NetworksBuilder builder = null;
             builder = new NetworksBuilder().setKey(new NetworksKey(extNetId)).setId(extNetId);
             builder.setVpnid(NeutronvpnUtils.getVpnForNetwork(dataBroker, extNetId));
             builder.setRouterIds(new ArrayList<Uuid>());
+            builder.setProviderNetworkType(provType);
 
             Networks networkss = builder.build();
             // Add Networks object to the ExternalNetworks list
@@ -275,14 +282,20 @@ public class NeutronvpnNatManager implements AutoCloseable {
         Uuid routerId = update.getUuid();
         Uuid extNetId = update.getExternalGatewayInfo().getExternalNetworkId();
 
-        // Add this router to the ExtRouters list
-        addExternalRouter(update, dataBroker);
+        try {
+            Network input = NeutronvpnUtils.getNeutronNetwork(dataBroker, extNetId);
+            ProviderTypes providerNwType = NeutronvpnUtils.getProviderNetworkType(input);
+            if(providerNwType == null){
+                LOG.error("Unable to get Network Provider Type for network {} and uuid {}", input.getName(), input.getUuid());
+                return;
+            }
+            // Add this router to the ExtRouters list
+            addExternalRouter(update, dataBroker);
 
-        // Create and add Networks object for this External Network to the ExternalNetworks list
-        InstanceIdentifier<Networks> netsIdentifier = InstanceIdentifier.builder(ExternalNetworks.class).
-                child(Networks.class, new NetworksKey(extNetId)).build();
+            // Create and add Networks object for this External Network to the ExternalNetworks list
+            InstanceIdentifier<Networks> netsIdentifier = InstanceIdentifier.builder(ExternalNetworks.class).
+                    child(Networks.class, new NetworksKey(extNetId)).build();
 
-        try {
             Optional<Networks> optionalNets = NeutronvpnUtils.read(dataBroker,
                     LogicalDatastoreType.CONFIGURATION,
                     netsIdentifier);
@@ -300,7 +313,9 @@ public class NeutronvpnNatManager implements AutoCloseable {
             }
             rtrList.add(routerId);
             builder.setRouterIds(rtrList);
-            builder.setVpnid(extNetId);
+            if (providerNwType != ProviderTypes.GRE) {
+                builder.setVpnid(extNetId);
+            }
 
             Networks networkss = builder.build();
             // Add Networks object to the ExternalNetworks list
@@ -421,6 +436,12 @@ public class NeutronvpnNatManager implements AutoCloseable {
         InstanceIdentifier<Routers> routersIdentifier = NeutronvpnUtils.buildExtRoutersIdentifier(routerId);
 
         try {
+            Network input = NeutronvpnUtils.getNeutronNetwork(dataBroker, extNetId);
+            ProviderTypes providerNwType = NeutronvpnUtils.getProviderNetworkType(input);
+            if(providerNwType == null){
+                LOG.error("Unable to get Network Provider Type for network {} and uuid{}", input.getName(), input.getUuid());
+                return;
+            }
             Optional<Routers> optionalRouters = NeutronvpnUtils.read(broker,
                     LogicalDatastoreType.CONFIGURATION,
                     routersIdentifier);
@@ -462,7 +483,9 @@ public class NeutronvpnNatManager implements AutoCloseable {
             MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, routersIdentifier, builder.build());
             LOG.trace("Wrote successfully Routers to CONFIG Datastore");
 
-            handleExternalPorts(routers, routerId);
+            if (providerNwType != ProviderTypes.GRE) {
+                handleExternalPorts(routers, routerId);
+            }
         } catch (Exception ex) {
             LOG.error("Creation of extrouters failed for router " + routerId.getValue() +
                     " failed with " + ex.getMessage());
index 539a0071e58c66b3d1a2106929a70e1f03df2447..b2cc6c24e670eebbb8c46ed2a6a66eda26ef5f87 100644 (file)
@@ -36,6 +36,7 @@ import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronConstants;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
@@ -143,6 +144,7 @@ public class NeutronvpnUtils {
         registerSuppoprtedNetworkType(NetworkTypeFlat.class);
         registerSuppoprtedNetworkType(NetworkTypeVlan.class);
         registerSuppoprtedNetworkType(NetworkTypeVxlan.class);
+        registerSuppoprtedNetworkType(NetworkTypeGre.class);
     }
 
     private NeutronvpnUtils() {
@@ -958,6 +960,29 @@ public class NeutronvpnUtils {
         return npe != null && supportedNetworkTypes.contains(npe.getNetworkType());
     }
 
+    static ProviderTypes getProviderNetworkType(Network network) {
+        if (network == null) {
+            logger.error("Error in getting provider network type since network is null");
+            return null;
+        }
+        NetworkProviderExtension npe = network.getAugmentation(NetworkProviderExtension.class);
+        if (npe != null) {
+            Class<? extends NetworkTypeBase> networkTypeBase = npe.getNetworkType();
+            if (networkTypeBase != null) {
+               if(networkTypeBase.isAssignableFrom(NetworkTypeFlat.class)) {
+                   return ProviderTypes.FLAT;
+               } else if (networkTypeBase.isAssignableFrom(NetworkTypeVlan.class)) {
+                   return ProviderTypes.VLAN;
+               } else if (networkTypeBase.isAssignableFrom(NetworkTypeVxlan.class)) {
+                   return ProviderTypes.VXLAN;
+               } else if (networkTypeBase.isAssignableFrom(NetworkTypeGre.class)) {
+                   return ProviderTypes.GRE;
+               }
+            }
+        }
+        return null;
+    }
+
     static boolean isNetworkOfType(Network network, Class<? extends NetworkTypeBase> type) {
         NetworkProviderExtension npe = network.getAugmentation(NetworkProviderExtension.class);
         return npe != null && type.isAssignableFrom(npe.getNetworkType());