natservice-impl: propagate upstream non-null annotations
[netvirt.git] / vpnservice / natservice / natservice-impl / src / main / java / org / opendaylight / netvirt / natservice / internal / NatTunnelInterfaceStateListener.java
index b9a6dffea2f715573fa0f73a0a8a583b2cfcf731..f299bd1c2f20764456d7e5377eb2f0e90bc692bc 100644 (file)
@@ -9,15 +9,19 @@
 package org.opendaylight.netvirt.natservice.internal;
 
 import com.google.common.base.Optional;
+import com.google.common.base.Strings;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.JdkFutureAdapters;
 import com.google.common.util.concurrent.ListenableFuture;
 import java.math.BigInteger;
 import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.Future;
+import javax.annotation.Nonnull;
 import javax.annotation.PostConstruct;
 import javax.inject.Inject;
 import javax.inject.Singleton;
@@ -25,6 +29,8 @@ import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
+import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
+import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
 import org.opendaylight.genius.mdsalutil.BucketInfo;
 import org.opendaylight.genius.mdsalutil.FlowEntity;
 import org.opendaylight.genius.mdsalutil.GroupEntity;
@@ -39,9 +45,13 @@ import org.opendaylight.netvirt.elanmanager.api.IElanService;
 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
 import org.opendaylight.netvirt.natservice.api.SnatServiceManager;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
 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.flow.types.rev131026.instruction.list.Instruction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeExternal;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeHwvtep;
@@ -87,6 +97,7 @@ public class NatTunnelInterfaceStateListener
     private final FloatingIPListener floatingIPListener;
     private final FibRpcService fibRpcService;
     private final IElanService elanManager;
+    private final IInterfaceManager interfaceManager;
     private NatMode natMode = NatMode.Controller;
 
     protected enum TunnelAction {
@@ -125,7 +136,8 @@ public class NatTunnelInterfaceStateListener
                                            final FloatingIPListener floatingIPListener,
                                            final FibRpcService fibRpcService,
                                            final NatserviceConfig config,
-                                           final IElanService elanManager) {
+                                           final IElanService elanManager,
+                                           final IInterfaceManager interfaceManager) {
         super(StateTunnelList.class, NatTunnelInterfaceStateListener.class);
         this.dataBroker = dataBroker;
         this.bgpManager = bgpManager;
@@ -140,6 +152,7 @@ public class NatTunnelInterfaceStateListener
         this.floatingIPListener = floatingIPListener;
         this.fibRpcService = fibRpcService;
         this.elanManager = elanManager;
+        this.interfaceManager = interfaceManager;
         if (config != null) {
             this.natMode = config.getNatMode();
         }
@@ -203,20 +216,17 @@ public class NatTunnelInterfaceStateListener
         //remove miss entry to NAPT switch
         //if naptswitch elect new switch and install Snat flows and remove those flows in oldnaptswitch
 
-        //get ExternalIpIn prior
-        List<String> externalIpCache;
-        //HashMap Label
-        HashMap<String, Long> externalIpLabel;
         Long routerId = NatUtil.getVpnId(dataBroker, routerName);
         if (routerId == NatConstants.INVALID_ID) {
             LOG.error("NAT Service : SNAT -> Invalid routerId returned for routerName {}", routerName);
             return;
         }
-        externalIpCache = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
+        Collection<String> externalIpCache = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
         ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,routerName);
         if (extNwProvType == null) {
             return;
         }
+        Map<String, Long> externalIpLabel;
         if (extNwProvType == ProviderTypes.VXLAN) {
             externalIpLabel = null;
         } else {
@@ -261,8 +271,8 @@ public class NatTunnelInterfaceStateListener
                 GroupEntity groupEntity = null;
                 try {
                     groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
-                        GroupTypes.GroupAll, null);
-                    LOG.info("NAT Service : SNAT -> Removing NAPT GroupEntity:{}", groupEntity);
+                        GroupTypes.GroupAll, Collections.emptyList() /*listBucketInfo*/);
+                    LOG.info("NAT Service : SNAT -> Removing NAPT GroupEntity:{} on Dpn {}", groupEntity, dpnId);
                     mdsalManager.removeGroup(groupEntity);
                 } catch (Exception ex) {
                     LOG.debug("NAT Service : SNAT -> Failed to remove group entity {} : {}", groupEntity, ex);
@@ -312,9 +322,7 @@ public class NatTunnelInterfaceStateListener
         LOG.trace("NAT Service : Handle tunnel event for srcDpn {} SrcTepIp {} DestTepIp {} ", srcDpnId, srcTepIp,
             destTepIp);
         int tunTypeVal = getTunnelType(stateTunnelList);
-
         LOG.trace("NAT Service : tunTypeVal is {}", tunTypeVal);
-
         try {
             String srcTepId = stateTunnelList.getSrcInfo().getTepDeviceId();
             String tunnelType = stateTunnelList.getTransportType().toString();
@@ -329,7 +337,8 @@ public class NatTunnelInterfaceStateListener
 
             switch (tunnelAction) {
                 case TUNNEL_EP_ADD:
-                    if (!hndlTepAddForAllRtrs(srcDpnId, tunnelType, tunnelName, srcTepIp, destTepIp)) {
+                    if (isTunnelInLogicalGroup(stateTunnelList)
+                            || !hndlTepAddForAllRtrs(srcDpnId, tunnelType, tunnelName, srcTepIp, destTepIp)) {
                         LOG.debug("NAT Service : Unable to process TEP ADD");
                     }
                     break;
@@ -354,8 +363,9 @@ public class NatTunnelInterfaceStateListener
             + " : {} and DEST IP: {}", fibManager.getTransportTypeStr(tunnelType), srcTepIp, destTepIp);
 
         InstanceIdentifier<DpnRoutersList> dpnRoutersListId = NatUtil.getDpnRoutersId(srcDpnId);
-        Optional<DpnRoutersList> optionalRouterDpnList = NatUtil.read(dataBroker, LogicalDatastoreType
-            .OPERATIONAL, dpnRoutersListId);
+        Optional<DpnRoutersList> optionalRouterDpnList =
+                SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
+                        LogicalDatastoreType.OPERATIONAL, dpnRoutersListId);
         if (!optionalRouterDpnList.isPresent()) {
             LOG.warn("NAT Service : RouterDpnList model is empty for DPN {}. Hence ignoring TEP add event for the ITM "
                     + "TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and TUNNEL NAME {} ",
@@ -413,8 +423,9 @@ public class NatTunnelInterfaceStateListener
 
         List<RoutersList> routersList = null;
         InstanceIdentifier<DpnRoutersList> dpnRoutersListId = NatUtil.getDpnRoutersId(srcDpnId);
-        Optional<DpnRoutersList> optionalRouterDpnList = NatUtil.read(dataBroker, LogicalDatastoreType
-            .OPERATIONAL, dpnRoutersListId);
+        Optional<DpnRoutersList> optionalRouterDpnList =
+                SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
+                        LogicalDatastoreType.OPERATIONAL, dpnRoutersListId);
         if (optionalRouterDpnList.isPresent()) {
             routersList = optionalRouterDpnList.get().getRoutersList();
         } else {
@@ -450,8 +461,9 @@ public class NatTunnelInterfaceStateListener
 
         // Check if this is externalRouter else ignore
         InstanceIdentifier<Routers> extRoutersId = NatUtil.buildRouterIdentifier(routerName);
-        Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType
-                .CONFIGURATION, extRoutersId);
+        Optional<Routers> routerData =
+                SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
+                        LogicalDatastoreType.CONFIGURATION, extRoutersId);
         if (!routerData.isPresent()) {
             LOG.debug("NAT Service : SNAT -> Ignoring TEP add for router {} since its not External Router",
                     routerName);
@@ -542,9 +554,9 @@ public class NatTunnelInterfaceStateListener
                 + "with vpnId {}...", srcDpnId, routerId, vpnId);
             defaultRouteProgrammer.installDefNATRouteInDPN(srcDpnId, vpnId, routerId);
 
-            LOG.debug("NAT Service : Install group in non NAPT switch {}", srcDpnId);
+            LOG.debug("NAT Service : Install group in non NAPT switch {} for router {}", srcDpnId, routerName);
             List<BucketInfo> bucketInfoForNonNaptSwitches =
-                externalRouterListner.getBucketInfoForNonNaptSwitches(srcDpnId, srcDpnId, routerName);
+                externalRouterListner.getBucketInfoForNonNaptSwitches(srcDpnId, primaryDpnId, routerName);
             long groupId = externalRouterListner.installGroup(srcDpnId, routerName, bucketInfoForNonNaptSwitches);
 
             LOG.debug("NAT Service : SNAT -> in the SNAT miss entry pointing to group {} in the non NAPT switch {}",
@@ -581,8 +593,8 @@ public class NatTunnelInterfaceStateListener
         Long vpnId;
         if (vpnName == null) {
             LOG.debug("NAT Service : SNAT -> Internal VPN associated to router {}", routerId);
-            vpnId = NatUtil.getVpnId(dataBroker, routerId);
-            if (vpnId == null || vpnId == NatConstants.INVALID_ID) {
+            vpnId = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
+            if (vpnId == NatConstants.INVALID_ID) {
                 LOG.error("Invalid External VPN-ID returned for routerName {}", routerName);
                 return false;
             }
@@ -613,14 +625,12 @@ public class NatTunnelInterfaceStateListener
                 networkId, routerId);
             return false;
         }
-        List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
-        if (externalIps != null) {
-            LOG.debug("NAT Service : Clearing the FIB entries but not the BGP routes");
-            for (String externalIp : externalIps) {
-                String rd = NatUtil.getVpnRd(dataBroker, externalVpnName);
-                LOG.debug("NAT Service : Removing Fib entry rd {} prefix {}", rd, externalIp);
-                fibManager.removeFibEntry(dataBroker, rd, externalIp, null);
-            }
+        Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
+        LOG.debug("NAT Service : Clearing the FIB entries but not the BGP routes");
+        for (String externalIp : externalIps) {
+            String rd = NatUtil.getVpnRd(dataBroker, externalVpnName);
+            LOG.debug("NAT Service : Removing Fib entry rd {} prefix {}", rd, externalIp);
+            fibManager.removeFibEntry(dataBroker, rd, externalIp, null);
         }
 
         /*
@@ -640,6 +650,13 @@ public class NatTunnelInterfaceStateListener
         if (extNwProvType == ProviderTypes.VXLAN) {
             // Get the External Gateway MAC Address which is Router gateway MAC address for SNAT
             gwMacAddress = NatUtil.getExtGwMacAddFromRouterId(dataBroker, routerId);
+            if (gwMacAddress != null) {
+                LOG.debug("External Gateway MAC address {} found for External Router ID {}", gwMacAddress,
+                        routerId);
+            } else {
+                LOG.error("No External Gateway MAC address found for External Router ID {}", routerId);
+                return false;
+            }
             //get l3Vni value for external VPN
             l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
             if (l3Vni == NatConstants.DEFAULT_L3VNI_VALUE) {
@@ -654,6 +671,7 @@ public class NatTunnelInterfaceStateListener
         if (externalIps != null) {
             for (final String externalIp : externalIps) {
                 long serviceId = 0;
+                String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
                 if (extNwProvType == ProviderTypes.VXLAN) {
                     LOG.debug("NAT Service : SNAT -> Advertise the route to the externalIp {} having nextHopIp {}",
                             externalIp, nextHopIp);
@@ -678,7 +696,7 @@ public class NatTunnelInterfaceStateListener
                     Uuid externalSubnetId = NatUtil.getExternalSubnetForRouterExternalIp(dataBroker, externalIp,
                             router);
                     NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, externalVpnName, rd, externalSubnetId,
-                            externalIp, nextHopIp, networkId.getValue(), null /* mac-address */, label, l3vni, LOG,
+                            fibExternalIp, nextHopIp, networkId.getValue(), null /* mac-address */, label, l3vni, LOG,
                             RouteOrigin.STATIC, srcDpnId);
                     serviceId = label;
                 }
@@ -701,7 +719,7 @@ public class NatTunnelInterfaceStateListener
                         .buildInstruction(customInstructionIndex));
                 CreateFibEntryInput input =
                     new CreateFibEntryInputBuilder().setVpnName(externalVpnName).setSourceDpid(srcDpnId)
-                        .setInstruction(customInstructions).setIpAddress(externalIp + "/32")
+                        .setInstruction(customInstructions).setIpAddress(fibExternalIp)
                         .setServiceId(serviceId).setInstruction(customInstructions).build();
                 Future<RpcResult<Void>> future = fibRpcService.createFibEntry(input);
                 ListenableFuture<RpcResult<Void>> listenableFuture = JdkFutureAdapters.listenInPoolThread(future);
@@ -709,7 +727,7 @@ public class NatTunnelInterfaceStateListener
                 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<Void>>() {
 
                     @Override
-                    public void onFailure(Throwable error) {
+                    public void onFailure(@Nonnull Throwable error) {
                         LOG.error("NAT Service : SNAT -> Error in generate label or fib install process", error);
                     }
 
@@ -766,6 +784,13 @@ public class NatTunnelInterfaceStateListener
         if (extNwProvType == ProviderTypes.VXLAN) {
             // Get the External Gateway MAC Address which is Router gateway MAC address for SNAT
             gwMacAddress = NatUtil.getExtGwMacAddFromRouterId(dataBroker, routerId);
+            if (gwMacAddress != null) {
+                LOG.debug("External Gateway MAC address {} found for External Router ID {}", gwMacAddress,
+                        routerId);
+            } else {
+                LOG.error("No External Gateway MAC address found for External Router ID {}", routerId);
+                return;
+            }
             //get l3Vni value for external VPN
             l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
             if (l3Vni == NatConstants.DEFAULT_L3VNI_VALUE) {
@@ -801,6 +826,8 @@ public class NatTunnelInterfaceStateListener
                     + "for the port: {}",
                     externalIp, interfaceName);
                 long serviceId = 0;
+                String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
+
                 if (extNwProvType == ProviderTypes.VXLAN) {
                     LOG.debug("NAT Service : DNAT -> Advertise the route to the externalIp {} having nextHopIp {}",
                             externalIp, nextHopIp);
@@ -821,7 +848,7 @@ public class NatTunnelInterfaceStateListener
                         l3vni = NatOverVxlanUtil.getInternetVpnVni(idManager, vpnName, l3vni).longValue();
                     }
                     NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, vpnName, rd, null,
-                            externalIp + "/32", nextHopIp, null, null, label, l3vni, LOG, RouteOrigin.STATIC,
+                            fibExternalIp, nextHopIp, null, null, label, l3vni, LOG, RouteOrigin.STATIC,
                             fipCfgdDpnId);
                     serviceId = label;
                 }
@@ -831,7 +858,7 @@ public class NatTunnelInterfaceStateListener
                 customInstructions.add(new InstructionGotoTable(NwConstants.PDNAT_TABLE).buildInstruction(0));
                 CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName)
                     .setSourceDpid(fipCfgdDpnId).setInstruction(customInstructions)
-                    .setIpAddress(externalIp + "/32").setServiceId(serviceId).setInstruction(customInstructions)
+                    .setIpAddress(fibExternalIp).setServiceId(serviceId).setInstruction(customInstructions)
                         .build();
                 Future<RpcResult<Void>> future = fibRpcService.createFibEntry(input);
                 ListenableFuture<RpcResult<Void>> listenableFuture = JdkFutureAdapters.listenInPoolThread(future);
@@ -839,7 +866,7 @@ public class NatTunnelInterfaceStateListener
                 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<Void>>() {
 
                     @Override
-                    public void onFailure(Throwable error) {
+                    public void onFailure(@Nonnull Throwable error) {
                         LOG.error("NAT Service : DNAT -> Error in generate label or fib install process", error);
                     }
 
@@ -875,8 +902,9 @@ public class NatTunnelInterfaceStateListener
 
         // Check if this is externalRouter else ignore
         InstanceIdentifier<Routers> extRoutersId = NatUtil.buildRouterIdentifier(routerName);
-        Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType
-                .CONFIGURATION, extRoutersId);
+        Optional<Routers> routerData =
+                SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
+                        LogicalDatastoreType.CONFIGURATION, extRoutersId);
         if (!routerData.isPresent()) {
             LOG.debug("NAT Service : SNAT -> Ignoring TEP del for router {} since its not External Router",
                     routerName);
@@ -1026,10 +1054,11 @@ public class NatTunnelInterfaceStateListener
             for (InternalToExternalPortMap intExtPortMap : intExtPortMapList) {
                 String internalIp = intExtPortMap.getInternalIp();
                 String externalIp = intExtPortMap.getExternalIp();
+                externalIp = NatUtil.validateAndAddNetworkMask(externalIp);
                 LOG.debug("NAT Service : DNAT -> Withdrawing the FIB route to the floating IP {} "
                     + "configured for the port: {}",
                     externalIp, interfaceName);
-                NatUtil.removePrefixFromBGP(dataBroker, bgpManager, fibManager, rd, externalIp + "/32", vpnName, LOG);
+                NatUtil.removePrefixFromBGP(dataBroker, bgpManager, fibManager, rd, externalIp, vpnName, LOG);
                 long serviceId = 0;
                 if (extNwProvType == ProviderTypes.VXLAN) {
                     serviceId = l3Vni;
@@ -1042,15 +1071,17 @@ public class NatTunnelInterfaceStateListener
                     }
                     serviceId = label;
                 }
+
                 RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName)
-                    .setSourceDpid(fipCfgdDpnId).setIpAddress(externalIp + "/32").setServiceId(serviceId).build();
+                    .setSourceDpid(fipCfgdDpnId).setIpAddress(externalIp).setServiceId(serviceId)
+                    .setIpAddressSource(RemoveFibEntryInput.IpAddressSource.FloatingIP).build();
                 Future<RpcResult<Void>> future = fibRpcService.removeFibEntry(input);
                 ListenableFuture<RpcResult<Void>> listenableFuture = JdkFutureAdapters.listenInPoolThread(future);
 
                 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<Void>>() {
 
                     @Override
-                    public void onFailure(Throwable error) {
+                    public void onFailure(@Nonnull Throwable error) {
                         LOG.error("NAT Service : DNAT -> Error in removing the table 21 entry pushing "
                             + "the MPLS label to the tunnel since label is invalid ", error);
                     }
@@ -1069,4 +1100,20 @@ public class NatTunnelInterfaceStateListener
             }
         }
     }
+
+    protected boolean isTunnelInLogicalGroup(StateTunnelList stateTunnelList) {
+        String ifaceName = stateTunnelList.getTunnelInterfaceName();
+        if (getTunnelType(stateTunnelList) == NatConstants.ITMTunnelLocType.Internal.getValue()) {
+            Interface configIface = interfaceManager.getInterfaceInfoFromConfigDataStore(ifaceName);
+            IfTunnel ifTunnel = (configIface != null) ? configIface.getAugmentation(IfTunnel.class) : null;
+            if (ifTunnel != null && ifTunnel.getTunnelInterfaceType().isAssignableFrom(TunnelTypeVxlan.class)) {
+                ParentRefs refs = configIface.getAugmentation(ParentRefs.class);
+                if (refs != null && !Strings.isNullOrEmpty(refs.getParentInterface())) {
+                    return true; //multiple VxLAN tunnels enabled, i.e. only logical tunnel should be treated
+                }
+            }
+        }
+        LOG.trace("MULTIPLE_VxLAN_TUNNELS: ignoring the tunnel event for {}", ifaceName);
+        return false;
+    }
 }