From 7c0b794cdd953d9cc1d32ef57e9df23000b7ccb3 Mon Sep 17 00:00:00 2001 From: Gobinath Date: Fri, 17 Feb 2017 15:49:34 +0530 Subject: [PATCH] Changes for achieving ECMP in VMs present in different DPNs * Split the traffic b/w extra routes behind the VMs present in the * same DC in the different DPNs The local fib entries of the extra route would now point to the load balancing select group which would contain in turn the buckets pointing to the local next hop groups(in case of colocated vms and tunnels in case of VMs present behind different DPNS). The extra route handling for the imported routes. Change-Id: I48ba107bd2b3f57884b6dae258221106e71ad251 Signed-off-by: Gobinath Signed-off-by: gobinath --- .../fibmanager/EVPNVrfEntryProcessor.java | 15 +- .../netvirt/fibmanager/FibUtil.java | 51 +++++ .../netvirt/fibmanager/NexthopManager.java | 60 +++++ .../netvirt/fibmanager/VrfEntryListener.java | 207 ++++++++++++------ .../vpnmanager/VpnInterfaceManager.java | 38 +++- .../netvirt/vpnmanager/VpnUtil.java | 24 +- 6 files changed, 304 insertions(+), 91 deletions(-) diff --git a/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/EVPNVrfEntryProcessor.java b/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/EVPNVrfEntryProcessor.java index 40b4079301..554b87ce1e 100644 --- a/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/EVPNVrfEntryProcessor.java +++ b/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/EVPNVrfEntryProcessor.java @@ -37,6 +37,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adj import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.vpn.extra.routes.Routes; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -249,17 +250,19 @@ public class EVPNVrfEntryProcessor { @Override public List> call() throws Exception { WriteTransaction tx = dataBroker.newWriteOnlyTransaction(); - + final Optional extraRouteOptional = Optional.absent(); if (localDpnIdList.size() <= 0) { for (VpnToDpnList curDpn : vpnToDpnList) { if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) { if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) { vrfEntryListener.deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(), - vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx); + vpnInstance.getVpnId(), vrfTableKey, vrfEntry, + extraRouteOptional, tx); } } else { vrfEntryListener.deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(), - vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx); + vpnInstance.getVpnId(), vrfTableKey, vrfEntry, + extraRouteOptional, tx); } } } else { @@ -269,11 +272,13 @@ public class EVPNVrfEntryProcessor { if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) { if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) { vrfEntryListener.deleteRemoteRoute(localDpnId, curDpn.getDpnId(), - vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx); + vpnInstance.getVpnId(), vrfTableKey, vrfEntry, + extraRouteOptional, tx); } } else { vrfEntryListener.deleteRemoteRoute(localDpnId, curDpn.getDpnId(), - vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx); + vpnInstance.getVpnId(), vrfTableKey, vrfEntry, + extraRouteOptional, tx); } } } diff --git a/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/FibUtil.java b/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/FibUtil.java index 2e69452eed..1d2f7485a0 100644 --- a/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/FibUtil.java +++ b/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/FibUtil.java @@ -28,9 +28,12 @@ import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.opendaylight.genius.mdsalutil.MDSALUtil; +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.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput; @@ -60,6 +63,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.vpn.extra.routes.Routes; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.InterVpnLinkStates; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.InterVpnLinks; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkState; @@ -648,4 +652,51 @@ public class FibUtil { public static String getCreateLocalNextHopJobKey(Long vpnId, BigInteger dpnId, String prefix) { return "FIB-" + vpnId.toString() + "-" + dpnId.toString() + "-" + prefix; } + + public static boolean isTunnelInterface(AdjacencyResult adjacencyResult) { + return Tunnel.class.equals(adjacencyResult.getInterfaceType()); + } + + public static Optional getLastRoutePathExtraRouteIfPresent(DataBroker dataBroker, Long vpnId, + String rd, String prefix) { + List usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, prefix); + String vpnName = getVpnNameFromId(dataBroker, vpnId); + if (usedRds == null || usedRds.isEmpty()) { + LOG.debug("No used rd found for prefix {} on vpn {}", prefix, vpnName); + return Optional.absent(); + } else if (usedRds.size() > 1) { + LOG.debug("The extra route prefix is still present in some DPNs"); + return Optional.absent(); + } else { + rd = usedRds.get(0); + } + //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn + return VpnExtraRouteHelper.getVpnExtraroutes(dataBroker, + getVpnNameFromId(dataBroker, vpnId), rd, prefix); + } + + public static InstanceIdentifier getNextHopIdentifier(String rd, String prefix) { + return InstanceIdentifier.builder(FibEntries.class) + .child(VrfTables.class,new VrfTablesKey(rd)).child(VrfEntry.class,new VrfEntryKey(prefix)).build(); + } + + public static List getNextHopAddresses(DataBroker broker, String rd, String prefix) { + InstanceIdentifier vrfEntryId = getNextHopIdentifier(rd, prefix); + Optional vrfEntry = read(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId); + if (vrfEntry.isPresent()) { + return getNextHopListFromRoutePaths(vrfEntry.get()); + } else { + return Collections.emptyList(); + } + } + + public static Optional getGatewayMac(DataBroker dataBroker, String rd, String localNextHopIP) { + InstanceIdentifier vrfEntryId = getNextHopIdentifier(rd, localNextHopIP); + Optional vrfEntry = read(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfEntryId); + if (vrfEntry.isPresent()) { + return Optional.fromNullable(vrfEntry.get().getGatewayMacAddress()); + } else { + return Optional.absent(); + } + } } diff --git a/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/NexthopManager.java b/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/NexthopManager.java index f493c2d668..541a8dd70e 100644 --- a/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/NexthopManager.java +++ b/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/NexthopManager.java @@ -15,7 +15,10 @@ import com.google.common.util.concurrent.Futures; import java.math.BigInteger; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; + import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; @@ -39,9 +42,11 @@ import org.opendaylight.genius.mdsalutil.actions.ActionPushVlan; import org.opendaylight.genius.mdsalutil.actions.ActionRegLoad; import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldEthernetDestination; import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldEthernetSource; +import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId; import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldVlanVid; import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager; import org.opendaylight.netvirt.elanmanager.api.IElanService; +import org.opendaylight.netvirt.vpnmanager.api.VpnExtraRouteHelper; 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; import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey; @@ -820,7 +825,9 @@ public class NexthopManager implements AutoCloseable { List clonedVpnExtraRoutes = new ArrayList<>(vpnExtraRoutes); if (clonedVpnExtraRoutes.contains(routes)) { listBucketInfo.addAll(getBucketsForLocalNexthop(vpnId, dpnId, vrfEntry, routes)); + clonedVpnExtraRoutes.remove(routes); } + listBucketInfo.addAll(getBucketsForRemoteNexthop(vpnId, dpnId, vrfEntry, rd, clonedVpnExtraRoutes)); return setupLoadBalancingNextHop(vpnId, dpnId, vrfEntry.getDestPrefix(), listBucketInfo, true); } @@ -850,4 +857,57 @@ public class NexthopManager implements AutoCloseable { }); return listBucketInfo; } + + private List getBucketsForRemoteNexthop(Long vpnId, BigInteger dpnId, VrfEntry vrfEntry, String rd, + List vpnExtraRoutes) { + List listBucketInfo = new ArrayList(); + Map> egressActionMap = new HashMap<>(); + vpnExtraRoutes.stream().forEach(vpnExtraRoute -> vpnExtraRoute.getNexthopIpList() + .stream().forEach(nextHopIp -> { + String nextHopPrefixIp = nextHopIp + NwConstants.IPV4PREFIX; + List tepIpAddresses = FibUtil.getNextHopAddresses(dataBroker, rd, nextHopPrefixIp); + java.util.Optional tepIp = tepIpAddresses.stream().findFirst(); + AdjacencyResult adjacencyResult = getRemoteNextHopPointer(dpnId, vpnId, + vrfEntry.getDestPrefix(), tepIp.get()); + if (adjacencyResult == null) { + return; + } + String egressInterface = adjacencyResult.getInterfaceName(); + if (!FibUtil.isTunnelInterface(adjacencyResult)) { + return; + } + Class tunnelType = VpnExtraRouteHelper + .getTunnelType(interfaceManager, + egressInterface); + if (!tunnelType.equals(TunnelTypeVxlan.class)) { + return; + } + Long label = FibUtil.getLabelFromRoutePaths(vrfEntry).get(); + BigInteger tunnelId = BigInteger.valueOf(label); + List actionInfos = new ArrayList<>(); + actionInfos.add(new ActionSetFieldTunnelId(tunnelId)); + Prefixes prefixInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId, nextHopPrefixIp); + String ifName = prefixInfo.getVpnInterfaceName(); + String macAddress = FibUtil.getMacAddressFromPrefix(dataBroker, ifName, nextHopPrefixIp); + actionInfos.add(new ActionSetFieldEthernetDestination(actionInfos.size(), + new MacAddress(macAddress))); + List egressActions = new ArrayList<>(); + if (egressActionMap.containsKey(egressInterface)) { + egressActions = egressActionMap.get(egressInterface); + } else { + egressActions = getEgressActionsForInterface(egressInterface, actionInfos.size()); + egressActionMap.put(egressInterface, egressActions); + } + if (egressActions.isEmpty()) { + LOG.error("Failed to retrieve egress action for prefix {} route-paths {}" + + " interface {}." + " Aborting remote FIB entry creation.", + vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths(), egressInterface); + } + actionInfos.addAll(egressActions); + BucketInfo bucket = new BucketInfo(actionInfos); + bucket.setWeight(1); + listBucketInfo.add(bucket); + })); + return listBucketInfo; + } } diff --git a/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/VrfEntryListener.java b/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/VrfEntryListener.java index 5c2fc3fdbf..c171844e97 100755 --- a/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/VrfEntryListener.java +++ b/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/VrfEntryListener.java @@ -81,7 +81,6 @@ import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.IVpnLinkService; import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkCache; import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkDataComposite; import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId; @@ -113,7 +112,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev15033 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentrybase.RoutePaths; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthop; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthopBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnToExtraroutes; @@ -753,8 +751,10 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase extraRouteOptional = VpnExtraRouteHelper.getVpnExtraroutes(dataBroker, + FibUtil.getVpnNameFromId(dataBroker, vpnId), rd, vrfEntry.getDestPrefix()); + if (extraRouteOptional.isPresent()) { + Routes extraRoute = extraRouteOptional.get(); for (String nextHopIp : extraRoute.getNexthopIpList()) { LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp); if (nextHopIp != null) { @@ -777,10 +777,11 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase returnLocalDpnId = new ArrayList<>(); Prefixes localNextHopInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId, vrfEntry.getDestPrefix()); String localNextHopIP = vrfEntry.getDestPrefix(); + String vpnName = FibUtil.getVpnNameFromId(dataBroker, vpnId); if (localNextHopInfo == null) { List usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, vrfEntry.getDestPrefix()); List vpnExtraRoutes = VpnExtraRouteHelper.getAllVpnExtraRoutes(dataBroker, - FibUtil.getVpnNameFromId(dataBroker, vpnId), usedRds, localNextHopIP); + vpnName, usedRds, localNextHopIP); //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn vpnExtraRoutes.stream().forEach(extraRoute -> { Prefixes localNextHopInfoLocal = FibUtil.getPrefixToInterface(dataBroker, @@ -814,9 +815,19 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase deleteLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) { List returnLocalDpnId = new ArrayList<>(); - VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix()); + Prefixes localNextHopInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId, vrfEntry.getDestPrefix()); String localNextHopIP = vrfEntry.getDestPrefix(); String vpnName = FibUtil.getVpnNameFromId(dataBroker, vpnId); @@ -1030,7 +1041,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase nextHopAddressList = FibUtil.getNextHopListFromRoutePaths(vrfEntry); LabelRouteInfo lri = getLabelRouteInfo(label); if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopAddressList, lri)) { - VpnNexthopBuilder vpnNexthopBuilder = new VpnNexthopBuilder(); - vpnNexthopBuilder.setDpnId(lri.getDpnId()); - BigInteger dpnId = checkDeleteLocalFibEntry(vpnNexthopBuilder.build(), localNextHopIP, + PrefixesBuilder prefixBuilder = new PrefixesBuilder(); + prefixBuilder.setDpnId(lri.getDpnId()); + BigInteger dpnId = checkDeleteLocalFibEntry(prefixBuilder.build(), localNextHopIP, vpnId, rd, vrfEntry, false /*isExtraRoute*/); if (!dpnId.equals(BigInteger.ZERO)) { returnLocalDpnId.add(dpnId); @@ -1070,7 +1081,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase adjacencyResults = resolveAdjacency(remoteDpnId, vpnId, vrfEntry, rd); if (adjacencyResults.isEmpty()) { LOG.error("Could not get interface for route-paths: {} in vpn {}", - vrfEntry.getRoutePaths(), rd); + vrfEntry.getRoutePaths(), rd); LOG.warn("Failed to add Route: {} in vpn: {}", - vrfEntry.getDestPrefix(), rd); + vrfEntry.getDestPrefix(), rd); return; } - - for (AdjacencyResult adjacencyResult : adjacencyResults) { - List actionInfos = new ArrayList<>(); - String egressInterface = adjacencyResult.getInterfaceName(); - if (Tunnel.class.equals(adjacencyResult.getInterfaceType())) { - addTunnelInterfaceActions(egressInterface, vpnId, vrfEntry, actionInfos); - } else { - addRewriteDstMacAction(vpnId, vrfEntry, actionInfos); - } - List egressActions = nextHopManager.getEgressActionsForInterface(egressInterface, - actionInfos.size()); - if (egressActions.isEmpty()) { - LOG.error("Failed to retrieve egress action for prefix {} route-paths {} interface {}. " - + "Aborting remote FIB entry creation.", - vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths(), egressInterface); + List usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, vrfEntry.getDestPrefix()); + List vpnExtraRoutes = VpnExtraRouteHelper.getAllVpnExtraRoutes(dataBroker, + vpnName, usedRds, vrfEntry.getDestPrefix()); + if (!vpnExtraRoutes.isEmpty()) { + List instructions = new ArrayList<>(); + long groupId = nextHopManager.createNextHopGroups(vpnId, rd, remoteDpnId, vrfEntry, + null, vpnExtraRoutes); + if (groupId == FibConstants.INVALID_GROUP_ID) { + LOG.error("Unable to create Group for local prefix {} on rd {} on Node {}", + vrfEntry.getDestPrefix(), rd, remoteDpnId.toString()); return; } - actionInfos.addAll(egressActions); - List instructions = new ArrayList<>(); + List actionInfos = + Collections.singletonList(new ActionGroup(groupId)); instructions.add(new InstructionApplyActions(actionInfos)); makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx); + } else { + List instructions = new ArrayList<>(); + for (AdjacencyResult adjacencyResult : adjacencyResults) { + List actionInfos = new ArrayList<>(); + String egressInterface = adjacencyResult.getInterfaceName(); + if (FibUtil.isTunnelInterface(adjacencyResult)) { + addTunnelInterfaceActions(egressInterface, vpnId, vrfEntry, actionInfos); + } else { + addRewriteDstMacAction(vpnId, vrfEntry, actionInfos); + } + List egressActions = nextHopManager.getEgressActionsForInterface(egressInterface, + actionInfos.size()); + if (egressActions.isEmpty()) { + LOG.error( + "Failed to retrieve egress action for prefix {} route-paths {} interface {}. " + + "Aborting remote FIB entry creation.", + vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths(), egressInterface); + return; + } + actionInfos.addAll(egressActions); + instructions.add(new InstructionApplyActions(actionInfos)); + } + makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx); } if (!wrTxPresent) { tx.submit(); @@ -1257,7 +1287,6 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase localDpnIdList = deleteLocalFibEntry(vpnInstance.getVpnId(), vrfTableKey.getRouteDistinguisher(), vrfEntry); if (vpnToDpnList != null) { - List usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnInstance.getVpnId(), vrfEntry.getDestPrefix()); - String usedRd; - if (usedRds.size() > 1) { - LOG.error("The extra route prefix is still present in some DPNs"); - return ; - } else { - // The first rd is retrieved from usedrds as Only 1 rd would be present as extra route prefix - //is not present in any other DPN - usedRd = usedRds.get(0); + String usedRd = null; + Optional extraRouteOptional; + if (usedRds != null && !usedRds.isEmpty()) { + if (usedRds.size() > 1) { + LOG.error("The extra route prefix is still present in some DPNs"); + return ; + } else { + // The first rd is retrieved from usedrds as Only 1 rd would be present as extra route prefix + //is not present in any other DPN + usedRd = usedRds.get(0); + } } - + //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn + extraRouteOptional = (usedRds != null && !usedRds.isEmpty()) ? VpnExtraRouteHelper + .getVpnExtraroutes(dataBroker, vpnName, usedRd, vrfEntry.getDestPrefix()) : Optional.absent(); DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance(); dataStoreCoordinator.enqueueJob("FIB-" + usedRd + "-" + vrfEntry.getDestPrefix(), () -> { @@ -1503,11 +1536,11 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnInstance.getVpnId(), vrfEntry.getDestPrefix()); - if (usedRds.size() > 1) { - LOG.error("The extra route prefix is still present in some DPNs"); - return ; - } else { - rd = usedRds.get(0); + if (usedRds != null && !usedRds.isEmpty()) { + if (usedRds.size() > 1) { + LOG.error("The extra route prefix is still present in some DPNs"); + return ; + } else { + rd = usedRds.get(0); + } } //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn Optional extraRouteOptional = VpnExtraRouteHelper.getVpnExtraroutes(dataBroker, vpnName, rd, vrfEntry.getDestPrefix()); - for (VpnToDpnList curDpn : vpnToDpnList) { if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) { - deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(), vpnInstance.getVpnId(), - vrfTableKey, vrfEntry, writeTx); + deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, + vrfEntry, extraRouteOptional, writeTx); } } } @@ -1601,7 +1635,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase extraRouteOptional, WriteTransaction tx) { Boolean wrTxPresent = true; if (tx == null) { @@ -1613,22 +1647,19 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnInstance.getVpnId(), + vrfEntry.getDestPrefix()); + if (usedRds.size() > 1) { + LOG.debug("The extra route prefix is still present in some DPNs"); + return futures; + } + //Is this fib route an extra route? If yes, get the nexthop which would be + //an adjacency in the vpn + Optional extraRouteOptional = Optional.absent(); + if (usedRds.size() != 0) { + extraRouteOptional = VpnExtraRouteHelper.getVpnExtraroutes(dataBroker, + FibUtil.getVpnNameFromId(dataBroker, vpnInstance.getVpnId()), + usedRds.get(0), vrfEntry.getDestPrefix()); + } + deleteRemoteRoute(null, localDpnId, vpnId, vrfTablesKey, modVrfEntry, + extraRouteOptional, writeTransaction); } futures.add(writeTransaction.submit()); } @@ -2021,7 +2067,25 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnInstance.getVpnId(), + vrfEntry.getDestPrefix()); + String usedRd; + if (usedRds != null && !usedRds.isEmpty()) { + if (usedRds.size() > 1) { + LOG.error("The extra route prefix is still present in some DPNs"); + return futures; + } else { + usedRd = usedRds.get(0); + } + } + //Is this fib route an extra route? If yes, get the nexthop which would be + //an adjacency in the vpn + Optional extraRouteOptional = VpnExtraRouteHelper.getVpnExtraroutes(dataBroker, + FibUtil.getVpnNameFromId(dataBroker, vpnInstance.getVpnId()), usedRds.get(0), + vrfEntry.getDestPrefix()); + + deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, + extraRouteOptional, tx); } futures.add(tx.submit()); if (callback != null) { @@ -2419,7 +2483,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase { LOG.trace(" deleting remote FIB entry {}", vrfEntry); - deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, writeCfgTxn); + deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, + Optional.absent(), writeCfgTxn); }); } diff --git a/vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/netvirt/vpnmanager/VpnInterfaceManager.java b/vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/netvirt/vpnmanager/VpnInterfaceManager.java index fea20d5eb8..0c205139e1 100755 --- a/vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/netvirt/vpnmanager/VpnInterfaceManager.java +++ b/vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/netvirt/vpnmanager/VpnInterfaceManager.java @@ -578,7 +578,6 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase vpnsToImportRoute = getVpnsImportingMyRoute(vpnName); Optional gwMac = Optional.absent(); VpnInstanceOpDataEntry vpnInstanceOpData = VpnUtil.getVpnInstanceOpData(dataBroker, primaryRd); Long l3vni = vpnInstanceOpData.getL3vni(); @@ -625,7 +624,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase rdToAllocate = VpnUtil .allocateRdForExtraRouteAndUpdateUsedRdsMap(dataBroker, - vpnId, prefix, vpnName, dpnId, nextHop, writeOperTxn); + vpnId, Optional.absent(), prefix, vpnName, dpnId, writeOperTxn); if (rdToAllocate.isPresent()) { rd = rdToAllocate.get(); LOG.info("The rd {} is allocated for the extraroute {}", rd, prefix); @@ -1608,7 +1607,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase rdToAllocate = VpnUtil.allocateRdForExtraRouteAndUpdateUsedRdsMap( - dataBroker, vpnId, prefix, vpnName, dpnId,adj, writeOperTxn); + dataBroker, vpnId, Optional.absent(), prefix, vpnName, dpnId,writeOperTxn); if (rdToAllocate.isPresent()) { adjBuilder.setVrfId(rdToAllocate.get()); addExtraRoute(vpnName, adj.getIpAddress(), nh,rdToAllocate.get(), @@ -1618,6 +1617,20 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase vpnsToImportRoute = getVpnsImportingMyRoute(vpnName); + vpnsToImportRoute.stream().forEach(vpn -> { + java.util.Optional.ofNullable(vpn.getVrfId()).ifPresent(vpnRd -> { + java.util.Optional.ofNullable(VpnUtil.allocateRdForExtraRouteAndUpdateUsedRdsMap( + dataBroker, vpn.getVpnId(), Optional.fromNullable(vpnId), prefix, + VpnUtil.getVpnName(dataBroker, vpn.getVpnId()), dpnId, + writeOperTxn)).ifPresent(rdsToAllocate -> { + addExtraRoute(VpnUtil.getVpnName(dataBroker, vpn.getVpnId()), + adj.getIpAddress(), nh, rdsToAllocate.get(), + currVpnIntf.getVpnInstanceName(), (int) label, + RouteOrigin.SELF_IMPORTED, currVpnIntf.getName(), writeConfigTxn); + }); + }); + }); } } else { adjBuilder.setVrfId(primaryRd); @@ -1633,7 +1646,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase identifier, Adjacency adj, BigInteger dpnId, - WriteTransaction writeOperTxn, WriteTransaction writeConfigTxn) { + WriteTransaction writeOperTxn, WriteTransaction writeConfigTxn) { Optional optVpnInterface = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, identifier); if (optVpnInterface.isPresent()) { @@ -1651,18 +1664,28 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase vpnsToImportRoute = + getVpnsImportingMyRoute(currVpnIntf.getVpnInstanceName()); + for (VpnInstanceOpDataEntry vpn : vpnsToImportRoute) { + java.util.Optional.ofNullable(vpn.getVrfId()).ifPresent(vpnRd -> { + delExtraRoute(adj.getIpAddress(), nh, vpnRd, + currVpnIntf.getVpnInstanceName(), + currVpnIntf.getName(), writeConfigTxn); + }); + } } } break; @@ -1672,7 +1695,6 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase getUsedRds(DataBroker broker, long vpnId, String destPrefix) { InstanceIdentifier usedRdsId = getUsedRdsIdentifier(vpnId, destPrefix); - Optional usedRds = read(broker, LogicalDatastoreType.OPERATIONAL, usedRdsId); + Optional usedRds = read(broker, LogicalDatastoreType.CONFIGURATION, usedRdsId); return usedRds.isPresent() ? usedRds.get().getRds() : new ArrayList(); } @@ -1465,8 +1465,8 @@ public class VpnUtil { } static java.util.Optional allocateRdForExtraRouteAndUpdateUsedRdsMap( - DataBroker dataBroker, long vpnId, String prefix, String vpnName, - BigInteger dpnId, Adjacency adjacency, WriteTransaction writeOperTxn) { + DataBroker dataBroker, long vpnId, Optional parentVpnId, String prefix, String vpnName, + BigInteger dpnId, WriteTransaction writeOperTxn) { List usedRds = getUsedRds(dataBroker, vpnId, prefix); //Check if rd is already allocated for the same prefix. Use same rd if extra route is behind same CSS. java.util.Optional rdToAllocate = usedRds.stream() @@ -1481,7 +1481,14 @@ public class VpnUtil { if (pair.getLeft().isEmpty()) { return false; } - Optional prefixToInterface = getPrefixToInterface(dataBroker, vpnId, pair.getLeft()); + Optional prefixToInterface; + //In case of VPN importing the routes, the interface is not present in the VPN + //and has to be fetched from the VPN from which it imports + if (parentVpnId.isPresent()) { + prefixToInterface = getPrefixToInterface(dataBroker, parentVpnId.get(), pair.getLeft()); + } else { + prefixToInterface = getPrefixToInterface(dataBroker, vpnId, pair.getLeft()); + } return prefixToInterface.isPresent() ? dpnId.equals(prefixToInterface.get().getDpnId()) : false; }).map(pair -> pair.getRight()).findFirst(); if (rdToAllocate.isPresent()) { @@ -1490,20 +1497,23 @@ public class VpnUtil { List availableRds = getVpnRdsFromVpnInstanceConfig(dataBroker, vpnName); if (availableRds.isEmpty()) { LOG.debug("Internal vpn. Returning vpn name {} as rd", vpnName); + usedRds.add(vpnName); + syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, getUsedRdsIdentifier(vpnId, prefix), + getDestPrefixesBuilder(prefix, usedRds).build()); return java.util.Optional.ofNullable(vpnName); } LOG.trace( "Removing used rds {} from available rds {} vpnid {} . prefix is {} , vpname- {}, dpnId- {}, adj - {}", - usedRds, availableRds, vpnId, prefix, vpnName, dpnId, adjacency); + usedRds, availableRds, vpnId, prefix, vpnName, dpnId); availableRds.removeAll(usedRds); if (availableRds.isEmpty()) { - LOG.error("No rd available from VpnInstance to allocate for new adjacency{}", adjacency); + LOG.error("No rd available from VpnInstance to allocate for prefix {}", prefix); return java.util.Optional.empty(); } // If rd is not allocated for this prefix or if extra route is behind different CSS, select a new rd. String rd = availableRds.get(0); usedRds.add(rd); - syncUpdate(dataBroker, LogicalDatastoreType.OPERATIONAL, getUsedRdsIdentifier(vpnId, prefix), + syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, getUsedRdsIdentifier(vpnId, prefix), getDestPrefixesBuilder(prefix, usedRds).build()); return java.util.Optional.ofNullable(rd); } -- 2.36.6