NETVIRT-1187 Imported FIB Route is not being translated to flows
[netvirt.git] / fibmanager / impl / src / main / java / org / opendaylight / netvirt / fibmanager / VrfEntryListener.java
index 12848837c3bf8f406638d278455706dd54cb6371..d8d62e53a51ff13f6664ddfd25227a8bb1365bf4 100755 (executable)
@@ -38,6 +38,7 @@ import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFaile
 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
+import org.opendaylight.genius.infra.RetryingManagedNewTransactionRunner;
 import org.opendaylight.genius.mdsalutil.ActionInfo;
 import org.opendaylight.genius.mdsalutil.FlowEntity;
 import org.opendaylight.genius.mdsalutil.InstructionInfo;
@@ -65,6 +66,7 @@ import org.opendaylight.netvirt.fibmanager.NexthopManager.AdjacencyResult;
 import org.opendaylight.netvirt.fibmanager.api.FibHelper;
 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
 import org.opendaylight.netvirt.vpnmanager.api.VpnExtraRouteHelper;
+import org.opendaylight.netvirt.vpnmanager.api.VpnHelper;
 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkCache;
 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkDataComposite;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
@@ -114,11 +116,12 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
     private static final int IPV4_ADDR_PREFIX_LENGTH = 32;
     private static final int LFIB_INTERVPN_PRIORITY = 15;
     public static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
-    private static final int DJC_MAX_RETRIES = 3;
+    private static final int MAX_RETRIES = 3;
     private static final BigInteger COOKIE_TABLE_MISS = new BigInteger("8000004", 16);
 
     private final DataBroker dataBroker;
     private final ManagedNewTransactionRunner txRunner;
+    private final RetryingManagedNewTransactionRunner retryingTxRunner;
     private final IMdsalApiManager mdsalManager;
     private final NexthopManager nextHopManager;
     private final BgpRouteVrfEntryHandler bgpRouteVrfEntryHandler;
@@ -143,6 +146,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
         super(VrfEntry.class, VrfEntryListener.class);
         this.dataBroker = dataBroker;
         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
+        this.retryingTxRunner = new RetryingManagedNewTransactionRunner(dataBroker, MAX_RETRIES);
         this.mdsalManager = mdsalApiManager;
         this.nextHopManager = nexthopManager;
         this.elanManager = elanManager;
@@ -319,8 +323,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
             try {
                 operFuture.get();
             } catch (InterruptedException | ExecutionException e) {
-                LOG.error("Exception encountered while submitting operational future for update vrfentry {}: "
-                        + "{}", update, e);
+                LOG.error("Exception encountered while submitting operational future for update vrfentry {}",
+                        update, e);
             }
 
             createFibEntries(identifier, update);
@@ -414,7 +418,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                 List<ListenableFuture<Void>> futures = new ArrayList<>();
                 futures.add(tx.submit());
                 return futures;
-            }, DJC_MAX_RETRIES);
+            }, MAX_RETRIES);
         }
 
         Optional<String> optVpnUuid = fibUtil.getVpnNameFromRd(rd);
@@ -756,7 +760,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                                         label, localNextHopInfo.getVpnInterfaceName(), lri.getDpnId());
                                 if (vpnExtraRoutes.isEmpty()) {
                                     BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP,
-                                            vpnId, rd, vrfEntry, lri.getParentVpnid(), null, vpnExtraRoutes);
+                                            vpnId, rd, vrfEntry, lri.getParentVpnid(), null /*vpnExtraRoute*/,
+                                            vpnExtraRoutes);
                                     returnLocalDpnId.add(dpnId);
                                 } else {
                                     for (Routes extraRoutes : vpnExtraRoutes) {
@@ -804,13 +809,18 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                         + " FIB processing", vrfEntry.getDestPrefix(), vpnId, rd, dpnId);
                 return dpnId;
             }
+            if (!isVpnPresentInDpn(rd, dpnId)) {
+                LOG.error("checkCreateLocalFibEntry: The VPN with id {} rd {} is not available on dpn {}",
+                        vpnId, rd, dpnId.toString());
+                return BigInteger.ZERO;
+            }
             String jobKey = FibUtil.getCreateLocalNextHopJobKey(vpnId, dpnId, vrfEntry.getDestPrefix());
             String interfaceName = localNextHopInfo.getVpnInterfaceName();
             String prefix = vrfEntry.getDestPrefix();
             String gwMacAddress = vrfEntry.getGatewayMacAddress();
             //The loadbalancing group is created only if the extra route has multiple nexthops
             //to avoid loadbalancing the discovered routes
-            if (vpnExtraRoutes != null) {
+            if (vpnExtraRoutes != null && routes != null) {
                 if (isIpv4Address(routes.getNexthopIpList().get(0))) {
                     localNextHopIP = routes.getNexthopIpList().get(0) + NwConstants.IPV4PREFIX;
                 } else {
@@ -825,7 +835,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                             vpnExtraRoutes);
                     localGroupId = groupId;
                 } else {
-                    groupId = nextHopManager.getLocalNextHopGroup(parentVpnId, localNextHopIP);
+                    groupId = nextHopManager.createLocalNextHop(parentVpnId, dpnId, interfaceName, localNextHopIP,
+                            prefix, gwMacAddress, jobKey);
                     localGroupId = groupId;
                 }
             } else {
@@ -887,6 +898,15 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
         return BigInteger.ZERO;
     }
 
+    private boolean isVpnPresentInDpn(String rd, BigInteger dpnId)  {
+        InstanceIdentifier<VpnToDpnList> id = VpnHelper.getVpnToDpnListIdentifier(rd, dpnId);
+        Optional<VpnToDpnList> dpnInVpn = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
+        if (dpnInVpn.isPresent()) {
+            return true;
+        }
+        return false;
+    }
+
     private LabelRouteInfo getLabelRouteInfo(Long label) {
         InstanceIdentifier<LabelRouteInfo> lriIid = InstanceIdentifier.builder(LabelRouteMap.class)
             .child(LabelRouteInfo.class, new LabelRouteInfoKey(label)).build();
@@ -1484,7 +1504,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                     List<ListenableFuture<Void>> futures = new ArrayList<>();
                     futures.add(tx.submit());
                     return futures;
-                }, DJC_MAX_RETRIES);
+                }, MAX_RETRIES);
         }
 
         //The flow/group entry has been deleted from config DS; need to clean up associated operational
@@ -1572,59 +1592,57 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
             () -> {
                 List<ListenableFuture<Void>> futures = new ArrayList<>();
                 synchronized (vpnInstance.getVpnInstanceName().intern()) {
-                    WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
-                    for (final VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
-                        SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
-                        if (subnetRoute != null) {
-                            long elanTag = subnetRoute.getElantag();
-                            installSubnetRouteInFib(dpnId, elanTag, rd, vpnId, vrfEntry, tx);
-                            installSubnetBroadcastAddrDropRule(dpnId, rd, vpnId, vrfEntry, NwConstants.ADD_FLOW, tx);
-                            continue;
-                        }
-                        RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
-                        if (routerInt != null) {
-                            LOG.trace("Router augmented vrfentry found rd:{}, uuid:{}, ip:{}, mac:{}",
-                                rd, routerInt.getUuid(), routerInt.getIpAddress(), routerInt.getMacAddress());
-                            routerInterfaceVrfEntryHandler.installRouterFibEntry(vrfEntry, dpnId, vpnId,
-                                    routerInt.getIpAddress(), new MacAddress(routerInt.getMacAddress()),
-                                    NwConstants.ADD_FLOW);
-                            continue;
-                        }
-                        //Handle local flow creation for imports
-                        if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
-                            java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
-                            if (optionalLabel.isPresent()) {
-                                List<String> nextHopList = FibHelper.getNextHopListFromRoutePaths(vrfEntry);
-                                LabelRouteInfo lri = getLabelRouteInfo(optionalLabel.get());
-                                if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopList, lri)) {
-                                    if (lri.getDpnId().equals(dpnId)) {
-                                        createLocalFibEntry(vpnId, rd, vrfEntry);
-                                        continue;
+                    futures.add(retryingTxRunner.callWithNewReadWriteTransactionAndSubmit(tx -> {
+                        for (final VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
+                            SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
+                            if (subnetRoute != null) {
+                                long elanTag = subnetRoute.getElantag();
+                                installSubnetRouteInFib(dpnId, elanTag, rd, vpnId, vrfEntry, tx);
+                                installSubnetBroadcastAddrDropRule(dpnId, rd, vpnId, vrfEntry, NwConstants.ADD_FLOW,
+                                        tx);
+                                continue;
+                            }
+                            RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
+                            if (routerInt != null) {
+                                LOG.trace("Router augmented vrfentry found rd:{}, uuid:{}, ip:{}, mac:{}",
+                                        rd, routerInt.getUuid(), routerInt.getIpAddress(), routerInt.getMacAddress());
+                                routerInterfaceVrfEntryHandler.installRouterFibEntry(vrfEntry, dpnId, vpnId,
+                                        routerInt.getIpAddress(), new MacAddress(routerInt.getMacAddress()),
+                                        NwConstants.ADD_FLOW);
+                                continue;
+                            }
+                            //Handle local flow creation for imports
+                            if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
+                                java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
+                                if (optionalLabel.isPresent()) {
+                                    List<String> nextHopList = FibHelper.getNextHopListFromRoutePaths(vrfEntry);
+                                    LabelRouteInfo lri = getLabelRouteInfo(optionalLabel.get());
+                                    if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopList, lri)) {
+                                        if (lri.getDpnId().equals(dpnId)) {
+                                            createLocalFibEntry(vpnId, rd, vrfEntry);
+                                            continue;
+                                        }
                                     }
                                 }
                             }
-                        }
-
-                        boolean shouldCreateRemoteFibEntry = shouldCreateFibEntryForVrfAndVpnIdOnDpn(vpnId,
-                                vrfEntry, dpnId);
-                        if (shouldCreateRemoteFibEntry) {
-                            LOG.trace("Will create remote FIB entry for vrfEntry {} on DPN {}",
+                            boolean shouldCreateRemoteFibEntry = shouldCreateFibEntryForVrfAndVpnIdOnDpn(vpnId,
                                     vrfEntry, dpnId);
-                            if (RouteOrigin.BGP.getValue().equals(vrfEntry.getOrigin())) {
-                                bgpRouteVrfEntryHandler.createRemoteFibEntry(dpnId, vpnId,
-                                        vrfTable.get().getRouteDistinguisher(), vrfEntry, tx, txnObjects);
-                            } else {
-                                createRemoteFibEntry(dpnId, vpnId, vrfTable.get().getRouteDistinguisher(),
-                                        vrfEntry, tx);
+                            if (shouldCreateRemoteFibEntry) {
+                                LOG.trace("Will create remote FIB entry for vrfEntry {} on DPN {}", vrfEntry, dpnId);
+                                if (RouteOrigin.BGP.getValue().equals(vrfEntry.getOrigin())) {
+                                    bgpRouteVrfEntryHandler.createRemoteFibEntry(dpnId, vpnId,
+                                            vrfTable.get().getRouteDistinguisher(), vrfEntry, tx, txnObjects);
+                                } else {
+                                    createRemoteFibEntry(dpnId, vpnId, vrfTable.get().getRouteDistinguisher(),
+                                            vrfEntry, tx);
+                                }
                             }
                         }
+                    }));
+                    if (callback != null) {
+                        ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
+                        Futures.addCallback(listenableFuture, callback, MoreExecutors.directExecutor());
                     }
-                    //TODO: if we have 100K entries in FIB, can it fit in one Tranasaction (?)
-                    futures.add(tx.submit());
-                }
-                if (callback != null) {
-                    ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
-                    Futures.addCallback(listenableFuture, callback, MoreExecutors.directExecutor());
                 }
                 return futures;
             });
@@ -1728,85 +1746,84 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                 List<ListenableFuture<Void>> futures = new ArrayList<>();
                 if (vrfTable.isPresent()) {
                     synchronized (vpnInstance.getVpnInstanceName().intern()) {
-                        WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
-                        for (final VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
+                        futures.add(retryingTxRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
+                            for (final VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
                                 /* Handle subnet routes here */
-                            SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
-                            if (subnetRoute != null) {
-                                LOG.trace("SUBNETROUTE: cleanUpDpnForVpn: Cleaning subnetroute {} on dpn {}"
-                                        + " for vpn {}", vrfEntry.getDestPrefix(), dpnId, rd);
-                                baseVrfEntryHandler.makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null,
-                                        NwConstants.DEL_FLOW, tx, null);
-                                List<RoutePaths> routePaths = vrfEntry.getRoutePaths();
-                                if (routePaths != null) {
-                                    for (RoutePaths routePath : routePaths) {
-                                        makeLFibTableEntry(dpnId, routePath.getLabel(), null,
-                                                DEFAULT_FIB_FLOW_PRIORITY,
-                                                NwConstants.DEL_FLOW, tx);
-                                        LOG.trace("SUBNETROUTE: cleanUpDpnForVpn: Released subnetroute label {} for"
-                                                + " rd {} prefix {}", routePath.getLabel(), rd,
-                                                vrfEntry.getDestPrefix());
+                                SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
+                                if (subnetRoute != null) {
+                                    LOG.trace("SUBNETROUTE: cleanUpDpnForVpn: Cleaning subnetroute {} on dpn {}"
+                                            + " for vpn {}", vrfEntry.getDestPrefix(), dpnId, rd);
+                                    baseVrfEntryHandler.makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null,
+                                            NwConstants.DEL_FLOW, tx, null);
+                                    List<RoutePaths> routePaths = vrfEntry.getRoutePaths();
+                                    if (routePaths != null) {
+                                        for (RoutePaths routePath : routePaths) {
+                                            makeLFibTableEntry(dpnId, routePath.getLabel(), null,
+                                                    DEFAULT_FIB_FLOW_PRIORITY,
+                                                    NwConstants.DEL_FLOW, tx);
+                                            LOG.trace("SUBNETROUTE: cleanUpDpnForVpn: Released subnetroute label {}"
+                                                    + " for rd {} prefix {}", routePath.getLabel(), rd,
+                                                    vrfEntry.getDestPrefix());
+                                        }
                                     }
+                                    installSubnetBroadcastAddrDropRule(dpnId, rd, vpnId, vrfEntry,
+                                            NwConstants.DEL_FLOW, tx);
+                                    continue;
+                                }
+                                // ping responder for router interfaces
+                                RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
+                                if (routerInt != null) {
+                                    LOG.trace("Router augmented vrfentry found for rd:{}, uuid:{}, ip:{}, mac:{}",
+                                            rd, routerInt.getUuid(), routerInt.getIpAddress(),
+                                            routerInt.getMacAddress());
+                                    routerInterfaceVrfEntryHandler.installRouterFibEntry(vrfEntry, dpnId, vpnId,
+                                            routerInt.getIpAddress(), new MacAddress(routerInt.getMacAddress()),
+                                            NwConstants.DEL_FLOW);
+                                    continue;
                                 }
-                                installSubnetBroadcastAddrDropRule(dpnId, rd, vpnId, vrfEntry,
-                                        NwConstants.DEL_FLOW, tx);
-                                continue;
-                            }
-                            // ping responder for router interfaces
-                            RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
-                            if (routerInt != null) {
-                                LOG.trace("Router augmented vrfentry found for rd:{}, uuid:{}, ip:{}, mac:{}",
-                                    rd, routerInt.getUuid(), routerInt.getIpAddress(), routerInt.getMacAddress());
-                                routerInterfaceVrfEntryHandler.installRouterFibEntry(vrfEntry, dpnId, vpnId,
-                                        routerInt.getIpAddress(), new MacAddress(routerInt.getMacAddress()),
-                                        NwConstants.DEL_FLOW);
-                                continue;
-                            }
 
-                            //Handle local flow deletion for imports
-                            if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
-                                java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
-                                if (optionalLabel.isPresent()) {
-                                    List<String> nextHopList = FibHelper.getNextHopListFromRoutePaths(vrfEntry);
-                                    LabelRouteInfo lri = getLabelRouteInfo(optionalLabel.get());
-                                    if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopList, lri)) {
-                                        if (lri.getDpnId().equals(dpnId)) {
+                                //Handle local flow deletion for imports
+                                if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
+                                    java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
+                                    if (optionalLabel.isPresent()) {
+                                        List<String> nextHopList = FibHelper.getNextHopListFromRoutePaths(vrfEntry);
+                                        LabelRouteInfo lri = getLabelRouteInfo(optionalLabel.get());
+                                        if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopList,
+                                                lri) && lri.getDpnId().equals(dpnId)) {
                                             deleteLocalFibEntry(vpnId, rd, vrfEntry);
-                                            continue;
                                         }
                                     }
                                 }
-                            }
 
-                            // Passing null as we don't know the dpn
-                            // to which prefix is attached at this point
-                            List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnInstance.getVpnId(),
-                                    vrfEntry.getDestPrefix());
-                            String vpnName = fibUtil.getVpnNameFromId(vpnInstance.getVpnId());
-                            Optional<Routes> extraRouteOptional;
-                            //Is this fib route an extra route? If yes, get the nexthop which would be
-                            //an adjacency in the vpn
-                            if (usedRds != null && !usedRds.isEmpty()) {
-                                if (usedRds.size() > 1) {
-                                    LOG.error("The extra route prefix is still present in some DPNs");
-                                    return futures;
-                                } else {
-                                    extraRouteOptional = VpnExtraRouteHelper.getVpnExtraroutes(dataBroker, vpnName,
-                                            usedRds.get(0), vrfEntry.getDestPrefix());
+                                // Passing null as we don't know the dpn
+                                // to which prefix is attached at this point
+                                List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker,
+                                        vpnInstance.getVpnId(), vrfEntry.getDestPrefix());
+                                String vpnName = fibUtil.getVpnNameFromId(vpnInstance.getVpnId());
+                                Optional<Routes> extraRouteOptional;
+                                //Is this fib route an extra route? If yes, get the nexthop which would be
+                                //an adjacency in the vpn
+                                if (usedRds != null && !usedRds.isEmpty()) {
+                                    if (usedRds.size() > 1) {
+                                        LOG.error("The extra route prefix is still present in some DPNs");
+                                        return;
+                                    } else {
+                                        extraRouteOptional = VpnExtraRouteHelper.getVpnExtraroutes(dataBroker, vpnName,
+                                                usedRds.get(0), vrfEntry.getDestPrefix());
 
+                                    }
+                                } else {
+                                    extraRouteOptional = Optional.absent();
+                                }
+                                if (RouteOrigin.BGP.getValue().equals(vrfEntry.getOrigin())) {
+                                    bgpRouteVrfEntryHandler.deleteRemoteRoute(null, dpnId, vpnId,
+                                            vrfTable.get().getKey(), vrfEntry, extraRouteOptional, tx, txnObjects);
+                                } else {
+                                    baseVrfEntryHandler.deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(),
+                                            vrfEntry, extraRouteOptional, tx);
                                 }
-                            } else {
-                                extraRouteOptional = Optional.absent();
-                            }
-                            if (RouteOrigin.BGP.getValue().equals(vrfEntry.getOrigin())) {
-                                bgpRouteVrfEntryHandler.deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(),
-                                        vrfEntry, extraRouteOptional, tx, txnObjects);
-                            } else {
-                                baseVrfEntryHandler.deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(),
-                                        vrfEntry, extraRouteOptional, tx);
                             }
-                        }
-                        futures.add(tx.submit());
+                        }));
                     }
                     if (callback != null) {
                         ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);