From: Suraj Ranjan Date: Mon, 18 Jul 2016 09:36:58 +0000 (+0530) Subject: FibManager module sync up X-Git-Tag: release/boron~236^2 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=62038a1a2254940f478ba1a12ff48d47aba09434;p=netvirt.git FibManager module sync up Change-Id: I6e5be84e484de2277ea43e2c065ebd9ca31fab92 Signed-off-by: Suraj Ranjan --- diff --git a/vpnservice/fibmanager/fibmanager-api/src/main/java/org/opendaylight/netvirt/fibmanager/api/IFibManager.java b/vpnservice/fibmanager/fibmanager-api/src/main/java/org/opendaylight/netvirt/fibmanager/api/IFibManager.java index 1b9faa4905..4bca84fbca 100644 --- a/vpnservice/fibmanager/fibmanager-api/src/main/java/org/opendaylight/netvirt/fibmanager/api/IFibManager.java +++ b/vpnservice/fibmanager/fibmanager-api/src/main/java/org/opendaylight/netvirt/fibmanager/api/IFibManager.java @@ -13,13 +13,20 @@ import java.util.List; public interface IFibManager { void populateFibOnNewDpn(BigInteger dpnId, long vpnId, String rd); + void cleanUpDpnForVpn(BigInteger dpnId, long vpnId, String rd, String nextHopIp); + void populateFibOnDpn(BigInteger localDpnId, BigInteger destDpnId, long vpnId, String rd, String nextHopIp); void cleanUpDpnForVpn(BigInteger dpnId, long vpnId, String rd); List printFibEntries(); + + // TODO Feels like this method is not used anywhere void addStaticRoute(String prefix, String nextHop, String rd, int label); - void deleteStaticRoute(String prefix, String rd); + void deleteStaticRoute(String prefix, String nextHop, String rd); void setConfTransType(String service, String transportType); String getConfTransType(); boolean isVPNConfigured(); void writeConfTransTypeConfigDS(); String getReqTransType(); + String getTransportTypeStr(String tunType); + void handleRemoteRoute(boolean action, BigInteger localDpnId, BigInteger remoteDpnId, + long vpnId, String rd, String destPrefix, String nextHopIp); } diff --git a/vpnservice/fibmanager/fibmanager-api/src/main/yang/fib-rpc.yang b/vpnservice/fibmanager/fibmanager-api/src/main/yang/fib-rpc.yang index e6448e3d37..8ebe0b2ed9 100644 --- a/vpnservice/fibmanager/fibmanager-api/src/main/yang/fib-rpc.yang +++ b/vpnservice/fibmanager/fibmanager-api/src/main/yang/fib-rpc.yang @@ -54,4 +54,35 @@ module fib-rpc { } } } -} + + rpc populate-fib-on-dpn { + description "Populates FIB table in specified DPN"; + input { + leaf dpid { + type uint64; + } + leaf vpn-id { + type uint32; + } + leaf rd { + type string; + } + } + } + + rpc cleanup-dpn-for-vpn { + description "Removes the VPN Fib entries in a given DPN"; + input { + leaf dpid { + type uint64; + } + leaf vpn-id { + type uint32; + } + leaf rd { + type string; + } + + } + } +} diff --git a/vpnservice/fibmanager/fibmanager-api/src/main/yang/odl-fib.yang b/vpnservice/fibmanager/fibmanager-api/src/main/yang/odl-fib.yang index 7e5213a77b..10d70f84cc 100644 --- a/vpnservice/fibmanager/fibmanager-api/src/main/yang/odl-fib.yang +++ b/vpnservice/fibmanager/fibmanager-api/src/main/yang/odl-fib.yang @@ -27,8 +27,13 @@ module odl-fib { type uint32; mandatory true; } - leaf nextHopAddress { + leaf-list nextHopAddressList { type string; + min-elements "1"; + } + leaf origin { + type string; + mandatory true; } } } diff --git a/vpnservice/fibmanager/fibmanager-impl/pom.xml b/vpnservice/fibmanager/fibmanager-impl/pom.xml index af77917cb7..3cc15c55cf 100644 --- a/vpnservice/fibmanager/fibmanager-impl/pom.xml +++ b/vpnservice/fibmanager/fibmanager-impl/pom.xml @@ -26,6 +26,11 @@ and is available at http://www.eclipse.org/legal/epl-v10.html fibmanager-api ${vpnservices.version} + + org.opendaylight.netvirt + bgpmanager-api + ${vpnservices.version} + org.opendaylight.genius mdsalutil-api diff --git a/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/FibConstants.java b/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/FibConstants.java index 65b21c3bd9..5d837d98b9 100644 --- a/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/FibConstants.java +++ b/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/FibConstants.java @@ -17,4 +17,5 @@ public class FibConstants { static final String FLOWID_PREFIX = "L3."; static final String VPN_IDPOOL_NAME = "vpnservices"; static final String SEPARATOR = "."; + public static final short L3VPN_SERVICE_IDENTIFIER = 2; // TODO : This should be in just on place } diff --git a/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/FibManager.java b/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/FibManager.java index 096924c76d..61db4a4be9 100644 --- a/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/FibManager.java +++ b/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/FibManager.java @@ -13,18 +13,24 @@ import com.google.common.base.Preconditions; import java.math.BigInteger; import java.net.InetAddress; import java.net.UnknownHostException; -import java.util.ArrayList; import java.util.Collection; -import java.util.HashSet; import java.util.List; +import java.util.concurrent.Callable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; +import com.google.common.util.concurrent.ListenableFuture; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator; +import org.opendaylight.netvirt.bgpmanager.api.RouteOrigin; import org.opendaylight.netvirt.vpnmanager.api.IVpnManager; import org.opendaylight.genius.mdsalutil.AbstractDataChangeListener; import org.opendaylight.genius.mdsalutil.ActionInfo; @@ -39,7 +45,22 @@ import org.opendaylight.genius.mdsalutil.MetaDataUtil; import org.opendaylight.genius.mdsalutil.NwConstants; import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager; import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.SubnetRoute; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.PrefixToInterface; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnToExtraroute; @@ -50,6 +71,12 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.pre 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.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.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn + .link.states.InterVpnLinkState; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn + .links.InterVpnLink; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.Vpn; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.VpnKey; @@ -78,334 +105,724 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class FibManager extends AbstractDataChangeListener implements AutoCloseable{ - private static final Logger LOG = LoggerFactory.getLogger(FibManager.class); - private static final String FLOWID_PREFIX = "L3."; - private ListenerRegistration listenerRegistration; - private final DataBroker broker; - private IMdsalApiManager mdsalManager; - private IVpnManager vpnmanager; - private NexthopManager nextHopManager; - private ItmRpcService itmManager; - private OdlInterfaceRpcService interfaceManager; - private IdManagerService idManager; - private static final BigInteger COOKIE_VM_LFIB_TABLE = new BigInteger("8000002", 16); - private static final BigInteger COOKIE_VM_FIB_TABLE = new BigInteger("8000003", 16); - private static final int DEFAULT_FIB_FLOW_PRIORITY = 10; - private static final BigInteger METADATA_MASK_CLEAR = new BigInteger("000000FFFFFFFFFF", 16); - private static final BigInteger CLEAR_METADATA = BigInteger.valueOf(0); - public static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16); - - - public FibManager(final DataBroker db) { - super(VrfEntry.class); - broker = db; - registerListener(db); - } - - @Override - public void close() throws Exception { - if (listenerRegistration != null) { - try { - listenerRegistration.close(); - } catch (final Exception e) { - LOG.error("Error when cleaning up DataChangeListener.", e); - } - listenerRegistration = null; - } - LOG.info("Fib Manager Closed"); - } - - public void setNextHopManager(NexthopManager nextHopManager) { - this.nextHopManager = nextHopManager; - } + private static final Logger LOG = LoggerFactory.getLogger(FibManager.class); + private static final String FLOWID_PREFIX = "L3."; + private ListenerRegistration listenerRegistration; + private final DataBroker broker; + private IMdsalApiManager mdsalManager; + private IVpnManager vpnmanager; + private NexthopManager nextHopManager; + private ItmRpcService itmManager; + + private OdlInterfaceRpcService interfaceManager; + private IdManagerService idManager; + private static final BigInteger COOKIE_VM_LFIB_TABLE = new BigInteger("8000002", 16); + private static final BigInteger COOKIE_VM_FIB_TABLE = new BigInteger("8000003", 16); + private static final int DEFAULT_FIB_FLOW_PRIORITY = 10; + private static final int LFIB_INTERVPN_PRIORITY = 1; + private static final BigInteger METADATA_MASK_CLEAR = new BigInteger("000000FFFFFFFFFF", 16); + private static final BigInteger CLEAR_METADATA = BigInteger.valueOf(0); + public static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16); + + + public FibManager(final DataBroker db) { + super(VrfEntry.class); + broker = db; + registerListener(db); + } + + @Override + public void close() throws Exception { + if (listenerRegistration != null) { + try { + listenerRegistration.close(); + } catch (final Exception e) { + LOG.error("Error when cleaning up DataChangeListener.", e); + } + listenerRegistration = null; + } + LOG.info("Fib Manager Closed"); + } + public void setNextHopManager(NexthopManager nextHopManager) { + this.nextHopManager = nextHopManager; + } public NexthopManager getNextHopManager() { return this.nextHopManager; } - public void setMdsalManager(IMdsalApiManager mdsalManager) { - this.mdsalManager = mdsalManager; - } - - public void setVpnmanager(IVpnManager vpnmanager) { - this.vpnmanager = vpnmanager; - } - - public void setITMRpcService(ItmRpcService itmManager) { - this.itmManager = itmManager; - } - - public void setInterfaceManager(OdlInterfaceRpcService ifManager) { - this.interfaceManager = ifManager; - } - - public void setIdManager(IdManagerService idManager) { - this.idManager = idManager; - } - - private void registerListener(final DataBroker db) { - try { - listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, - getWildCardPath(), FibManager.this, DataChangeScope.SUBTREE); - } catch (final Exception e) { - LOG.error("FibManager DataChange listener registration fail!", e); - throw new IllegalStateException("FibManager registration Listener failed.", e); - } - } - - - private InstanceIdentifier getWildCardPath() { - return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class).child(VrfEntry.class); - } - - - @Override - protected void add(final InstanceIdentifier identifier, - final VrfEntry vrfEntry) { - LOG.trace("Add key: " + identifier + ", value=" + vrfEntry ); - createFibEntries(identifier, vrfEntry); - } - - @Override - protected void remove(InstanceIdentifier identifier, VrfEntry vrfEntry) { - LOG.trace("Remove key: " + identifier + ", value=" + vrfEntry); - deleteFibEntries(identifier, vrfEntry); - } - - @Override - protected void update(InstanceIdentifier identifier, VrfEntry original, VrfEntry update) { - LOG.trace("Update key: " + identifier + ", original=" + original + ", update=" + update ); - if (original.getAugmentation(SubnetRoute.class) != null && update.getAugmentation(SubnetRoute.class) == null) - return; - createFibEntries(identifier, update); - } - - private void createFibEntries(final InstanceIdentifier identifier, - final VrfEntry vrfEntry) { - final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class); - Preconditions.checkNotNull(vrfTableKey, "VrfTablesKey cannot be null or empty!"); - Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!"); - - VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher()); - Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available " + vrfTableKey.getRouteDistinguisher()); - Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId() + " has null vpnId!"); - - Collection vpnToDpnList = vpnInstance.getVpnToDpnList(); - Long vpnId = vpnInstance.getVpnId(); - String rd = vrfTableKey.getRouteDistinguisher(); - SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class); - if (subnetRoute != null) { - LOG.trace("SubnetRoute augmented vrfentry found for rd {} prefix {} with elantag {}", - rd, vrfEntry.getDestPrefix(), subnetRoute.getElantag()); - long elanTag = subnetRoute.getElantag(); + public void setMdsalManager(IMdsalApiManager mdsalManager) { + this.mdsalManager = mdsalManager; + } + + public void setVpnmanager(IVpnManager vpnmanager) { + this.vpnmanager = vpnmanager; + } + + public void setITMRpcService(ItmRpcService itmManager) { + this.itmManager = itmManager; + } + + public void setInterfaceManager(OdlInterfaceRpcService ifManager) { + this.interfaceManager = ifManager; + } + + public void setIdManager(IdManagerService idManager) { + this.idManager = idManager; + } + + private void registerListener(final DataBroker db) { + try { + listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, + getWildCardPath(), FibManager.this, DataChangeScope.SUBTREE); + } catch (final Exception e) { + LOG.error("FibManager DataChange listener registration fail!", e); + throw new IllegalStateException("FibManager registration Listener failed.", e); + } + } + + + private InstanceIdentifier getWildCardPath() { + return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class).child(VrfEntry.class); + } + + + @Override + protected void add(final InstanceIdentifier identifier, final VrfEntry vrfEntry) { + Preconditions.checkNotNull(vrfEntry, "VrfEntry should not be null or empty."); + String rd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher(); + LOG.info("ADD: Adding Fib Entry rd {} prefix {} nexthop {} label {}", + rd, vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), vrfEntry.getLabel()); + createFibEntries(identifier, vrfEntry); + LOG.info("ADD: Added Fib Entry rd {} prefix {} nexthop {} label {}", + rd, vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), vrfEntry.getLabel()); + leakRouteIfNeeded(identifier, vrfEntry, NwConstants.ADD_FLOW); + } + + @Override + protected void remove(InstanceIdentifier identifier, VrfEntry vrfEntry) { + Preconditions.checkNotNull(vrfEntry, "VrfEntry should not be null or empty."); + String rd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher(); + LOG.info("REMOVE: Removing Fib Entry rd {} prefix {} nexthop {} label {}", + rd, vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), vrfEntry.getLabel()); + deleteFibEntries(identifier, vrfEntry); + LOG.info("REMOVE: Removed Fib Entry rd {} prefix {} nexthop {} label {}", + rd, vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), vrfEntry.getLabel()); + leakRouteIfNeeded(identifier, vrfEntry, NwConstants.DEL_FLOW); + } + + @Override + protected void update(InstanceIdentifier identifier, VrfEntry original, VrfEntry update) { + Preconditions.checkNotNull(update, "VrfEntry should not be null or empty."); + if (original.getAugmentation(SubnetRoute.class) != null && update.getAugmentation(SubnetRoute.class) == null) + return; + String rd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher(); + LOG.info("UPDATE: Updating Fib Entries to rd {} prefix {} nexthop {} label {}", + rd, update.getDestPrefix(), update.getNextHopAddressList(), update.getLabel()); + createFibEntries(identifier, update); + LOG.info("UPDATE: Updated Fib Entries to rd {} prefix {} nexthop {} label {}", + rd, update.getDestPrefix(), update.getNextHopAddressList(), update.getLabel()); + } + + private void createFibEntries(final InstanceIdentifier vrfEntryIid, final VrfEntry vrfEntry) { + final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class); + + final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher()); + Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available " + vrfTableKey.getRouteDistinguisher()); + Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId() + " has null vpnId!"); + + final Collection vpnToDpnList = vpnInstance.getVpnToDpnList(); + final Long vpnId = vpnInstance.getVpnId(); + final String rd = vrfTableKey.getRouteDistinguisher(); + SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class); + if (subnetRoute != null) { + final long elanTag = subnetRoute.getElantag(); + LOG.trace("SubnetRoute augmented vrfentry found for rd {} prefix {} with elantag {}", + rd, vrfEntry.getDestPrefix(), elanTag); + if (vpnToDpnList != null) { + DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance(); + dataStoreCoordinator.enqueueJob("FIB"+rd.toString()+vrfEntry.getDestPrefix(), + new Callable>>() { + @Override + public List> call() throws Exception { + WriteTransaction tx = broker.newWriteOnlyTransaction(); + for (final VpnToDpnList curDpn : vpnToDpnList) { + installSubnetRouteInFib(curDpn.getDpnId(),elanTag, rd, vpnId.longValue(), vrfEntry, tx); + } + List> futures = new ArrayList<>(); + futures.add(tx.submit()); + return futures; + } + }); + } + return; + } + + if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.INTERVPN) { + // When it is a leaked route, the LFIB and FIB goes a bit different. + installInterVpnRouteInLFib(rd, vrfEntry); + return; + } + + final List localDpnIdList = createLocalFibEntry(vpnInstance.getVpnId(), rd, vrfEntry); + if (vpnToDpnList != null) { - for (VpnToDpnList curDpn : vpnToDpnList) { - installSubnetRouteInFib(curDpn.getDpnId(),elanTag, rd, vpnId.longValue(), vrfEntry); + DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance(); + dataStoreCoordinator.enqueueJob("FIB"+rd.toString()+vrfEntry.getDestPrefix(), + new Callable>>() { + @Override + public List> call() throws Exception { + WriteTransaction tx = broker.newWriteOnlyTransaction(); + for (VpnToDpnList vpnDpn : vpnToDpnList) { + if ( !localDpnIdList.contains(vpnDpn.getDpnId())) { + createRemoteFibEntry(vpnDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx); + } + } + List> futures = new ArrayList<>(); + futures.add(tx.submit()); + return futures; + } + }); + } + + Optional vpnUuid = FibUtil.getVpnNameFromRd(broker, rd); + if ( vpnUuid.isPresent() ) { + Optional interVpnLink = FibUtil.getInterVpnLinkByVpnUuid(broker, vpnUuid.get()); + if ( interVpnLink.isPresent() ) { + String routeNexthop = vrfEntry.getNextHopAddressList().get(0); + if ( isNexthopTheOtherVpnLinkEndpoint(routeNexthop, vpnUuid.get(), interVpnLink.get()) ) { + // This is an static route that points to the other endpoint of an InterVpnLink + // In that case, we should add another entry in FIB table pointing to LPortDispatcher table. + installRouteInInterVpnLink(interVpnLink.get(), rd, vrfEntry, vpnId); + } } } - return; } - BigInteger localDpnId = createLocalFibEntry(vpnInstance.getVpnId(), - rd, vrfEntry); - if (vpnToDpnList != null) { - for (VpnToDpnList curDpn : vpnToDpnList) { - if (!curDpn.getDpnId().equals(localDpnId)) { - createRemoteFibEntry(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(), - vrfTableKey, vrfEntry); + + /* + * Returns true if the specified nexthop is the other endpoint in an + * InterVpnLink, regarding one of the VPN's point of view. + */ + private boolean isNexthopTheOtherVpnLinkEndpoint(String nexthop, String thisVpnUuid, InterVpnLink interVpnLink) { + return + interVpnLink != null + && ( (interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(thisVpnUuid) + && interVpnLink.getSecondEndpoint().getIpAddress().getValue().equals(nexthop)) + || (interVpnLink.getSecondEndpoint().getVpnUuid().getValue().equals(thisVpnUuid ) + && interVpnLink.getFirstEndpoint().getIpAddress().getValue().equals(nexthop)) ); + } + + + // FIXME: Refactoring needed here. + // This kind of logic must be taken to an 'upper' layer like BgpManager or VpnManager + private void leakRouteIfNeeded(final InstanceIdentifier vrfEntryIid, final VrfEntry vrfEntry, + int addOrRemove) { + Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!"); + final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class); + + String rd = vrfTableKey.getRouteDistinguisher(); + VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd); + Preconditions.checkNotNull(vpnInstance, + "Vpn Instance not available with rd " + vrfTableKey.getRouteDistinguisher()); + Preconditions.checkNotNull(vpnInstance.getVpnId(), + "Vpn Instance with vrf " + vpnInstance.getVrfId() + " has null vpnId!"); + + String vpnUuid = vpnInstance.getVpnInstanceName(); + Preconditions.checkArgument(vpnUuid != null && !vpnUuid.isEmpty(), + "Could not find suitable VPN UUID for Route-Distinguisher=" + rd); + + // if the new vrfEntry has been learned by Quagga BGP, its necessary to check if it's + // there an interVpnLink for the involved vpn in order to make learn the new route to + // the other part of the inter-vpn-link. + + // For leaking, we need the InterVpnLink to be active. For removal, we just need a InterVpnLink. + Optional interVpnLink = + (addOrRemove == NwConstants.ADD_FLOW) ? FibUtil.getActiveInterVpnLinkFromRd(broker, rd) + : FibUtil.getInterVpnLinkByRd(broker, rd); + if ( !interVpnLink.isPresent() ) { + LOG.debug("Could not find an InterVpnLink for Route-Distinguisher={}", rd); + return; + } + + // Ok, at this point everything is ready for the leaking/removal... but should it be performed? + // For removal, we remove all leaked routes, but we only leak a route if the corresponding flag is enabled. + boolean proceed = (addOrRemove == NwConstants.DEL_FLOW ) + || ( RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP + && interVpnLink.get().isBgpRoutesLeaking() ); + + if ( proceed ) { + String theOtherVpnId = ( interVpnLink.get().getFirstEndpoint().getVpnUuid().getValue().equals(vpnUuid) ) + ? interVpnLink.get().getSecondEndpoint().getVpnUuid().getValue() + : vpnUuid; + + String dstVpnRd = FibUtil.getVpnRd(broker, theOtherVpnId); + String endpointIp = vrfEntry.getNextHopAddressList().get(0); + + InstanceIdentifier vrfEntryIidInOtherVpn = + InstanceIdentifier.builder(FibEntries.class) + .child(VrfTables.class, new VrfTablesKey(dstVpnRd)) + .child(VrfEntry.class, new VrfEntryKey(vrfEntry.getDestPrefix())) + .build(); + if ( addOrRemove == NwConstants.ADD_FLOW ) { + LOG.info("Leaking route (destination={}, nexthop={}) from Vrf={} to Vrf={}", + vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), rd, dstVpnRd); + String key = rd + FibConstants.SEPARATOR + vrfEntry.getDestPrefix(); + long label = FibUtil.getUniqueId(idManager, FibConstants.VPN_IDPOOL_NAME, key); + VrfEntry newVrfEntry = new VrfEntryBuilder(vrfEntry).setNextHopAddressList(Arrays.asList(endpointIp)) + .setLabel(label) + .setOrigin(RouteOrigin.INTERVPN.getValue()) + .build(); + MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryIidInOtherVpn, newVrfEntry); + } else { + LOG.info("Removing leaked vrfEntry={}", vrfEntryIidInOtherVpn.toString()); + MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryIidInOtherVpn); } } } - } - private void installSubnetRouteInFib(BigInteger dpnId, long elanTag, String rd, - long vpnId, VrfEntry vrfEntry){ - List instructions = new ArrayList<>(); + private void installSubnetRouteInFib(final BigInteger dpnId, final long elanTag, final String rd, + final long vpnId, final VrfEntry vrfEntry, WriteTransaction tx){ + Boolean wrTxPresent = true; + if (tx == null) { + wrTxPresent = false; + tx = broker.newWriteOnlyTransaction(); + } + final List instructions = new ArrayList(); + BigInteger subnetRouteMeta = ((BigInteger.valueOf(elanTag)).shiftLeft(32)).or((BigInteger.valueOf(vpnId))); + instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { subnetRouteMeta, MetaDataUtil.METADATA_MASK_SUBNET_ROUTE })); + instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_SUBNET_ROUTE_TABLE })); + makeConnectedRoute(dpnId,vpnId,vrfEntry,rd,instructions,NwConstants.ADD_FLOW, tx); - instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { (BigInteger.valueOf(elanTag)).shiftLeft(24), MetaDataUtil.METADATA_MASK_SERVICE })); - instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_SUBNET_ROUTE_TABLE })); - makeConnectedRoute(dpnId,vpnId,vrfEntry,rd,instructions,NwConstants.ADD_FLOW); + List actionsInfos = new ArrayList(); + // reinitialize instructions list for LFIB Table + final List LFIBinstructions = new ArrayList(); - List actionsInfos = new ArrayList<>(); - // reinitialize instructions list for LFIB Table - instructions = new ArrayList<>(); + actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{})); + LFIBinstructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos)); + LFIBinstructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { subnetRouteMeta, MetaDataUtil.METADATA_MASK_SUBNET_ROUTE })); + LFIBinstructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_SUBNET_ROUTE_TABLE })); - actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{})); - instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos)); - instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { (BigInteger.valueOf(elanTag)).shiftLeft(24), MetaDataUtil.METADATA_MASK_SERVICE })); - instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_SUBNET_ROUTE_TABLE })); + makeLFibTableEntry(dpnId,vrfEntry.getLabel(), LFIBinstructions, DEFAULT_FIB_FLOW_PRIORITY, NwConstants.ADD_FLOW, tx); + if(!wrTxPresent ){ + tx.submit(); + } + } - makeLFibTableEntry(dpnId,vrfEntry.getLabel(),instructions, - vrfEntry.getNextHopAddress(),NwConstants.ADD_FLOW); - // TODO makeTunnelTableEntry(); - } + private void installInterVpnRouteInLFib(final String rd, final VrfEntry vrfEntry) { + // INTERVPN routes are routes in a Vpn1 that have been leaked to Vpn2. In DC-GW, this Vpn2 route is pointing + // to a list of DPNs where Vpn2's VpnLink was instantiated. In these DPNs LFIB must be programmed so that the + // packet is commuted from Vpn2 to Vpn1. + Optional vpnNameOpc = FibUtil.getVpnNameFromRd(broker, rd); + if ( !vpnNameOpc.isPresent() ) { + LOG.warn("Could not find VpnInstanceName for Route-Distinguisher {}", rd); + return; + } - private Optional read(DataBroker broker, LogicalDatastoreType datastoreType, - InstanceIdentifier path) { + String vpnName = vpnNameOpc.get(); + List interVpnLinks = FibUtil.getAllInterVpnLinks(broker); + boolean interVpnLinkFound = false; + for ( InterVpnLink interVpnLink : interVpnLinks ) { + boolean vpnIs1stEndpoint = interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(vpnName); + boolean vpnIs2ndEndpoint = !vpnIs1stEndpoint + && interVpnLink.getSecondEndpoint().getVpnUuid().getValue().equals(vpnName); + if ( vpnIs1stEndpoint || vpnIs2ndEndpoint ) { + interVpnLinkFound = true; + + Optional vpnLinkState = FibUtil.getInterVpnLinkState(broker, interVpnLink.getName()); + if ( !vpnLinkState.isPresent() + || !vpnLinkState.get().getState().equals(InterVpnLinkState.State.Active) ) { + LOG.warn("InterVpnLink {}, linking VPN {} and {}, is not in Active state", + interVpnLink.getName(), interVpnLink.getFirstEndpoint().getVpnUuid().getValue(), + interVpnLink.getSecondEndpoint().getVpnUuid().getValue() ); + return; + } + + List targetDpns = + ( vpnIs1stEndpoint ) ? vpnLinkState.get().getFirstEndpointState().getDpId() + : vpnLinkState.get().getSecondEndpointState().getDpId(); + int lportTag = + ( vpnIs1stEndpoint ) ? vpnLinkState.get().getSecondEndpointState().getLportTag() + : vpnLinkState.get().getFirstEndpointState().getLportTag(); + + for ( BigInteger dpId : targetDpns ) { + List actionsInfos = Arrays.asList(new ActionInfo(ActionType.pop_mpls, new String[]{})); + + BigInteger[] metadata = new BigInteger[] { + MetaDataUtil.getMetaDataForLPortDispatcher(lportTag, FibConstants.L3VPN_SERVICE_IDENTIFIER), + MetaDataUtil.getMetaDataMaskForLPortDispatcher() + }; + List instructions = + Arrays.asList(new InstructionInfo(InstructionType.apply_actions, actionsInfos), + new InstructionInfo(InstructionType.write_metadata, metadata), + new InstructionInfo(InstructionType.goto_table, + new long[] { NwConstants.L3_INTERFACE_TABLE })); + + makeLFibTableEntry(dpId, vrfEntry.getLabel(), instructions, LFIB_INTERVPN_PRIORITY, + NwConstants.ADD_FLOW, null); + } + + break; + } + } + + if ( !interVpnLinkFound ) { + LOG.warn("VrfEntry=[prefix={} label={} nexthop={}] for VPN {} has origin INTERVPN but no InterVpnLink could be found", + vrfEntry.getDestPrefix(), vrfEntry.getLabel(), vrfEntry.getNextHopAddressList(), rd); + } + } - ReadOnlyTransaction tx = broker.newReadOnlyTransaction(); - Optional result = Optional.absent(); - try { - result = tx.read(datastoreType, path).get(); - } catch (Exception e) { - throw new RuntimeException(e); - } - return result; - } + private void installRouteInInterVpnLink(final InterVpnLink interVpnLink, final String vpnUuid, + final VrfEntry vrfEntry, long vpnTag) { + Preconditions.checkNotNull(interVpnLink, "InterVpnLink cannot be null"); + Preconditions.checkArgument(vrfEntry.getNextHopAddressList() != null + && vrfEntry.getNextHopAddressList().size() == 1); - private void makeSubnetRouteTableMissFlow(BigInteger dpnId, int addOrRemove) { - final BigInteger COOKIE_TABLE_MISS = new BigInteger("8000004", 16); - List actionsInfos = new ArrayList<>(); - List instructions = new ArrayList<>(); - actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[]{})); - instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos)); - List matches = new ArrayList<>(); - String flowRef = getFlowRef(dpnId, NwConstants.L3_SUBNET_ROUTE_TABLE, NwConstants.TABLE_MISS_FLOW); - FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_SUBNET_ROUTE_TABLE, flowRef, - NwConstants.TABLE_MISS_PRIORITY, "Subnet Route Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions); + // After having received a static route, we should check if the vpn is part of an inter-vpn-link. + // In that case, we should populate the FIB table of the VPN pointing to LPortDisptacher table + // using as metadata the LPortTag associated to that vpn in the inter-vpn-link. + Optional interVpnLinkState = FibUtil.getInterVpnLinkState(broker, interVpnLink.getName()); + if ( !interVpnLinkState.isPresent() ) { + LOG.warn("Could not find State for InterVpnLink {}", interVpnLink.getName()); + return; + } + if ( ! interVpnLinkState.get().getState().equals(InterVpnLinkState.State.Active) ) { + LOG.warn("Route to {} with nexthop={} cannot be installed because the interVpnLink {} is not active", + vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList().get(0), interVpnLink.getName()); + return; + } - if (addOrRemove == NwConstants.ADD_FLOW) { - mdsalManager.installFlow(flowEntity); - } else { - mdsalManager.removeFlow(flowEntity); - } - } - private Collection getDpnsForVpn(VpnInstanceOpDataEntry vpnInstance) { - Collection dpns = new HashSet<>(); - for(VpnToDpnList dpn : vpnInstance.getVpnToDpnList()) { - dpns.add(dpn.getDpnId()); - } + // Everything Ok + boolean vpnIsFirstEndpoint = isVpnFirstEndPoint(interVpnLink, vpnUuid); + List targetDpns = + vpnIsFirstEndpoint ? interVpnLinkState.get().getFirstEndpointState().getDpId() + : interVpnLinkState.get().getSecondEndpointState().getDpId(); - return dpns; - } + Integer otherEndpointlportTag = + vpnIsFirstEndpoint ? interVpnLinkState.get().getSecondEndpointState().getLportTag() + : interVpnLinkState.get().getFirstEndpointState().getLportTag(); - public BigInteger createLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) { - BigInteger localDpnId = BigInteger.ZERO; - Prefixes localNextHopInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix()); - String localNextHopIP = vrfEntry.getDestPrefix(); + BigInteger[] metadata = new BigInteger[] { + MetaDataUtil.getMetaDataForLPortDispatcher(otherEndpointlportTag, + FibConstants.L3VPN_SERVICE_IDENTIFIER), + MetaDataUtil.getMetaDataMaskForLPortDispatcher() + }; + List instructions = + Arrays.asList(new InstructionInfo(InstructionType.write_metadata, metadata).buildInstruction(0), + new InstructionInfo(InstructionType.goto_table, + new long[] { NwConstants.L3_INTERFACE_TABLE }).buildInstruction(1)); - if(localNextHopInfo == null) { - //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn - Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix()); - if (extra_route != null) { - localNextHopInfo = getPrefixToInterface(vpnId, extra_route.getNexthopIp() + "/32"); - localNextHopIP = extra_route.getNexthopIp() + "/32"; + String values[] = vrfEntry.getDestPrefix().split("/"); + String destPrefixIpAddress = values[0]; + int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]); + + List matches = new ArrayList<>(); + matches.add(new MatchInfo(MatchFieldType.metadata, + new BigInteger[] { BigInteger.valueOf(vpnTag), + MetaDataUtil.METADATA_MASK_VRFID })); + matches.add(new MatchInfo(MatchFieldType.eth_type, new long[] { NwConstants.ETHTYPE_IPV4 })); + + if (prefixLength != 0) { + matches.add(new MatchInfo(MatchFieldType.ipv4_destination, + new String[] { destPrefixIpAddress, Integer.toString(prefixLength) })); + } + + int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength; + String nextHop = vrfEntry.getNextHopAddressList().get(0); + String flowRef = getInterVpnFibFlowRef(interVpnLink.getName(), vrfEntry.getDestPrefix(), nextHop); + Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_FIB_TABLE, flowRef, priority, flowRef, 0, 0, + COOKIE_VM_FIB_TABLE, matches, instructions); + + for ( BigInteger dpId : targetDpns ) { + mdsalManager.installFlow(dpId, flowEntity); } } - if(localNextHopInfo != null) { - localDpnId = localNextHopInfo.getDpnId(); - long groupId = nextHopManager.createLocalNextHop(vpnId, localDpnId, localNextHopInfo.getVpnInterfaceName(), localNextHopIP); + private void removeRouteFromInterVpnLink(final InterVpnLink interVpnLink, final String vpnUuid, + final VrfEntry vrfEntry) { - List actionsInfos = new ArrayList<>(); - List instructions = new ArrayList<>(); + Preconditions.checkNotNull(interVpnLink, "InterVpnLink cannot be null"); + Preconditions.checkArgument(vrfEntry.getNextHopAddressList() != null + && vrfEntry.getNextHopAddressList().size() == 1); - actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId)})); - instructions.add(new InstructionInfo(InstructionType.write_actions,actionsInfos)); - makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW); + Optional interVpnLinkState = FibUtil.getInterVpnLinkState(broker, interVpnLink.getName()); + if ( !interVpnLinkState.isPresent() ) { + LOG.warn("Could not find State for InterVpnLink {}", interVpnLink.getName()); + return; + } - actionsInfos= new ArrayList<>(); - instructions= new ArrayList<>(); - actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{})); - actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) })); - instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos)); - makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), instructions, vrfEntry.getNextHopAddress(), NwConstants.ADD_FLOW); + // Everything Ok + boolean vpnIsFirstEndpoint = isVpnFirstEndPoint(interVpnLink, vpnUuid); + List targetDpns = + vpnIsFirstEndpoint ? interVpnLinkState.get().getFirstEndpointState().getDpId() + : interVpnLinkState.get().getSecondEndpointState().getDpId(); - LOG.debug("Installing tunnel table entry on dpn {} for interface {} with label {}", - localDpnId, localNextHopInfo.getVpnInterfaceName(), vrfEntry.getLabel()); - makeTunnelTableEntry(localDpnId, vrfEntry.getLabel(), groupId); + String nextHop = vrfEntry.getNextHopAddressList().get(0); + String flowRef = getInterVpnFibFlowRef(interVpnLink.getName(), vrfEntry.getDestPrefix(), nextHop); + FlowKey flowKey = new FlowKey(new FlowId(flowRef)); + Flow flow = new FlowBuilder().setKey(flowKey).setId(new FlowId(flowRef)).setTableId(NwConstants.L3_FIB_TABLE) + .setFlowName(flowRef).build(); - } - return localDpnId; - } + for ( BigInteger dpId : targetDpns ) { + mdsalManager.removeFlow(dpId, flow); + } - private void makeTunnelTableEntry(BigInteger dpId, long label, long groupId/*String egressInterfaceName*/) { - List actionsInfos = new ArrayList<>(); - actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) })); + } + private boolean isVpnFirstEndPoint(InterVpnLink interVpnLink, String vpnName) { + return interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(vpnName); + } - createTerminatingServiceActions(dpId, (int)label, actionsInfos); + private Optional read(DataBroker broker, LogicalDatastoreType datastoreType, + InstanceIdentifier path) { - LOG.debug("Terminating service Entry for dpID {} : label : {} egress : {} installed successfully", - dpId, label, groupId); - } + ReadOnlyTransaction tx = broker.newReadOnlyTransaction(); - public void createTerminatingServiceActions( BigInteger destDpId, int label, List actionsInfos) { - List mkMatches = new ArrayList<>(); + Optional result = Optional.absent(); + try { + result = tx.read(datastoreType, path).get(); + } catch (Exception e) { + throw new RuntimeException(e); + } - LOG.info("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", destDpId , label,actionsInfos); + return result; + } - // Matching metadata - // FIXME vxlan vni bit set is not working properly with OVS.need to revisit - mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)})); + private void makeSubnetRouteTableMissFlow(BigInteger dpnId, int addOrRemove) { + final BigInteger COOKIE_TABLE_MISS = new BigInteger("8000004", 16); + List actionsInfos = new ArrayList(); + List instructions = new ArrayList(); + actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[]{})); + instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos)); + List matches = new ArrayList(); + String flowRef = getTableMissFlowRef(dpnId, NwConstants.L3_SUBNET_ROUTE_TABLE, NwConstants.TABLE_MISS_FLOW); + FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_SUBNET_ROUTE_TABLE, flowRef, + NwConstants.TABLE_MISS_PRIORITY, "Subnet Route Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions); - List mkInstructions = new ArrayList<>(); - mkInstructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos)); + if (addOrRemove == NwConstants.ADD_FLOW) { + mdsalManager.installFlow(flowEntity); + } else { + mdsalManager.removeFlow(flowEntity); + } + } - FlowEntity terminatingServiceTableFlowEntity = MDSALUtil.buildFlowEntity(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE, - getFlowRef(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,label), 5, String.format("%s:%d","TST Flow Entry ",label), - 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(label)),mkMatches, mkInstructions); + private Collection getDpnsForVpn(VpnInstanceOpDataEntry vpnInstance) { + Collection dpns = new HashSet<>(); + for(VpnToDpnList dpn : vpnInstance.getVpnToDpnList()) { + dpns.add(dpn.getDpnId()); + } - mdsalManager.installFlow(terminatingServiceTableFlowEntity); - } + return dpns; + } - private void removeTunnelTableEntry(BigInteger dpId, long label) { - FlowEntity flowEntity; - LOG.info("remove terminatingServiceActions called with DpnId = {} and label = {}", dpId , label); - List mkMatches = new ArrayList<>(); - // Matching metadata - mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)})); - flowEntity = MDSALUtil.buildFlowEntity(dpId, - NwConstants.INTERNAL_TUNNEL_TABLE, - getFlowRef(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, (int)label), - 5, String.format("%s:%d","TST Flow Entry ",label), 0, 0, - COOKIE_TUNNEL.add(BigInteger.valueOf(label)), mkMatches, null); - mdsalManager.removeFlow(flowEntity); - LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully",dpId, label); - } + private List createLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) { + List returnLocalDpnId = new ArrayList(); + Prefixes localNextHopInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix()); + String localNextHopIP = vrfEntry.getDestPrefix(); + + if (localNextHopInfo == null) { + //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn + Extraroute extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix()); + if (extraRoute != null) { + //FIXME:Suraj +// for (String nextHopIp : extraRoute.getNexthopIpList()) { +// LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp); +// if (nextHopIp != null) { +// localNextHopInfo = getPrefixToInterface(vpnId, nextHopIp + "/32"); +// localNextHopIP = nextHopIp + "/32"; +// BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP, vpnId, rd, +// vrfEntry); +// returnLocalDpnId.add(dpnId); +// } +// } + } + } else { + BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP, vpnId, rd, vrfEntry); + returnLocalDpnId.add(dpnId); + } - public BigInteger deleteLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) { - BigInteger localDpnId = BigInteger.ZERO; - boolean isExtraRoute = false; - VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix()); - String localNextHopIP = vrfEntry.getDestPrefix(); + return returnLocalDpnId; + } - if(localNextHopInfo == null) { - //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn - Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix()); - if (extra_route != null) { - localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, extra_route.getNexthopIp() + "/32"); - localNextHopIP = extra_route.getNexthopIp() + "/32"; - isExtraRoute = true; + private BigInteger checkCreateLocalFibEntry(Prefixes localNextHopInfo, String localNextHopIP, final Long vpnId, final String rd, + final VrfEntry vrfEntry){ + if (localNextHopInfo != null) { + final BigInteger dpnId = localNextHopInfo.getDpnId(); + final long groupId = nextHopManager.createLocalNextHop(vpnId, dpnId, localNextHopInfo.getVpnInterfaceName(), localNextHopIP); + + List actionsInfos = + Arrays.asList(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId)})); + final List instructions = + Arrays.asList(new InstructionInfo(InstructionType.write_actions, actionsInfos)); + + actionsInfos = Arrays.asList(new ActionInfo(ActionType.pop_mpls, new String[]{}), + new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }) ); + final List lfibinstructions = Arrays.asList(new InstructionInfo(InstructionType.write_actions, actionsInfos)); + + LOG.debug("Installing tunnel table entry on dpn {} for interface {} with label {}", + dpnId, localNextHopInfo.getVpnInterfaceName(), vrfEntry.getLabel()); + + DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance(); + dataStoreCoordinator.enqueueJob("FIB"+vpnId.toString()+dpnId.toString()+vrfEntry.getDestPrefix(), + new Callable>>() { + @Override + public List> call() throws Exception { + WriteTransaction tx = broker.newWriteOnlyTransaction(); + + makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx); + makeLFibTableEntry(dpnId, vrfEntry.getLabel(), lfibinstructions , DEFAULT_FIB_FLOW_PRIORITY, NwConstants.ADD_FLOW, tx); + makeTunnelTableEntry(dpnId, vrfEntry.getLabel(), groupId, tx); + List> futures = new ArrayList<>(); + futures.add(tx.submit()); + return futures; + } + }); + return dpnId; } + return BigInteger.ZERO; } + private void makeTunnelTableEntry(BigInteger dpId, long label, long groupId/*String egressInterfaceName*/, + WriteTransaction tx) { + List actionsInfos = new ArrayList(); + actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) })); + + + createTerminatingServiceActions(dpId, (int)label, actionsInfos, tx); + + LOG.debug("Terminating service Entry for dpID {} : label : {} egress : {} installed successfully", + dpId, label, groupId); + } + + public void createTerminatingServiceActions( BigInteger destDpId, int label, List actionsInfos, + WriteTransaction tx) { + List mkMatches = new ArrayList<>(); + + LOG.info("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", destDpId , label,actionsInfos); + + // Matching metadata + // FIXME vxlan vni bit set is not working properly with OVS.need to revisit + mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)})); - if(localNextHopInfo != null) { - localDpnId = localNextHopInfo.getDpnId(); - Prefixes prefix = getPrefixToInterface(vpnId, isExtraRoute ? localNextHopIP : vrfEntry.getDestPrefix()); - makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, null /* invalid */, - NwConstants.DEL_FLOW); - makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), null /* invalid */, - vrfEntry.getNextHopAddress(), NwConstants.DEL_FLOW); - removeTunnelTableEntry(localDpnId, vrfEntry.getLabel()); - deleteLocalAdjacency(localDpnId, vpnId, localNextHopIP); + List mkInstructions = new ArrayList<>(); + mkInstructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos)); + + FlowEntity terminatingServiceTableFlowEntity = MDSALUtil.buildFlowEntity(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE, + getTableMissFlowRef(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,label), 5, String.format("%s:%d","TST Flow Entry ",label), + 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(label)),mkMatches, mkInstructions); + + FlowKey flowKey = new FlowKey( new FlowId(terminatingServiceTableFlowEntity.getFlowId()) ); + + FlowBuilder flowbld = terminatingServiceTableFlowEntity.getFlowBuilder(); + + Node nodeDpn = buildDpnNode(terminatingServiceTableFlowEntity.getDpnId()); + InstanceIdentifier flowInstanceId = InstanceIdentifier.builder(Nodes.class) + .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class) + .child(Table.class, new TableKey(terminatingServiceTableFlowEntity.getTableId())).child(Flow.class,flowKey).build(); + tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flowbld.build(),true ); } - return localDpnId; - } - private InstanceIdentifier getPrefixToInterfaceIdentifier(Long vpnId, String ipPrefix) { - return InstanceIdentifier.builder(PrefixToInterface.class) - .child(VpnIds.class, new VpnIdsKey(vpnId)).child(Prefixes.class, new PrefixesKey(ipPrefix)).build(); - } + private void removeTunnelTableEntry(BigInteger dpId, long label, WriteTransaction tx) { + FlowEntity flowEntity; + LOG.info("remove terminatingServiceActions called with DpnId = {} and label = {}", dpId , label); + List mkMatches = new ArrayList<>(); + // Matching metadata + mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)})); + flowEntity = MDSALUtil.buildFlowEntity(dpId, + NwConstants.INTERNAL_TUNNEL_TABLE, + getTableMissFlowRef(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, (int)label), + 5, String.format("%s:%d","TST Flow Entry ",label), 0, 0, + COOKIE_TUNNEL.add(BigInteger.valueOf(label)), mkMatches, null); + Node nodeDpn = buildDpnNode(flowEntity.getDpnId()); + FlowKey flowKey = new FlowKey(new FlowId(flowEntity.getFlowId())); + InstanceIdentifier flowInstanceId = InstanceIdentifier.builder(Nodes.class) + .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class) + .child(Table.class, new TableKey(flowEntity.getTableId())).child(Flow.class, flowKey).build(); + + tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId); + LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully", dpId, label); + } - private Prefixes getPrefixToInterface(Long vpnId, String ipPrefix) { - Optional localNextHopInfoData = - FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, getPrefixToInterfaceIdentifier(vpnId, ipPrefix)); - return localNextHopInfoData.isPresent() ? localNextHopInfoData.get() : null; - } + /** + * Delete local FIB entry + * @param vpnId + * @param rd + * @param vrfEntry + * @return + */ + public List deleteLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) { + List returnLocalDpnId = new ArrayList<>(); + BigInteger localDpnId = BigInteger.ZERO; + VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix()); + String localNextHopIP = vrfEntry.getDestPrefix(); + + if (localNextHopInfo == null) { + //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn + Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix()); + if (extra_route != null) { + //FIXME:Suraj +// for (String nextHopIp : extra_route.getNexthopIpList()) { +// LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp); +// if (nextHopIp != null) { +// localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, nextHopIp + "/32"); +// localNextHopIP = nextHopIp + "/32"; +// BigInteger dpnId = checkDeleteLocalFibEntry(localNextHopInfo, localNextHopIP, localDpnId, +// vpnId, rd, vrfEntry, true /*isExtraRoute*/); +// returnLocalDpnId.add(dpnId); +// } +// } + } + } else { + BigInteger dpnId = checkDeleteLocalFibEntry(localNextHopInfo, localNextHopIP, localDpnId, + vpnId, rd, vrfEntry, false /*isExtraRoute*/); + returnLocalDpnId.add(dpnId); + } + + return returnLocalDpnId; + } + + private BigInteger checkDeleteLocalFibEntry(VpnNexthop localNextHopInfo, final String localNextHopIP, + final BigInteger localDpnId, final Long vpnId, final String rd, + final VrfEntry vrfEntry, final boolean isExtraRoute) { + if (localNextHopInfo != null) { + final BigInteger dpnId = localNextHopInfo.getDpnId();; + DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance(); + dataStoreCoordinator.enqueueJob("FIB"+vpnId.toString()+dpnId.toString()+vrfEntry.getDestPrefix(), + new Callable>>() { + @Override + public List> call() throws Exception { + WriteTransaction tx = broker.newWriteOnlyTransaction(); + + Prefixes prefix = getPrefixToInterface(vpnId, isExtraRoute ? localNextHopIP : vrfEntry.getDestPrefix()); + makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null /* instructions */, + NwConstants.DEL_FLOW, tx); + makeLFibTableEntry(dpnId, vrfEntry.getLabel(), null /* instructions */, + DEFAULT_FIB_FLOW_PRIORITY, NwConstants.DEL_FLOW, tx); + removeTunnelTableEntry(dpnId, vrfEntry.getLabel(), tx); + List> futures = new ArrayList<>(); + futures.add(tx.submit()); + return futures; + } + }); + //TODO: verify below adjacency call need to be optimized (?) + deleteLocalAdjacency(localDpnId, vpnId, localNextHopIP); + } + return localDpnId; + } + + + private InstanceIdentifier getPrefixToInterfaceIdentifier(Long vpnId, String ipPrefix) { + return InstanceIdentifier.builder(PrefixToInterface.class) + .child(VpnIds.class, new VpnIdsKey(vpnId)).child(Prefixes.class, new PrefixesKey(ipPrefix)).build(); + } + + private Prefixes getPrefixToInterface(Long vpnId, String ipPrefix) { + Optional localNextHopInfoData = + FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, getPrefixToInterfaceIdentifier(vpnId, ipPrefix)); + return localNextHopInfoData.isPresent() ? localNextHopInfoData.get() : null; + } private InstanceIdentifier getVpnToExtrarouteIdentifier(String vrfId, String ipPrefix) { return InstanceIdentifier.builder(VpnToExtraroute.class) @@ -420,117 +837,106 @@ public class FibManager extends AbstractDataChangeListener implements } - private Class getTunnelType(String ifName) { + private Class getTunnelType(String ifName) { try { Future> result = interfaceManager.getTunnelType( - new GetTunnelTypeInputBuilder().setIntfName(ifName).build()); - RpcResult rpcResult = result.get(); - if(!rpcResult.isSuccessful()) { - LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors()); - } else { - return rpcResult.getResult().getTunnelType(); - } - - } catch (InterruptedException | ExecutionException e) { - LOG.warn("Exception when getting tunnel interface Id for tunnel type {}", e); - } - - return null; - - } - private void createRemoteFibEntry(final BigInteger localDpnId, final BigInteger remoteDpnId, - final long vpnId, final VrfTablesKey vrfTableKey, - final VrfEntry vrfEntry) { - String rd = vrfTableKey.getRouteDistinguisher(); - LOG.debug("createremotefibentry: adding route {} for rd {}", vrfEntry.getDestPrefix(), rd); - /********************************************/ - String tunnelInterface = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry, rd); - if(tunnelInterface == null) { - LOG.error("Could not get interface for nexthop: {} in vpn {}", - vrfEntry.getNextHopAddress(), rd); - LOG.warn("Failed to add Route: {} in vpn: {}", - vrfEntry.getDestPrefix(), rd); - return; - } - List actionInfos = new ArrayList<>(); - Class tunnel_type = getTunnelType(tunnelInterface); - if (tunnel_type.equals(TunnelTypeMplsOverGre.class)) { - LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix()); - actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[] { null })); - actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label, new String[] { Long.toString(vrfEntry.getLabel())})); - } else { - int label = vrfEntry.getLabel().intValue(); - BigInteger tunnelId; - // FIXME vxlan vni bit set is not working properly with OVS.need to revisit - if(tunnel_type.equals(TunnelTypeVxlan.class)) { - tunnelId = BigInteger.valueOf(label); - } else { - tunnelId = BigInteger.valueOf(label); + new GetTunnelTypeInputBuilder().setIntfName(ifName).build()); + RpcResult rpcResult = result.get(); + if(!rpcResult.isSuccessful()) { + LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors()); + } else { + return rpcResult.getResult().getTunnelType(); + } + + } catch (InterruptedException | ExecutionException e) { + LOG.warn("Exception when getting tunnel interface Id for tunnel type {}", e); } - LOG.debug("adding set tunnel id action for label {}", label); - actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[]{ - tunnelId})); + + return null; + } - actionInfos.addAll(nextHopManager.getEgressActionsForInterface(tunnelInterface)); - List instructions= new ArrayList<>(); - instructions.add(new InstructionInfo(InstructionType.write_actions, actionInfos)); -/* - List actionInfos = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry); - if(actionInfos == null) { - LOG.error("Could not get nexthop group id for nexthop: {} in vpn {}", - vrfEntry.getNextHopAddress(), rd); - LOG.warn("Failed to add Route: {} in vpn: {}", - vrfEntry.getDestPrefix(), rd); - return; - } - BigInteger dpnId = nextHopManager.getDpnForPrefix(vpnId, vrfEntry.getDestPrefix()); - if(dpnId == null) { - //This route may be extra route... try to query with nexthop Ip - LOG.debug("Checking for extra route to install remote fib entry {}", vrfEntry.getDestPrefix()); - dpnId = nextHopManager.getDpnForPrefix(vpnId, vrfEntry.getNextHopAddress() + "/32"); - } - if(dpnId == null) { - LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix()); - actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[] { null })); - actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label, new String[] { Long.toString(vrfEntry.getLabel())})); - } else { - int label = vrfEntry.getLabel().intValue(); - LOG.debug("adding set tunnel id action for label {}", label); - actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] { - MetaDataUtil.getTunnelIdWithValidVniBitAndVniSet(label), - MetaDataUtil.METADA_MASK_VALID_TUNNEL_ID_BIT_AND_TUNNEL_ID })); - } -**/ - makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW); - LOG.debug("Successfully added fib entry for prefix {} in vpn {} ", vrfEntry.getDestPrefix(), vpnId); - } - - private void delIntfFromDpnToVpnList(long vpnId, BigInteger dpnId, String intfName, String rd) { - InstanceIdentifier id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId); - Optional dpnInVpn = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id); - if (dpnInVpn.isPresent()) { - List vpnInterfaces = dpnInVpn.get().getVpnInterfaces(); - org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces - currVpnInterface = new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesBuilder().setInterfaceName(intfName).build(); - - if (vpnInterfaces.remove(currVpnInterface)) { - if (vpnInterfaces.isEmpty()) { - LOG.trace("Last vpn interface {} on dpn {} for vpn {}. Clean up fib in dpn", intfName, dpnId, rd); - FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id); - cleanUpDpnForVpn(dpnId, vpnId, rd); - } else { - LOG.trace("Delete vpn interface {} from dpn {} to vpn {} list.", intfName, dpnId, rd); - FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id.child( - org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data - .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class, - new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesKey(intfName))); - } - } - } - } - - private void cleanUpOpDataForFib(Long vpnId, String rd, final VrfEntry vrfEntry) { + private void createRemoteFibEntry(final BigInteger remoteDpnId, final long vpnId, final VrfTablesKey vrfTableKey, + final VrfEntry vrfEntry, WriteTransaction tx) { + Boolean wrTxPresent = true; + if (tx == null) { + wrTxPresent = false; + tx = broker.newWriteOnlyTransaction(); + } + String rd = vrfTableKey.getRouteDistinguisher(); + LOG.debug("createremotefibentry: adding route {} for rd {} with transaction ", vrfEntry.getDestPrefix(), rd); + /********************************************/ + List tunnelInterfaceList = resolveAdjacency(remoteDpnId, vpnId, vrfEntry, rd); + + if (tunnelInterfaceList.isEmpty()) { + LOG.error("Could not get interface for nexthop: {} in vpn {}", + vrfEntry.getNextHopAddressList(), rd); + LOG.warn("Failed to add Route: {} in vpn: {}", + vrfEntry.getDestPrefix(), rd); + return; + } + + for (String tunnelInterface : tunnelInterfaceList) { + List instructions = new ArrayList<>(); + List actionInfos = new ArrayList<>(); + Class tunnel_type = getTunnelType(tunnelInterface); + if (tunnel_type.equals(TunnelTypeMplsOverGre.class)) { + LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix()); + actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[]{null})); + actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label, new String[]{Long.toString(vrfEntry.getLabel())})); + } else { + int label = vrfEntry.getLabel().intValue(); + BigInteger tunnelId; + // FIXME vxlan vni bit set is not working properly with OVS.need to revisit + if (tunnel_type.equals(TunnelTypeVxlan.class)) { + tunnelId = BigInteger.valueOf(label); + } else { + tunnelId = BigInteger.valueOf(label); + } + + LOG.debug("adding set tunnel id action for label {}", label); + actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[]{tunnelId})); + } + List egressActions = nextHopManager.getEgressActionsForInterface(tunnelInterface); + if(egressActions.isEmpty()){ + LOG.error("Failed to retrieve egress action for prefix {} nextHop {} interface {}. Aborting remote FIB entry creation.", vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), tunnelInterface); + return; + } + actionInfos.addAll(egressActions); + instructions.add(new InstructionInfo(InstructionType.write_actions, actionInfos)); + makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx); + } + if(!wrTxPresent ){ + tx.submit(); + } + LOG.debug("Successfully added FIB entry for prefix {} in vpnId {}", vrfEntry.getDestPrefix(), vpnId); + } + + private void delIntfFromDpnToVpnList(long vpnId, BigInteger dpnId, String intfName, String rd) { + InstanceIdentifier id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId); + Optional dpnInVpn = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id); + if (dpnInVpn.isPresent()) { + List vpnInterfaces = dpnInVpn.get().getVpnInterfaces(); + org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces + currVpnInterface = new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesBuilder().setInterfaceName(intfName).build(); + + if (vpnInterfaces.remove(currVpnInterface)) { + if (vpnInterfaces.isEmpty()) { + LOG.trace("Last vpn interface {} on dpn {} for vpn {}. Clean up fib in dpn", intfName, dpnId, rd); + FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id); + cleanUpDpnForVpn(dpnId, vpnId, rd); + } else { + LOG.trace("Delete vpn interface {} from dpn {} to vpn {} list.", intfName, dpnId, rd); + FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id.child( + org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data + .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class, + new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesKey(intfName))); + } + } + } + } + + private void cleanUpOpDataForFib(Long vpnId, String rd, final VrfEntry vrfEntry) { /* Get interface info from prefix to interface mapping; Use the interface info to get the corresponding vpn interface op DS entry, remove the adjacency corresponding to this fib entry. @@ -539,370 +945,557 @@ public class FibManager extends AbstractDataChangeListener implements - prefix to interface entry - vpn interface op DS */ - LOG.debug("Cleanup of prefix {} in VPN {}", vrfEntry.getDestPrefix(), vpnId); - Prefixes prefixInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix()); - Extraroute extraRoute = null; - if (prefixInfo == null) { - extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix()); - if(extraRoute != null) { - prefixInfo = getPrefixToInterface(vpnId, extraRoute.getNexthopIp() + "/32"); - //clean up the vpn to extra route entry in DS - //FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, FibUtil.getVpnToExtrarouteIdentifier(rd, - // vrfEntry.getDestPrefix())); - } - } - if (prefixInfo == null) { - LOG.debug("Cleanup VPN Data Failed as unable to find prefix Info for prefix {}" , vrfEntry.getDestPrefix()); - return; //Don't have any info for this prefix (shouldn't happen); need to return - } - String ifName = prefixInfo.getVpnInterfaceName(); - synchronized (ifName.intern()) { - Optional optvpnInterface = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, FibUtil.getVpnInterfaceIdentifier(ifName)); - if (optvpnInterface.isPresent()) { - long associatedVpnId = FibUtil.getVpnId(broker, optvpnInterface.get().getVpnInstanceName()); - if (vpnId != associatedVpnId) { - LOG.warn("Prefixes {} are associated with different vpn instance with id : {} rather than {}", - vrfEntry.getDestPrefix(), associatedVpnId, vpnId); - LOG.trace("Releasing prefix label - rd {}, prefix {}", rd, vrfEntry.getDestPrefix()); - FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME, - FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix())); - LOG.warn("Not proceeding with Cleanup op data for prefix {}", vrfEntry.getDestPrefix()); - return; - } else { - LOG.debug("Processing cleanup of prefix {} associated with vpn {}", vrfEntry.getDestPrefix(), associatedVpnId); - } - } - if (extraRoute != null) { - FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, FibUtil.getVpnToExtrarouteIdentifier(rd, vrfEntry.getDestPrefix())); - } - Optional optAdjacencies = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, FibUtil.getAdjListPath(ifName)); - int numAdj = 0; - if (optAdjacencies.isPresent()) { - numAdj = optAdjacencies.get().getAdjacency().size(); - } - - //remove adjacency corr to prefix - if (numAdj > 1) { - LOG.trace("cleanUpOpDataForFib: remove adjacency for prefix: {} {}", vpnId, vrfEntry.getDestPrefix()); - FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, - FibUtil.getAdjacencyIdentifier(ifName, vrfEntry.getDestPrefix())); - } - - if ((numAdj - 1) == 0) { //there are no adjacencies left for this vpn interface, clean up - //clean up the vpn interface from DpnToVpn list - LOG.trace("Clean up vpn interface {} from dpn {} to vpn {} list.", ifName, prefixInfo.getDpnId(), rd); - FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, - FibUtil.getVpnInterfaceIdentifier(ifName)); - } - - FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME, - FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix())); - } - } - - private void deleteFibEntries(final InstanceIdentifier identifier, - final VrfEntry vrfEntry) { - final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class); - Preconditions.checkNotNull(vrfTableKey, "VrfTablesKey cannot be null or empty!"); - Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!"); - - String rd = vrfTableKey.getRouteDistinguisher(); - VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher()); - if (vpnInstance == null) { - LOG.debug("VPN Instance for rd {} is not available from VPN Op Instance Datastore", rd); - return; - } - Collection vpnToDpnList = vpnInstance.getVpnToDpnList(); - SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class); - if (subnetRoute != null) { + LOG.debug("Cleanup of prefix {} in VPN {}", vrfEntry.getDestPrefix(), vpnId); + Prefixes prefixInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix()); + Extraroute extraRoute = null; + if (prefixInfo == null) { + extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix()); + if(extraRoute != null) { + //FIXME:Suraj +// for (String nextHopIp : extraRoute.getNexthopIpList()) { + // LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp); +// + // if (nextHopIp != null) { + // prefixInfo = getPrefixToInterface(vpnId, nextHopIp + "/32"); + // checkCleanUpOpDataForFib(prefixInfo, vpnId, rd, vrfEntry, extraRoute); + // } + // } + } + } else { + checkCleanUpOpDataForFib(prefixInfo, vpnId, rd, vrfEntry, extraRoute); + } + } + + private void checkCleanUpOpDataForFib(Prefixes prefixInfo, Long vpnId, String rd, + final VrfEntry vrfEntry, Extraroute extraRoute) { + + if (prefixInfo == null) { + LOG.debug("Cleanup VPN Data Failed as unable to find prefix Info for prefix {}", vrfEntry.getDestPrefix()); + return; //Don't have any info for this prefix (shouldn't happen); need to return + } + + String ifName = prefixInfo.getVpnInterfaceName(); + synchronized (ifName.intern()) { + Optional optvpnInterface = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, + FibUtil.getVpnInterfaceIdentifier(ifName)); + if (optvpnInterface.isPresent()) { + long associatedVpnId = FibUtil.getVpnId(broker, optvpnInterface.get().getVpnInstanceName()); + if (vpnId != associatedVpnId) { + LOG.warn("Prefixes {} are associated with different vpn instance with id : {} rather than {}", + vrfEntry.getDestPrefix(), associatedVpnId, vpnId); + LOG.trace("Releasing prefix label - rd {}, prefix {}", rd, vrfEntry.getDestPrefix()); + FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME, + FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix())); + LOG.warn("Not proceeding with Cleanup op data for prefix {}", vrfEntry.getDestPrefix()); + return; + } else { + LOG.debug("Processing cleanup of prefix {} associated with vpn {}", + vrfEntry.getDestPrefix(), associatedVpnId); + } + } + if (extraRoute != null) { + FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, + FibUtil.getVpnToExtrarouteIdentifier(rd, vrfEntry.getDestPrefix())); + } + Optional optAdjacencies = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, + FibUtil.getAdjListPath(ifName)); + int numAdj = 0; + if (optAdjacencies.isPresent()) { + numAdj = optAdjacencies.get().getAdjacency().size(); + } + //remove adjacency corr to prefix + if (numAdj > 1) { + LOG.trace("cleanUpOpDataForFib: remove adjacency for prefix: {} {}", vpnId, vrfEntry.getDestPrefix()); + FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, + FibUtil.getAdjacencyIdentifier(ifName, vrfEntry.getDestPrefix())); + } + if ((numAdj - 1) == 0) { //there are no adjacencies left for this vpn interface, clean up + //clean up the vpn interface from DpnToVpn list + LOG.trace("Clean up vpn interface {} from dpn {} to vpn {} list.", ifName, prefixInfo.getDpnId(), rd); + FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, + FibUtil.getVpnInterfaceIdentifier(ifName)); + } + FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME, + FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix())); + } + } + + + private void deleteFibEntries(final InstanceIdentifier identifier, final VrfEntry vrfEntry) { + final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class); + + final String rd = vrfTableKey.getRouteDistinguisher(); + final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher()); + if (vpnInstance == null) { + LOG.debug("VPN Instance for rd {} is not available from VPN Op Instance Datastore", rd); + return; + } + final Collection vpnToDpnList = vpnInstance.getVpnToDpnList(); + SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class); + if (subnetRoute != null) { + if (vpnToDpnList != null) { + DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance(); + dataStoreCoordinator.enqueueJob("FIB" + rd.toString() + vrfEntry.getDestPrefix(), + new Callable>>() { + @Override + public List> call() throws Exception { + WriteTransaction tx = broker.newWriteOnlyTransaction(); + + for (final VpnToDpnList curDpn : vpnToDpnList) { + + makeConnectedRoute(curDpn.getDpnId(), vpnInstance.getVpnId(), vrfEntry, + vrfTableKey.getRouteDistinguisher(), null, NwConstants.DEL_FLOW, tx); + makeLFibTableEntry(curDpn.getDpnId(), vrfEntry.getLabel(), null, + DEFAULT_FIB_FLOW_PRIORITY, NwConstants.DEL_FLOW, tx); + } + List> futures = new ArrayList<>(); + futures.add(tx.submit()); + return futures; + } + }); + } + FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME, + FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix())); + LOG.trace("deleteFibEntries: Released subnetroute label {} for rd {} prefix {}", vrfEntry.getLabel(), rd, + vrfEntry.getDestPrefix()); + return; + } + + final List localDpnIdList = deleteLocalFibEntry(vpnInstance.getVpnId(), + vrfTableKey.getRouteDistinguisher(), vrfEntry); if (vpnToDpnList != null) { - for (VpnToDpnList curDpn : vpnToDpnList) { - makeConnectedRoute(curDpn.getDpnId(), vpnInstance.getVpnId(), vrfEntry, vrfTableKey - .getRouteDistinguisher(), null, NwConstants.DEL_FLOW); - makeLFibTableEntry(curDpn.getDpnId(), vrfEntry.getLabel(), null, - vrfEntry.getNextHopAddress(), NwConstants.DEL_FLOW); + DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance(); + dataStoreCoordinator.enqueueJob("FIB" + rd.toString() + vrfEntry.getDestPrefix(), + new Callable>>() { + @Override + public List> call() throws Exception { + WriteTransaction tx = broker.newWriteOnlyTransaction(); + + if (localDpnIdList.size() <= 0) { + for (VpnToDpnList curDpn : vpnToDpnList) { + deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx); + } + } else { + for (BigInteger localDpnId : localDpnIdList) { + for (VpnToDpnList curDpn : vpnToDpnList) { + if (!curDpn.getDpnId().equals(localDpnId)) { + deleteRemoteRoute(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx); + } + } + } + } + List> futures = new ArrayList<>(); + futures.add(tx.submit()); + return futures; + } + }); + } + + //The flow/group entry has been deleted from config DS; need to clean up associated operational + //DS entries in VPN Op DS, VpnInstanceOpData and PrefixToInterface to complete deletion + cleanUpOpDataForFib(vpnInstance.getVpnId(), vrfTableKey.getRouteDistinguisher(), vrfEntry); + + // Remove all fib entries configured due to interVpnLink, when nexthop is the opposite endPoint + // of the interVpnLink. + Optional vpnUuid = FibUtil.getVpnNameFromRd(broker, rd); + if ( vpnUuid.isPresent() ) { + Optional interVpnLink = FibUtil.getInterVpnLinkByVpnUuid(broker, vpnUuid.get()); + String routeNexthop = vrfEntry.getNextHopAddressList().get(0); + + if ( interVpnLink.isPresent() + && ( (interVpnLink.get().getFirstEndpoint().getVpnUuid().getValue().equals(vpnUuid.get()) + && interVpnLink.get().getSecondEndpoint().getIpAddress().getValue().equals(routeNexthop)) + || (interVpnLink.get().getSecondEndpoint().getVpnUuid().getValue().equals(vpnUuid.get() ) + && interVpnLink.get().getFirstEndpoint().getIpAddress().getValue().equals(routeNexthop)) ) ) { + // This is route that points to the other endpoint of an InterVpnLink + // In that case, we should look for the FIB table pointing to LPortDispatcher table and remove it. + removeRouteFromInterVpnLink(interVpnLink.get(), rd, vrfEntry); } } - FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME, - FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix())); - LOG.trace("deleteFibEntries: Released subnetroute label {} for rd {} prefix {}", vrfEntry.getLabel(), rd, - vrfEntry.getDestPrefix()); - return; - } - BigInteger localDpnId = deleteLocalFibEntry(vpnInstance.getVpnId(), - vrfTableKey.getRouteDistinguisher(), vrfEntry); - if (vpnToDpnList != null) { - for (VpnToDpnList curDpn : vpnToDpnList) { - if (!curDpn.getDpnId().equals(localDpnId)) { - deleteRemoteRoute(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry); + + } + + public void deleteRemoteRoute(final BigInteger localDpnId, final BigInteger remoteDpnId, + final long vpnId, final VrfTablesKey vrfTableKey, + final VrfEntry vrfEntry, WriteTransaction tx) { + + Boolean wrTxPresent = true; + if (tx == null) { + wrTxPresent = false; + tx = broker.newWriteOnlyTransaction(); + } + + LOG.debug("deleting route: prefix={}, vpnId={}", vrfEntry.getDestPrefix(), vpnId); + String rd = vrfTableKey.getRouteDistinguisher(); + + if(localDpnId != null) { + // localDpnId is not known when clean up happens for last vm for a vpn on a dpn + deleteFibEntry(remoteDpnId, vpnId, vrfEntry, rd, tx); + return; + } + + // below two reads are kept as is, until best way is found to identify dpnID + VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix()); + Extraroute extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix()); + + if (localNextHopInfo == null && extraRoute != null) { + // Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn + //FIXME:Suraj +// for (String nextHopIp : extraRoute.getNexthopIpList()) { + // localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, nextHopIp); + // checkDpnDeleteFibEntry(localNextHopInfo, remoteDpnId, vpnId, vrfEntry, rd, tx); + // } + } else { + checkDpnDeleteFibEntry(localNextHopInfo, remoteDpnId, vpnId, vrfEntry, rd, tx); + } + if(!wrTxPresent ){ + tx.submit(); + } + } + + private boolean checkDpnDeleteFibEntry(VpnNexthop localNextHopInfo, BigInteger remoteDpnId, long vpnId, + VrfEntry vrfEntry, String rd, WriteTransaction tx){ + boolean isRemoteRoute = true; + if (localNextHopInfo != null) { + isRemoteRoute = (!remoteDpnId.equals(localNextHopInfo.getDpnId())); + } + if (isRemoteRoute) { + deleteFibEntry(remoteDpnId, vpnId, vrfEntry, rd, tx); + return true; + } else { + LOG.debug("Did not delete FIB entry: rd={}, vrfEntry={}, as it is local to dpnId={}", rd, vrfEntry.getDestPrefix(), remoteDpnId); + return false; + } + } + + private void deleteFibEntry(BigInteger remoteDpnId, long vpnId, VrfEntry vrfEntry, String rd, WriteTransaction tx){ + makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW, tx); + LOG.debug("Successfully delete FIB entry: vrfEntry={}, vpnId={}", vrfEntry.getDestPrefix(), vpnId); + } + + private long get + (byte[] rawIpAddress) { + return (((rawIpAddress[0] & 0xFF) << (3 * 8)) + ((rawIpAddress[1] & 0xFF) << (2 * 8)) + + ((rawIpAddress[2] & 0xFF) << (1 * 8)) + (rawIpAddress[3] & 0xFF)) & 0xffffffffL; + } + + private void makeConnectedRoute(BigInteger dpId, long vpnId, VrfEntry vrfEntry, String rd, + List instructions, int addOrRemove, WriteTransaction tx) { + Boolean wrTxPresent = true; + if (tx == null) { + wrTxPresent = false; + tx = broker.newWriteOnlyTransaction(); + } + + LOG.trace("makeConnectedRoute: vrfEntry {}", vrfEntry); + String values[] = vrfEntry.getDestPrefix().split("/"); + String ipAddress = values[0]; + int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]); + if (addOrRemove == NwConstants.ADD_FLOW) { + LOG.debug("Adding route to DPN {} for rd {} prefix {} ", dpId, rd, vrfEntry.getDestPrefix()); + } else { + LOG.debug("Removing route from DPN {} for rd {} prefix {}", dpId, rd, vrfEntry.getDestPrefix()); + } + InetAddress destPrefix; + try { + destPrefix = InetAddress.getByName(ipAddress); + } catch (UnknownHostException e) { + LOG.error("Failed to get destPrefix for prefix {} ", vrfEntry.getDestPrefix(), e); + return; + } + + List matches = new ArrayList<>(); + + matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] { + BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID })); + + matches.add(new MatchInfo(MatchFieldType.eth_type, + new long[] { NwConstants.ETHTYPE_IPV4 })); + + if(prefixLength != 0) { + matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] { + destPrefix.getHostAddress(), Integer.toString(prefixLength)})); + } + int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength; + String flowRef = getFlowRef(dpId, NwConstants.L3_FIB_TABLE, rd, priority, destPrefix); + FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_FIB_TABLE, flowRef, priority, flowRef, 0, 0, + COOKIE_VM_FIB_TABLE, matches, instructions); + + Flow flow = flowEntity.getFlowBuilder().build(); + String flowId = flowEntity.getFlowId(); + FlowKey flowKey = new FlowKey( new FlowId(flowId)); + Node nodeDpn = buildDpnNode(dpId); + + InstanceIdentifier flowInstanceId = InstanceIdentifier.builder(Nodes.class) + .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class) + .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build(); + if (addOrRemove == NwConstants.ADD_FLOW) { + tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId,flow, true); + } else { + tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId); + } + + if(!wrTxPresent ){ + tx.submit(); + } + } + + //TODO: How to handle the below code, its a copy paste from MDSALManager.java + private Node buildDpnNode(BigInteger dpnId) { + NodeId nodeId = new NodeId("openflow:" + dpnId); + Node nodeDpn = new NodeBuilder().setId(nodeId).setKey(new NodeKey(nodeId)).build(); + + return nodeDpn; + } + + private void makeLFibTableEntry(BigInteger dpId, long label, List instructions, int priority, + int addOrRemove, WriteTransaction tx) { + Boolean wrTxPresent = true; + if (tx == null) { + wrTxPresent = false; + tx = broker.newWriteOnlyTransaction(); + } + + List matches = new ArrayList(); + matches.add(new MatchInfo(MatchFieldType.eth_type, + new long[] { NwConstants.ETHTYPE_MPLS_UC })); + matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(label)})); + + // Install the flow entry in L3_LFIB_TABLE + String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, label, priority); + + FlowEntity flowEntity; + flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_LFIB_TABLE, flowRef, priority, flowRef, 0, 0, + COOKIE_VM_LFIB_TABLE, matches, instructions); + Flow flow = flowEntity.getFlowBuilder().build(); + String flowId = flowEntity.getFlowId(); + FlowKey flowKey = new FlowKey( new FlowId(flowId)); + Node nodeDpn = buildDpnNode(dpId); + InstanceIdentifier flowInstanceId = InstanceIdentifier.builder(Nodes.class) + .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class) + .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build(); + + if (addOrRemove == NwConstants.ADD_FLOW) { + tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId,flow, true); + } else { + tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId); + } + if(!wrTxPresent ){ + tx.submit(); + } + LOG.debug("LFIB Entry for dpID {} : label : {} instructions {} modified successfully {}",dpId, label, instructions ); + } + + private void deleteLocalAdjacency(final BigInteger dpId, final long vpnId, final String ipAddress) { + LOG.trace("deleteLocalAdjacency called with dpid {}, vpnId{}, ipAddress {}",dpId, vpnId, ipAddress); + try { + nextHopManager.removeLocalNextHop(dpId, vpnId, ipAddress); + } catch (NullPointerException e) { + LOG.trace("", e); + } + } + + public void populateFibOnNewDpn(final BigInteger dpnId, final long vpnId, final String rd) { + LOG.trace("New dpn {} for vpn {} : populateFibOnNewDpn", dpnId, rd); + InstanceIdentifier id = buildVrfId(rd); + String lockOnDpnVpn = new String(dpnId.toString() + vpnId); + synchronized (lockOnDpnVpn.intern()) { + final Optional vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id); + if (vrfTable.isPresent()) { + DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance(); + dataStoreCoordinator.enqueueJob("FIB" + vpnId + dpnId.toString(), + new Callable>>() { + @Override + public List> call() throws Exception { + WriteTransaction tx = broker.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); + continue; + } + // Passing null as we don't know the dpn + // to which prefix is attached at this point + createRemoteFibEntry(dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, tx); + } + //TODO: if we have 100K entries in FIB, can it fit in one Tranasaction (?) + List> futures = new ArrayList<>(); + futures.add(tx.submit()); + return futures; + } + }); + } + } + } + + public void populateFibOnDpn(BigInteger dpnId, BigInteger localDpnId, long vpnId, String rd, String nexthopIp) { + LOG.trace(" dpn {} for vpn {}, rd {}, nexthopIp {} : populateFibOnDpn", dpnId, vpnId, rd, nexthopIp); + InstanceIdentifier id = buildVrfId(rd); + String lockOnDpnVpn = new String(dpnId.toString()+ vpnId); + synchronized (lockOnDpnVpn.intern()) { + Optional vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id); + if (vrfTable.isPresent()) { + for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) { + // Passing null as we don't know the dpn + // to which prefix is attached at this point + if (nexthopIp.trim().equals(vrfEntry.getNextHopAddressList().get(0).trim())) { + LOG.trace(" creating remote FIB entry"); + createRemoteFibEntry(dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, null); + } + } } } } - //The flow/group entry has been deleted from config DS; need to clean up associated operational - //DS entries in VPN Op DS, VpnInstanceOpData and PrefixToInterface to complete deletion - cleanUpOpDataForFib(vpnInstance.getVpnId(), vrfTableKey.getRouteDistinguisher(), vrfEntry); - } - - public void deleteRemoteRoute(final BigInteger localDpnId, final BigInteger remoteDpnId, - final long vpnId, final VrfTablesKey vrfTableKey, - final VrfEntry vrfEntry) { - LOG.debug("deleting route "+ vrfEntry.getDestPrefix() + " "+vpnId); - String rd = vrfTableKey.getRouteDistinguisher(); - boolean isRemoteRoute = true; - if (localDpnId == null) { - // localDpnId is not known when clean up happens for last vm for a vpn on a dpn - VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix()); - if(localNextHopInfo == null) { - //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn - Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix()); - if (extra_route != null) { - localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, extra_route.getNexthopIp()); - } - } - if (localNextHopInfo != null) { - isRemoteRoute = (!remoteDpnId.equals(localNextHopInfo.getDpnId())); - } - } - if (isRemoteRoute) { - makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW); - LOG.debug("Successfully delete fib entry for "+ vrfEntry.getDestPrefix() + " vpnId "+vpnId); - } else{ - LOG.debug("Did not delete fib entry rd: {} =, prefix: {} as it is local to dpn {}", rd, vrfEntry.getDestPrefix(), remoteDpnId); - } - } - - private long getIpAddress(byte[] rawIpAddress) { - return (((rawIpAddress[0] & 0xFF) << (3 * 8)) + ((rawIpAddress[1] & 0xFF) << (2 * 8)) - + ((rawIpAddress[2] & 0xFF) << (1 * 8)) + (rawIpAddress[3] & 0xFF)) & 0xffffffffL; - } - - private void makeConnectedRoute(BigInteger dpId, long vpnId, VrfEntry vrfEntry, String rd, - List instructions, int addOrRemove) { LOG.trace("makeConnectedRoute: vrfEntry {}",vrfEntry); - String values[] = vrfEntry.getDestPrefix().split("/"); - String ipAddress = values[0]; - int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]); - if (addOrRemove == NwConstants.ADD_FLOW) { - LOG.debug("Adding route to DPN {} for rd {} prefix {} ", dpId, rd, vrfEntry.getDestPrefix()); - } else { - LOG.debug("Removing route from DPN {} for rd {} prefix {}", dpId, rd, vrfEntry.getDestPrefix()); - } - InetAddress destPrefix = null; - try { - destPrefix = InetAddress.getByName(ipAddress); - } catch (UnknownHostException e) { - LOG.error("Failed to get destPrefix for prefix {} ", vrfEntry.getDestPrefix(), e); - return; - } - - List matches = new ArrayList<>(); - - matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] { - BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID })); - - matches.add(new MatchInfo(MatchFieldType.eth_type, - new long[] { 0x0800L })); - - if(prefixLength != 0) { - matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] { - destPrefix.getHostAddress(), Integer.toString(prefixLength)})); - } - - String flowRef = getFlowRef(dpId, NwConstants.L3_FIB_TABLE, rd, destPrefix); - - FlowEntity flowEntity; - - int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength; - flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_FIB_TABLE, flowRef, - priority, flowRef, 0, 0, - COOKIE_VM_FIB_TABLE, matches, instructions); - - if (addOrRemove == NwConstants.ADD_FLOW) { - /* We need to call sync API to install flow so that 2 DS operations on the same object do not - * happen at same time. However, MDSALManager's syncInstallFlow takes a delay time (or uses a default one) to wait - * for or for notification that operational DS write for flows is done. We do not turn on the stats writing for flows, - * so that notification never comes, so we do not need that wait. Sending the lowest value of wait "1 ms" since 0 wait means - * wait indefinitely. */ - mdsalManager.syncInstallFlow(flowEntity, 1); - } else { - mdsalManager.syncRemoveFlow(flowEntity, 1); - } - } - - private void makeLFibTableEntry(BigInteger dpId, long label, List instructions, - String nextHop, int addOrRemove) { - List matches = new ArrayList<>(); - matches.add(new MatchInfo(MatchFieldType.eth_type, - new long[] { 0x8847L })); - matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(label)})); - - // Install the flow entry in L3_LFIB_TABLE - String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, label, nextHop); - - FlowEntity flowEntity; - flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_LFIB_TABLE, flowRef, - DEFAULT_FIB_FLOW_PRIORITY, flowRef, 0, 0, - COOKIE_VM_LFIB_TABLE, matches, instructions); - - if (addOrRemove == NwConstants.ADD_FLOW) { - /* We need to call sync API to install flow so that 2 DS operations on the same object do not - * happen at same time. However, MDSALManager's syncInstallFlow takes a delay time (or uses a default one) to wait - * for or for notification that operational DS write for flows is done. We do not turn on the stats writing for flows, - * so that notification never comes, so we do not need that wait. Sending the lowest value of wait "1 ms" since 0 wait means - * wait indefinitely. */ - - mdsalManager.syncInstallFlow(flowEntity, 1); - } else { - mdsalManager.syncRemoveFlow(flowEntity, 1); - } - LOG.debug("LFIB Entry for dpID {} : label : {} instructions {} modified successfully {}",dpId, label, instructions ); - } - - private void deleteLocalAdjacency(final BigInteger dpId, final long vpnId, final String ipAddress) { - LOG.trace("deleteLocalAdjacency called with dpid {}, vpnId{}, ipAddress {}",dpId, vpnId, ipAddress); - try { - nextHopManager.removeLocalNextHop(dpId, vpnId, ipAddress); - } catch (NullPointerException e) { - LOG.trace("", e); - } - } - - public void populateFibOnNewDpn(BigInteger dpnId, long vpnId, String rd) { - LOG.trace("New dpn {} for vpn {} : populateFibOnNewDpn", dpnId, rd); - InstanceIdentifier id = buildVrfId(rd); - String lockOnDpnVpn = new String(dpnId.toString()+ vpnId); - synchronized (lockOnDpnVpn.intern()) { - Optional vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id); - if (vrfTable.isPresent()) { - for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) { - SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class); - if (subnetRoute != null){ - long elanTag= subnetRoute.getElantag(); - installSubnetRouteInFib(dpnId, elanTag, rd, vpnId, vrfEntry); - continue; - } - // Passing null as we don't know the dpn - // to which prefix is attached at this point - createRemoteFibEntry(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry); - } - } - } - } - - public void populateFibOnDpn(BigInteger dpnId, long vpnId, String rd, String nexthopIp) { - LOG.trace("dpn {} for vpn {}, nexthopIp {} : populateFibOnDpn", dpnId, rd, nexthopIp); - InstanceIdentifier id = buildVrfId(rd); - String lockOnDpnVpn = new String(dpnId.toString()+ vpnId); - synchronized (lockOnDpnVpn.intern()) { - Optional vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id); - if (vrfTable.isPresent()) { - for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) { - // Passing null as we don't know the dpn - // to which prefix is attached at this point - if (nexthopIp == vrfEntry.getNextHopAddress()) { - createRemoteFibEntry(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry); - } - } - } - } - } - - public void cleanUpDpnForVpn(BigInteger dpnId, long vpnId, String rd) { - LOG.trace("Remove dpn {} for vpn {} : cleanUpDpnForVpn", dpnId, rd); - InstanceIdentifier id = buildVrfId(rd); - String lockOnDpnVpn = new String(dpnId.toString()+ vpnId); - synchronized (lockOnDpnVpn.intern()) { - Optional vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id); - if (vrfTable.isPresent()) { - for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) { - /* Handle subnet routes here */ - SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class); - if (subnetRoute != null){ - LOG.trace("Cleaning subnetroute {} on dpn {} for vpn {} : cleanUpDpnForVpn", vrfEntry.getDestPrefix(), - dpnId, rd); - makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW); - makeLFibTableEntry(dpnId, vrfEntry.getLabel(), null, - vrfEntry.getNextHopAddress(),NwConstants.DEL_FLOW); - LOG.trace("cleanUpDpnForVpn: Released subnetroute label {} for rd {} prefix {}", vrfEntry.getLabel(), rd, - vrfEntry.getDestPrefix()); - continue; + + public void handleRemoteRoute(boolean action, BigInteger localDpnId, BigInteger remoteDpnId, long vpnId, String rd, String destPrefix , + String nextHopIp) { + VrfTablesKey vrfTablesKey = new VrfTablesKey(rd); + VrfEntry vrfEntry = getVrfEntry(broker, rd, destPrefix); + if (vrfEntry == null) { + LOG.trace("VrfEntry for prefix {} is null. Exitting.", nextHopIp); + return; + } + LOG.trace("handleRemoteRoute --- action {}, localDpnId {}, remoteDpnId {} , vpnId {}, rd {}, destPfx {}", + action, localDpnId, remoteDpnId, vpnId, rd, destPrefix); + if (action == true) { + createRemoteFibEntry(remoteDpnId, vpnId, vrfTablesKey, vrfEntry, null); + } else { + deleteRemoteRoute(null, remoteDpnId, vpnId, vrfTablesKey, vrfEntry, null); + } + + } + + public void cleanUpDpnForVpn(final BigInteger dpnId, final long vpnId, final String rd) { + LOG.trace("Remove dpn {} for vpn {} : cleanUpDpnForVpn", dpnId, rd); + InstanceIdentifier id = buildVrfId(rd); + String lockOnDpnVpn = new String(dpnId.toString() + vpnId); + synchronized (lockOnDpnVpn.intern()) { + + final Optional vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id); + if (vrfTable.isPresent()) { + DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance(); + dataStoreCoordinator.enqueueJob("FIB" + vpnId + dpnId.toString(), + new Callable>>() { + WriteTransaction tx = broker.newWriteOnlyTransaction(); + @Override + public List> call() throws Exception { + for (final VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) { + /* Handle subnet routes here */ + SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class); + if (subnetRoute != null) { + LOG.trace("Cleaning subnetroute {} on dpn {} for vpn {} : cleanUpDpnForVpn", vrfEntry.getDestPrefix(), + dpnId, rd); + makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW, tx); + makeLFibTableEntry(dpnId, vrfEntry.getLabel(), null, DEFAULT_FIB_FLOW_PRIORITY, NwConstants.DEL_FLOW, tx); + LOG.trace("cleanUpDpnForVpn: Released subnetroute label {} for rd {} prefix {}", vrfEntry.getLabel(), rd, + vrfEntry.getDestPrefix()); + continue; + } + // Passing null as we don't know the dpn + // to which prefix is attached at this point + deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, tx); + } + List> futures = new ArrayList<>(); + futures.add(tx.submit()); + return futures; + } + + }); + } + + } + } + + public void cleanUpDpnForVpn(BigInteger dpnId, long vpnId, String rd, String nexthopIp) { + LOG.trace(" cleanup remote routes on dpn {} for vpn {}, rd {}, nexthopIp {} : cleanUpDpnForVpn", dpnId, vpnId, rd, nexthopIp); + InstanceIdentifier id = buildVrfId(rd); + String lockOnDpnVpn = new String(dpnId.toString()+ vpnId); + synchronized (lockOnDpnVpn.intern()) { + Optional vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id); + if (vrfTable.isPresent()) { + for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) { + LOG.trace(":vrfEntry :: {}", vrfEntry); + // Passing null as we don't know the dpn + // to which prefix is attached at this point + if (nexthopIp.trim().equals(vrfEntry.getNextHopAddressList().get(0).trim())) { + LOG.trace(" deleting remote FIB entry {}", vrfEntry); + deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, null); + } + } + } else { + LOG.trace("No vrfTable is present"); + } + } + } + + public static InstanceIdentifier buildVrfId(String rd) { + InstanceIdentifierBuilder idBuilder = + InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)); + InstanceIdentifier id = idBuilder.build(); + return id; + } + + private String getFlowRef(BigInteger dpnId, short tableId, long label, int priority) { + return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR) + .append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(label).append(NwConstants.FLOWID_SEPARATOR) + .append(priority).toString(); + } + + private String getFlowRef(BigInteger dpnId, short tableId, String rd, int priority, InetAddress destPrefix) { + return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR) + .append(tableId).append(NwConstants.FLOWID_SEPARATOR) + .append(rd).append(NwConstants.FLOWID_SEPARATOR) + .append(priority).append(NwConstants.FLOWID_SEPARATOR) + .append(destPrefix.getHostAddress()).toString(); + } + + private String getInterVpnFibFlowRef(String interVpnLinkName, String prefix, String nextHop ) { + return new StringBuilder(64).append(FLOWID_PREFIX) + .append(interVpnLinkName).append(NwConstants.FLOWID_SEPARATOR) + .append(prefix).append(NwConstants.FLOWID_SEPARATOR) + .append(nextHop).toString(); + } + + protected List resolveAdjacency(final BigInteger remoteDpnId, final long vpnId, final VrfEntry vrfEntry, + String rd) { + List adjacencyList = new ArrayList<>(); + LOG.trace("resolveAdjacency called with remotedpid {}, vpnId{}, VrfEntry {}", remoteDpnId, vpnId, vrfEntry); + try { + Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix()); + List prefixIpList; + if (extra_route == null) { + prefixIpList = Arrays.asList(vrfEntry.getDestPrefix()); + } else { + prefixIpList = new ArrayList<>(); + //FIXME:Suraj +// for (String extraRouteIp : extra_route.getNexthopIpList()) { + // prefixIpList.add(extraRouteIp + "/32"); + // } + } + + for (String prefixIp : prefixIpList) { + for (String nextHopIp : vrfEntry.getNextHopAddressList()) { + LOG.debug("NextHop IP for destination {} is {}", prefixIp, nextHopIp); + String adjacency = nextHopManager.getRemoteNextHopPointer(remoteDpnId, vpnId, prefixIp, nextHopIp); + if (adjacency != null && !adjacency.isEmpty() && !adjacencyList.contains(adjacency)) { + adjacencyList.add(adjacency); + } + } } - // Passing null as we don't know the dpn - // to which prefix is attached at this point - deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry); - } - } - } - } - - public void cleanUpDpnForVpn(BigInteger dpnId, long vpnId, String rd, String nexthopIp) { - LOG.trace("dpn {} for vpn {}, nexthopIp {} : cleanUpDpnForVpn", dpnId, rd, nexthopIp); - InstanceIdentifier id = buildVrfId(rd); - String lockOnDpnVpn = new String(dpnId.toString()+ vpnId); - synchronized (lockOnDpnVpn.intern()) { - Optional vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id); - if (vrfTable.isPresent()) { - for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) { - // Passing null as we don't know the dpn - // to which prefix is attached at this point - if (nexthopIp == vrfEntry.getNextHopAddress()) { - deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry); - } - } - } - } - } - - public static InstanceIdentifier buildVrfId(String rd) { - InstanceIdentifierBuilder idBuilder = - InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)); - InstanceIdentifier id = idBuilder.build(); - return id; - } - - private String getFlowRef(BigInteger dpnId, short tableId, long label, String nextHop) { - return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR) - .append(tableId).append(NwConstants.FLOWID_SEPARATOR) - .append(label).append(NwConstants.FLOWID_SEPARATOR) - .append(nextHop).toString(); - } - - private String getFlowRef(BigInteger dpnId, short tableId, String rd, InetAddress destPrefix) { - return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR) - .append(tableId).append(NwConstants.FLOWID_SEPARATOR) - .append(rd).append(NwConstants.FLOWID_SEPARATOR) - .append(destPrefix.getHostAddress()).toString(); - } - - protected String resolveAdjacency(final BigInteger localDpnId, final BigInteger remoteDpnId, - final long vpnId, final VrfEntry vrfEntry, String rd) { - String adjacency = null; - boolean staticRoute = false; - LOG.trace("resolveAdjacency called with localdpid{} remotedpid {}, vpnId{}, VrfEntry {}", localDpnId, remoteDpnId, vpnId, vrfEntry); - try { - Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix()); - if(extra_route != null) { - staticRoute = true; - } - - adjacency = - nextHopManager.getRemoteNextHopPointer(localDpnId, remoteDpnId, vpnId, - (staticRoute) ? extra_route.getNexthopIp() + "/32" : vrfEntry.getDestPrefix(), - vrfEntry.getNextHopAddress()); - } catch (NullPointerException e) { - LOG.trace("", e); - } - return adjacency; - } - - protected VpnInstanceOpDataEntry getVpnInstance(String rd) { - InstanceIdentifier id = InstanceIdentifier.create(VpnInstanceOpData.class).child( - VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd)); - Optional vpnInstanceOpData = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id); - if(vpnInstanceOpData.isPresent()) { - return vpnInstanceOpData.get(); - } - return null; - } + } catch (NullPointerException e) { + LOG.trace("", e); + } + return adjacencyList; + } + + protected VpnInstanceOpDataEntry getVpnInstance(String rd) { + InstanceIdentifier id = InstanceIdentifier.create(VpnInstanceOpData.class).child( + VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd)); + Optional vpnInstanceOpData = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id); + return vpnInstanceOpData.isPresent() ? vpnInstanceOpData.get() : null; + } public void processNodeAdd(BigInteger dpnId) { LOG.debug("Received notification to install TableMiss entries for dpn {} ", dpnId); @@ -914,15 +1507,18 @@ public class FibManager extends AbstractDataChangeListener implements private void makeTableMissFlow(BigInteger dpnId, int addOrRemove) { final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16); // Instruction to goto L3 InterfaceTable - List instructions = new ArrayList<>(); + List instructions = new ArrayList(); instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_INTERFACE_TABLE })); - List matches = new ArrayList<>(); + List matches = new ArrayList(); FlowEntity flowEntityLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_LFIB_TABLE, - getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, NwConstants.TABLE_MISS_FLOW), + getTableMissFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, NwConstants.TABLE_MISS_FLOW), NwConstants.TABLE_MISS_PRIORITY, "Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions); - FlowEntity flowEntityFib = MDSALUtil.buildFlowEntity(dpnId,NwConstants.L3_FIB_TABLE, getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, NwConstants.TABLE_MISS_FLOW), - NwConstants.TABLE_MISS_PRIORITY, "FIB Table Miss Flow", 0, 0, COOKIE_VM_FIB_TABLE, + FlowEntity flowEntityFib = MDSALUtil.buildFlowEntity(dpnId,NwConstants.L3_FIB_TABLE, + getTableMissFlowRef(dpnId, NwConstants.L3_FIB_TABLE, + NwConstants.TABLE_MISS_FLOW), + NwConstants.TABLE_MISS_PRIORITY, "FIB Table Miss Flow", + 0, 0, COOKIE_VM_FIB_TABLE, matches, instructions); if (addOrRemove == NwConstants.ADD_FLOW) { @@ -936,85 +1532,94 @@ public class FibManager extends AbstractDataChangeListener implements } } - private String getFlowRef(BigInteger dpnId, short tableId, int tableMiss) { + private String getTableMissFlowRef(BigInteger dpnId, short tableId, int tableMiss) { return new StringBuffer().append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR) .append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(tableMiss) .append(FLOWID_PREFIX).toString(); } - /* - * Install flow entry in protocol table to forward mpls - * coming through gre tunnel to LFIB table. - */ - private void makeProtocolTableFlow(BigInteger dpnId, int addOrRemove) { - final BigInteger COOKIE_PROTOCOL_TABLE = new BigInteger("1070000", 16); - // Instruction to goto L3 InterfaceTable - List instructions = new ArrayList<>(); - instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] {NwConstants.L3_LFIB_TABLE})); - List matches = new ArrayList<>(); - matches.add(new MatchInfo(MatchFieldType.eth_type, - new long[] { 0x8847L })); - FlowEntity flowEntityToLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_PROTOCOL_TABLE, - getFlowRef(dpnId, NwConstants.L3_PROTOCOL_TABLE, - NwConstants.L3_LFIB_TABLE), - DEFAULT_FIB_FLOW_PRIORITY, - "Protocol Table For LFIB", - 0, 0, - COOKIE_PROTOCOL_TABLE, - matches, instructions); - - if (addOrRemove == NwConstants.ADD_FLOW) { - LOG.debug("Invoking MDSAL to install Protocol Entries for dpn {}", dpnId); - mdsalManager.installFlow(flowEntityToLfib); - } else { - mdsalManager.removeFlow(flowEntityToLfib); - } - } - - public List printFibEntries() { - List result = new ArrayList<>(); - result.add(String.format(" %-7s %-20s %-20s %-7s", "RD", "Prefix", "Nexthop", "Label")); - result.add("-------------------------------------------------------------------"); - InstanceIdentifier id = InstanceIdentifier.create(FibEntries.class); - Optional fibEntries = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id); - if (fibEntries.isPresent()) { - List vrfTables = fibEntries.get().getVrfTables(); - for (VrfTables vrfTable : vrfTables) { - for (VrfEntry vrfEntry : vrfTable.getVrfEntry()) { - result.add(String.format(" %-7s %-20s %-20s %-7s", vrfTable.getRouteDistinguisher(), - vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddress(), vrfEntry.getLabel())); - } - } - } - return result; - } - - private void makeL3IntfTblMissFlow(BigInteger dpnId, int addOrRemove) { - List instructions = new ArrayList<>(); - List matches = new ArrayList<>(); - final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16); - // Instruction to clear metadata except SI and LportTag bits - instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { - CLEAR_METADATA, METADATA_MASK_CLEAR })); - // Instruction to clear action - instructions.add(new InstructionInfo(InstructionType.clear_actions)); - // Instruction to goto L3 InterfaceTable - - List actionsInfos = new ArrayList<>(); - actionsInfos.add(new ActionInfo(ActionType.nx_resubmit, new String[]{ - Short.toString(NwConstants.LPORT_DISPATCHER_TABLE)})); - instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos)); - //instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.LPORT_DISPATCHER_TABLE })); - - FlowEntity flowEntityL3Intf = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_INTERFACE_TABLE, - getFlowRef(dpnId, NwConstants.L3_INTERFACE_TABLE, NwConstants.TABLE_MISS_FLOW), - NwConstants.TABLE_MISS_PRIORITY, "L3 Interface Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions); - if (addOrRemove == NwConstants.ADD_FLOW) { - LOG.info("Invoking MDSAL to install L3 interface Table Miss Entries"); - mdsalManager.installFlow(flowEntityL3Intf); - } else { - mdsalManager.removeFlow(flowEntityL3Intf); - } - } + /* + * Install flow entry in protocol table to forward mpls + * coming through gre tunnel to LFIB table. + */ + private void makeProtocolTableFlow(BigInteger dpnId, int addOrRemove) { + final BigInteger COOKIE_PROTOCOL_TABLE = new BigInteger("1070000", 16); + // Instruction to goto L3 InterfaceTable + List instructions = new ArrayList<>(); + instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] {NwConstants.L3_LFIB_TABLE})); + List matches = new ArrayList(); + matches.add(new MatchInfo(MatchFieldType.eth_type, + new long[] { NwConstants.ETHTYPE_MPLS_UC })); + FlowEntity flowEntityToLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_PROTOCOL_TABLE, + getTableMissFlowRef(dpnId, NwConstants.L3_PROTOCOL_TABLE, + NwConstants.L3_LFIB_TABLE), + DEFAULT_FIB_FLOW_PRIORITY, + "Protocol Table For LFIB", + 0, 0, + COOKIE_PROTOCOL_TABLE, + matches, instructions); + + if (addOrRemove == NwConstants.ADD_FLOW) { + LOG.debug("Invoking MDSAL to install Protocol Entries for dpn {}", dpnId); + mdsalManager.installFlow(flowEntityToLfib); + } else { + mdsalManager.removeFlow(flowEntityToLfib); + } + } + public List printFibEntries() { + List result = new ArrayList(); + result.add(String.format(" %-7s %-20s %-20s %-7s %-7s", "RD", "Prefix", "NextHop", "Label", "Origin")); + result.add("-------------------------------------------------------------------"); + InstanceIdentifier id = InstanceIdentifier.create(FibEntries.class); + Optional fibEntries = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id); + if (fibEntries.isPresent()) { + List vrfTables = fibEntries.get().getVrfTables(); + for (VrfTables vrfTable : vrfTables) { + for (VrfEntry vrfEntry : vrfTable.getVrfEntry()) { + for (String nextHop : vrfEntry.getNextHopAddressList()) { + result.add(String.format(" %-7s %-20s %-20s %-7s %-7s", vrfTable.getRouteDistinguisher(), + vrfEntry.getDestPrefix(), nextHop, vrfEntry.getLabel(), vrfEntry.getOrigin())); + } + } + } + } + return result; + } + + private void makeL3IntfTblMissFlow(BigInteger dpnId, int addOrRemove) { + List instructions = new ArrayList(); + List matches = new ArrayList(); + final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16); + // Instruction to goto L3 InterfaceTable + + List actionsInfos = new ArrayList (); + actionsInfos.add(new ActionInfo(ActionType.nx_resubmit, new String[]{ + Short.toString(NwConstants.LPORT_DISPATCHER_TABLE)})); + instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos)); + //instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.LPORT_DISPATCHER_TABLE })); + + FlowEntity flowEntityL3Intf = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_INTERFACE_TABLE, + getTableMissFlowRef(dpnId, NwConstants.L3_INTERFACE_TABLE, NwConstants.TABLE_MISS_FLOW), + NwConstants.TABLE_MISS_PRIORITY, "L3 Interface Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions); + if (addOrRemove == NwConstants.ADD_FLOW) { + LOG.info("Invoking MDSAL to install L3 interface Table Miss Entries"); + mdsalManager.installFlow(flowEntityL3Intf); + } else { + mdsalManager.removeFlow(flowEntityL3Intf); + } + } + + private VrfEntry getVrfEntry(DataBroker broker, String rd, String ipPrefix) { + InstanceIdentifier vrfEntryId = + InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)). + child(VrfEntry.class, new VrfEntryKey(ipPrefix)).build(); + Optional vrfEntry = read(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId); + if (vrfEntry.isPresent()) { + return (vrfEntry.get()); + } + return null; + } } + + diff --git a/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/FibManagerProvider.java b/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/FibManagerProvider.java index ec0e2835c1..327da2f48d 100644 --- a/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/FibManagerProvider.java +++ b/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/FibManagerProvider.java @@ -108,15 +108,15 @@ public class FibManagerProvider implements BindingAwareProvider, IFibManager, Au return fibManager.printFibEntries(); } - //Temp @Override public void addStaticRoute(String prefix, String nextHop, String rd, int label) { this.vpnmanager.addExtraRoute(prefix, nextHop, rd, null, label); } + //FIXME: Once changes are upstreamed from vpnmanager @Override - public void deleteStaticRoute(String prefix, String rd) { - this.vpnmanager.delExtraRoute(prefix, rd, null); + public void deleteStaticRoute(String prefix, String nextHop, String rd) { + // this.vpnmanager.delExtraRoute(prefix, nextHop, rd, null); } public void setRpcProviderRegistry(RpcProviderRegistry rpcProviderRegistry) { @@ -153,5 +153,23 @@ public class FibManagerProvider implements BindingAwareProvider, IFibManager, Au public boolean isVPNConfigured() { return this.vpnmanager.isVPNConfigured(); } + @Override + public String getTransportTypeStr(String tunType) { + return this.nexthopManager.getTransportTypeStr(tunType); + } + + @Override + public void handleRemoteRoute(boolean action, BigInteger localDpnId, BigInteger remoteDpnId, long vpnId, String rd, String destPrefix , String nextHopIp) { + fibManager.handleRemoteRoute(action, localDpnId, remoteDpnId, vpnId,rd, destPrefix, nextHopIp); + } + @Override + public void populateFibOnDpn(BigInteger localDpnId, BigInteger remoteDpnId, long vpnId, String rd, String nextHopIp) { + fibManager.populateFibOnDpn(localDpnId, remoteDpnId, vpnId, rd, nextHopIp); + } + + @Override + public void cleanUpDpnForVpn(BigInteger dpnId, long vpnId, String rd, String nextHopIp) { + fibManager.cleanUpDpnForVpn(dpnId, vpnId, rd, nextHopIp); + } -} +} \ No newline at end of file diff --git a/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/FibRpcServiceImpl.java b/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/FibRpcServiceImpl.java index 1e2e44785a..f2542ec2d9 100644 --- a/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/FibRpcServiceImpl.java +++ b/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/FibRpcServiceImpl.java @@ -28,6 +28,11 @@ import org.opendaylight.genius.mdsalutil.MatchInfo; import org.opendaylight.genius.mdsalutil.MetaDataUtil; import org.opendaylight.genius.mdsalutil.NwConstants; import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.PopulateFibOnDpnInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CleanupDpnForVpnInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceToVpnId; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry; @@ -40,9 +45,6 @@ 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.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddressesKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; @@ -74,18 +76,20 @@ public class FibRpcServiceImpl implements FibRpcService { * to install FIB routes on specified dpn with given instructions * */ + @Override public Future> createFibEntry(CreateFibEntryInput input) { BigInteger dpnId = input.getSourceDpid(); String vpnName = input.getVpnName(); long vpnId = getVpnId(broker, vpnName); + String vpnRd = getVpnRd(broker, vpnName); String ipAddress = input.getIpAddress(); LOG.info("Create custom FIB entry - {} on dpn {} for VPN {} ", ipAddress, dpnId, vpnName); List instructions = input.getInstruction(); - + LOG.info("ADD: Adding Custom Fib Entry rd {} prefix {} label {}", vpnRd, ipAddress, input.getServiceId()); makeLocalFibEntry(vpnId, dpnId, ipAddress, instructions); updateVpnToDpnAssociation(vpnId, dpnId, ipAddress, vpnName); - + LOG.info("ADD: Added Custom Fib Entry rd {} prefix {} label {}", vpnRd, ipAddress, input.getServiceId()); return Futures.immediateFuture(RpcResultBuilder.success().build()); } @@ -93,24 +97,40 @@ public class FibRpcServiceImpl implements FibRpcService { * to remove FIB/LFIB/TST routes from specified dpn * */ + @Override public Future> removeFibEntry(RemoveFibEntryInput input) { BigInteger dpnId = input.getSourceDpid(); String vpnName = input.getVpnName(); long vpnId = getVpnId(broker, vpnName); + String vpnRd = getVpnRd(broker, vpnName); long serviceId = input.getServiceId(); String ipAddress = input.getIpAddress(); LOG.info("Delete custom FIB entry - {} on dpn {} for VPN {} ", ipAddress, dpnId, vpnName); - + LOG.info("REMOVE: Removing Custom Fib Entry rd {} prefix {} label {}", vpnRd, ipAddress, input.getServiceId()); removeLocalFibEntry(dpnId, vpnId, ipAddress); //removeLFibTableEntry(dpnId, serviceId); //removeTunnelTableEntry(dpnId, serviceId); removeFromVpnDpnAssociation(vpnId, dpnId, ipAddress, vpnName); + LOG.info("REMOVE: Removed Custom Fib Entry rd {} prefix {} label {}", vpnRd, ipAddress, input.getServiceId()); return Futures.immediateFuture(RpcResultBuilder.success().build()); } + + @Override + public Future> populateFibOnDpn(PopulateFibOnDpnInput input) { + fibManager.populateFibOnNewDpn(input.getDpid(), input.getVpnId(), input.getRd()); + return Futures.immediateFuture(RpcResultBuilder.success().build()); + } + + @Override + public Future> cleanupDpnForVpn(CleanupDpnForVpnInput input) { + fibManager.cleanUpDpnForVpn(input.getDpid(), input.getVpnId(), input.getRd()); + return Futures.immediateFuture(RpcResultBuilder.success().build()); + } + private void removeLocalFibEntry(BigInteger dpnId, long vpnId, String ipPrefix) { String values[] = ipPrefix.split("/"); String ipAddress = values[0]; @@ -118,18 +138,18 @@ public class FibRpcServiceImpl implements FibRpcService { LOG.debug("Removing route from DPN. ip {} masklen {}", ipAddress, prefixLength); InetAddress destPrefix = null; try { - destPrefix = InetAddress.getByName(ipAddress); + destPrefix = InetAddress.getByName(ipAddress); } catch (UnknownHostException e) { - LOG.error("UnknowHostException in removeRoute. Failed to remove Route for ipPrefix {}", ipAddress); - return; + LOG.error("UnknowHostException in removeRoute. Failed to remove Route for ipPrefix {}", ipAddress); + return; } - List matches = new ArrayList<>(); + List matches = new ArrayList(); matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] { - BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID })); + BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID })); matches.add(new MatchInfo(MatchFieldType.eth_type, - new long[] { 0x0800L })); + new long[] { 0x0800L })); if(prefixLength != 0) { matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] { @@ -141,8 +161,8 @@ public class FibRpcServiceImpl implements FibRpcService { int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength; Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_FIB_TABLE, flowRef, - priority, flowRef, 0, 0, - COOKIE_VM_FIB_TABLE, matches, null); + priority, flowRef, 0, 0, + COOKIE_VM_FIB_TABLE, matches, null); mdsalManager.removeFlow(dpnId, flowEntity); @@ -150,9 +170,9 @@ public class FibRpcServiceImpl implements FibRpcService { } private void removeLFibTableEntry(BigInteger dpnId, long serviceId) { - List matches = new ArrayList<>(); + List matches = new ArrayList(); matches.add(new MatchInfo(MatchFieldType.eth_type, - new long[] { 0x8847L })); + new long[] { 0x8847L })); matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(serviceId)})); String flowRef = getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, serviceId, ""); @@ -160,8 +180,8 @@ public class FibRpcServiceImpl implements FibRpcService { LOG.debug("removing LFib entry with flow ref {}", flowRef); Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef, - DEFAULT_FIB_FLOW_PRIORITY, flowRef, 0, 0, - COOKIE_VM_LFIB_TABLE, matches, null); + DEFAULT_FIB_FLOW_PRIORITY, flowRef, 0, 0, + COOKIE_VM_LFIB_TABLE, matches, null); mdsalManager.removeFlow(dpnId, flowEntity); @@ -170,27 +190,27 @@ public class FibRpcServiceImpl implements FibRpcService { private void removeTunnelTableEntry(BigInteger dpnId, long serviceId) { LOG.info("remove terminatingServiceActions called with DpnId = {} and label = {}", dpnId , serviceId); - List mkMatches = new ArrayList<>(); + List mkMatches = new ArrayList(); // Matching metadata mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(serviceId)})); Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE, - getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""), - 5, String.format("%s:%d","TST Flow Entry ",serviceId), 0, 0, - COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, null); + getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""), + 5, String.format("%s:%d","TST Flow Entry ",serviceId), 0, 0, + COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, null); mdsalManager.removeFlow(dpnId, flowEntity); LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully {}",dpnId, serviceId); } private void makeTunnelTableEntry(BigInteger dpnId, long serviceId, List customInstructions) { - List mkMatches = new ArrayList<>(); + List mkMatches = new ArrayList(); LOG.info("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", dpnId , serviceId); mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(serviceId)})); Flow terminatingServiceTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE, - getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""), 5, String.format("%s:%d","TST Flow Entry ",serviceId), - 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)),mkMatches, customInstructions); + getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""), 5, String.format("%s:%d","TST Flow Entry ",serviceId), + 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)),mkMatches, customInstructions); mdsalManager.installFlow(dpnId, terminatingServiceTableFlowEntity); } @@ -207,22 +227,22 @@ public class FibRpcServiceImpl implements FibRpcService { LOG.debug("Adding route to DPN. ip {} masklen {}", ipAddress, prefixLength); InetAddress destPrefix = null; try { - destPrefix = InetAddress.getByName(ipAddress); + destPrefix = InetAddress.getByName(ipAddress); } catch (UnknownHostException e) { - LOG.error("UnknowHostException in addRoute. Failed to add Route for ipPrefix {}", ipAddress); - return; + LOG.error("UnknowHostException in addRoute. Failed to add Route for ipPrefix {}", ipAddress); + return; } - List matches = new ArrayList<>(); + List matches = new ArrayList(); matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] { - BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID })); + BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID })); matches.add(new MatchInfo(MatchFieldType.eth_type, - new long[] { 0x0800L })); + new long[] { 0x0800L })); if(prefixLength != 0) { - matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] { - destPrefix.getHostAddress(), Integer.toString(prefixLength) })); + matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] { + destPrefix.getHostAddress(), Integer.toString(prefixLength) })); } String flowRef = getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, vpnId, ipAddress); @@ -230,8 +250,8 @@ public class FibRpcServiceImpl implements FibRpcService { int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength; Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_FIB_TABLE, flowRef, - priority, flowRef, 0, 0, - COOKIE_VM_FIB_TABLE, matches, customInstructions); + priority, flowRef, 0, 0, + COOKIE_VM_FIB_TABLE, matches, customInstructions); mdsalManager.installFlow(dpnId, flowEntity); @@ -239,13 +259,13 @@ public class FibRpcServiceImpl implements FibRpcService { } private void makeLFibTableEntry(BigInteger dpId, long serviceId, List customInstructions) { - List matches = new ArrayList<>(); + List matches = new ArrayList(); matches.add(new MatchInfo(MatchFieldType.eth_type, new long[] { 0x8847L })); matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(serviceId)})); - List instructions = new ArrayList<>(); - List actionsInfos = new ArrayList<>(); + List instructions = new ArrayList(); + List actionsInfos = new ArrayList(); actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{})); Instruction writeInstruction = new InstructionInfo(InstructionType.write_actions, actionsInfos).buildInstruction(0); instructions.add(writeInstruction); @@ -265,8 +285,8 @@ public class FibRpcServiceImpl implements FibRpcService { private String getFlowRef(BigInteger dpnId, short tableId, long id, String ipAddress) { return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR) - .append(tableId).append(NwConstants.FLOWID_SEPARATOR) - .append(id).append(NwConstants.FLOWID_SEPARATOR).append(ipAddress).toString(); + .append(tableId).append(NwConstants.FLOWID_SEPARATOR) + .append(id).append(NwConstants.FLOWID_SEPARATOR).append(ipAddress).toString(); } private synchronized void updateVpnToDpnAssociation(long vpnId, BigInteger dpnId, String ipAddr, String vpnName) { @@ -276,24 +296,25 @@ public class FibRpcServiceImpl implements FibRpcService { String rd = (routeDistinguisher == null) ? vpnName : routeDistinguisher; InstanceIdentifier id = getVpnToDpnListIdentifier(rd, dpnId); Optional dpnInVpn = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id); - org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses - ipAddress = new IpAddressesBuilder().setIpAddress(ipAddr).build(); + org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data + .entry.vpn.to.dpn.list.IpAddresses + ipAddress = new IpAddressesBuilder().setIpAddress(ipAddr).build(); if (dpnInVpn.isPresent()) { MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, id.child( - org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance - .op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses.class, + org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance + .op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses.class, new IpAddressesKey(ipAddr)), ipAddress); } else { MDSALUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, - getVpnInstanceOpDataIdentifier(rd), - getVpnInstanceOpData(rd, vpnId)); + getVpnInstanceOpDataIdentifier(rd), + getVpnInstanceOpData(rd, vpnId, vpnName)); VpnToDpnListBuilder vpnToDpnList = new VpnToDpnListBuilder().setDpnId(dpnId); List ipAddresses = new ArrayList<>(); + .vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses> ipAddresses = new ArrayList<>(); ipAddresses.add(ipAddress); MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, id, - vpnToDpnList.setIpAddresses(ipAddresses).build()); + vpnToDpnList.setIpAddresses(ipAddresses).build()); LOG.debug("populate FIB on new dpn {} for VPN {}", dpnId, vpnName); fibManager.populateFibOnNewDpn(dpnId, vpnId, rd); } @@ -308,7 +329,7 @@ public class FibRpcServiceImpl implements FibRpcService { Optional dpnInVpn = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id); if (dpnInVpn.isPresent()) { List ipAddresses = dpnInVpn.get().getIpAddresses(); + .vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses> ipAddresses = dpnInVpn.get().getIpAddresses(); org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses ipAddress = new IpAddressesBuilder().setIpAddress(ipAddr).build(); @@ -323,8 +344,8 @@ public class FibRpcServiceImpl implements FibRpcService { } } else { delete(broker, LogicalDatastoreType.OPERATIONAL, id.child( - org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data - .vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses.class, + org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data + .vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses.class, new IpAddressesKey(ipAddr))); } } @@ -347,7 +368,7 @@ public class FibRpcServiceImpl implements FibRpcService { } static InstanceIdentifier - getVpnInstanceToVpnIdIdentifier(String vpnName) { + getVpnInstanceToVpnIdIdentifier(String vpnName) { return InstanceIdentifier.builder(VpnInstanceToVpnId.class) .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance.class, new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstanceKey(vpnName)).build(); @@ -356,21 +377,21 @@ public class FibRpcServiceImpl implements FibRpcService { static InstanceIdentifier getVpnToDpnListIdentifier(String rd, BigInteger dpnId) { return InstanceIdentifier.builder(VpnInstanceOpData.class) - .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd)) - .child(VpnToDpnList.class, new VpnToDpnListKey(dpnId)).build(); + .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd)) + .child(VpnToDpnList.class, new VpnToDpnListKey(dpnId)).build(); } static InstanceIdentifier getVpnInstanceOpDataIdentifier(String rd) { return InstanceIdentifier.builder(VpnInstanceOpData.class) - .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd)).build(); + .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd)).build(); } - static VpnInstanceOpDataEntry getVpnInstanceOpData(String rd, long vpnId) { - return new VpnInstanceOpDataEntryBuilder().setVrfId(rd).setVpnId(vpnId).build(); + static VpnInstanceOpDataEntry getVpnInstanceOpData(String rd, long vpnId, String vpnName) { + return new VpnInstanceOpDataEntryBuilder().setVrfId(rd).setVpnId(vpnId).setVpnInstanceName(vpnName).build(); } static void delete(DataBroker broker, LogicalDatastoreType datastoreType, - InstanceIdentifier path) { + InstanceIdentifier path) { WriteTransaction tx = broker.newWriteOnlyTransaction(); tx.delete(datastoreType, path); tx.submit(); @@ -379,9 +400,9 @@ public class FibRpcServiceImpl implements FibRpcService { static long getVpnId(DataBroker broker, String vpnName) { InstanceIdentifier id - = getVpnInstanceToVpnIdIdentifier(vpnName); + = getVpnInstanceToVpnIdIdentifier(vpnName); Optional vpnInstance - = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id); + = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id); long vpnId = -1; if(vpnInstance.isPresent()) { @@ -390,4 +411,5 @@ public class FibRpcServiceImpl implements FibRpcService { return vpnId; } + } 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 d2803c51fc..c290393373 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 @@ -16,16 +16,31 @@ import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.genius.mdsalutil.MDSALUtil; import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.*; 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.VpnInstanceToVpnId; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency; 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 + .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.genius.idmanager.rev160406.IdManagerService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder; + + +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; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn + .link.states.InterVpnLinkStateKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn + .links.InterVpnLink; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.common.RpcResult; @@ -33,13 +48,15 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; public class FibUtil { private static final Logger LOG = LoggerFactory.getLogger(FibUtil.class); - static Optional read(DataBroker broker, LogicalDatastoreType datastoreType, - InstanceIdentifier path) { + public static Optional read(DataBroker broker, LogicalDatastoreType datastoreType, + InstanceIdentifier path) { ReadOnlyTransaction tx = broker.newReadOnlyTransaction(); @@ -76,7 +93,8 @@ public class FibUtil { static InstanceIdentifier getAdjacencyIdentifier(String vpnInterfaceName, String ipAddress) { return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces.class) .child(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface.class, new org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey(vpnInterfaceName)).augmentation( - org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency.class, new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyKey(ipAddress)).build(); + org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies.class) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency.class, new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyKey(ipAddress)).build(); } static InstanceIdentifier getAdjListPath(String vpnInterfaceName) { @@ -87,7 +105,8 @@ public class FibUtil { static InstanceIdentifier getPrefixToInterfaceIdentifier(long vpnId, String ipPrefix) { return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.PrefixToInterface.class) - .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.VpnIds.class, new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.VpnIdsKey(vpnId)).child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes.class, + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface + .VpnIds.class, new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.VpnIdsKey(vpnId)).child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes.class, new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.PrefixesKey(ipPrefix)).build(); } @@ -96,7 +115,7 @@ public class FibUtil { .child(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface.class, new org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey(vpnInterfaceName)).build(); } - static InstanceIdentifier getVpnToDpnListIdentifier(String rd, BigInteger dpnId) { + public static InstanceIdentifier getVpnToDpnListIdentifier(String rd, BigInteger dpnId) { return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData.class) .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry.class, new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey(rd)) .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList.class, new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListKey(dpnId)).build(); @@ -104,10 +123,23 @@ public class FibUtil { static InstanceIdentifier getVpnToExtrarouteIdentifier(String vrfId, String ipPrefix) { return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnToExtraroute.class) - .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.Vpn.class, new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.VpnKey(vrfId)).child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.vpn.Extraroute.class, + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.Vpn + .class, new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to + .extraroute.VpnKey(vrfId)).child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn + .rev130911.vpn.to.extraroute.vpn.Extraroute.class, new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.vpn.ExtrarouteKey(ipPrefix)).build(); } + static InstanceIdentifier getVpnInstanceOpDataIdentifier(String rd) { + return InstanceIdentifier.builder(VpnInstanceOpData.class) + .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd)).build(); + } + + static Optional getVpnInstanceOpData(DataBroker broker, String rd) { + InstanceIdentifier id = getVpnInstanceOpDataIdentifier(rd); + return read(broker, LogicalDatastoreType.OPERATIONAL, id); + } + static String getNextHopLabelKey(String rd, String prefix){ String key = rd + FibConstants.SEPARATOR + prefix; return key; @@ -126,17 +158,14 @@ public class FibUtil { } } - static InstanceIdentifier + static InstanceIdentifier getVpnInstanceToVpnIdIdentifier(String vpnName) { return InstanceIdentifier.builder(VpnInstanceToVpnId.class) - .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id - .VpnInstance.class, - new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id - .VpnInstanceKey(vpnName)).build(); + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance.class, + new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstanceKey(vpnName)).build(); } - static long getVpnId(DataBroker broker, String vpnName) { + public static long getVpnId(DataBroker broker, String vpnName) { InstanceIdentifier id @@ -152,15 +181,229 @@ public class FibUtil { return vpnId; } + /** + * Retrieves the VpnInstance name (typically the VPN Uuid) out from the route-distinguisher + * + * @param broker + * @param rd + * @return + */ + public static Optional getVpnNameFromRd(DataBroker broker, String rd) { + Optional vpnInstanceOpData = getVpnInstanceOpData(broker, rd); + return Optional.fromNullable(vpnInstanceOpData.isPresent() ? vpnInstanceOpData.get().getVpnInstanceName() + : null); + } + + static List getAllInterVpnLinks(DataBroker broker) { + InstanceIdentifier interVpnLinksIid = InstanceIdentifier.builder(InterVpnLinks.class).build(); + + Optional interVpnLinksOpData = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, + interVpnLinksIid); + + return ( interVpnLinksOpData.isPresent() ) ? interVpnLinksOpData.get().getInterVpnLink() + : new ArrayList(); + } + + /** + * Returns the instance identifier for a given vpnLinkName + * + * @param vpnLinkName + * @return + */ + public static InstanceIdentifier getInterVpnLinkStateIid(String vpnLinkName) { + return InstanceIdentifier.builder(InterVpnLinkStates.class).child(InterVpnLinkState.class, new InterVpnLinkStateKey(vpnLinkName)).build(); + } + + /** + * Checks if the InterVpnLink is in Active state + * + * @param broker + * @param vpnLinkName + * @return + */ + public static boolean isInterVpnLinkActive(DataBroker broker, String vpnLinkName) { + Optional interVpnLinkState = getInterVpnLinkState(broker, vpnLinkName); + if ( !interVpnLinkState.isPresent() ) { + LOG.warn("Could not find Operative State for InterVpnLink {}", vpnLinkName); + return false; + } + + return interVpnLinkState.get().getState().equals(InterVpnLinkState.State.Active); + } + + /** + * Checks if the state of the interVpnLink + * + * @param broker + * @param vpnLinkName + * @return + */ + public static Optional getInterVpnLinkState(DataBroker broker, String vpnLinkName) { + InstanceIdentifier vpnLinkStateIid = getInterVpnLinkStateIid(vpnLinkName); + return read(broker, LogicalDatastoreType.CONFIGURATION, vpnLinkStateIid); + } + + /** + * Retrieves the InterVpnLink in which the VPN, represented by its Uuid, + * participates + * + * @param dataBroker + * @param vpnUuid + * @return The InterVpnLink or Optional.absent() if the VPN does not + * participate in an InterVpnLink + */ + public static Optional getInterVpnLinkByVpnUuid(DataBroker dataBroker, String vpnUuid) { + List interVpnLinkList = getAllInterVpnLinks(dataBroker); + for (InterVpnLink interVpnLink : interVpnLinkList) { + if (interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(vpnUuid) + || interVpnLink.getSecondEndpoint().getVpnUuid().getValue().equals(vpnUuid)) { + LOG.debug("InterVpnLink found for VPN {}. Details: vpn1=( uuid={} endpoint={}) vpn2=( uuid={} endpoint={} ))", + vpnUuid, interVpnLink.getFirstEndpoint().getVpnUuid(), + interVpnLink.getFirstEndpoint().getIpAddress(), interVpnLink.getSecondEndpoint().getVpnUuid(), + interVpnLink.getSecondEndpoint().getIpAddress()); + return Optional.fromNullable(interVpnLink); + } + } + LOG.debug("Could not find a suitable InterVpnLink for VpnUuid={}", vpnUuid); + return Optional.absent(); + } + + /** + * Retrieves the InterVpnLink in which the VPN, represented by its + * Route-Distinguisher, participates. + * + * @param dataBroker + * @param rd + * @return The InterVpnLink or Optional.absent() if the VPN does not + * participate in an InterVpnLink + */ + public static Optional getInterVpnLinkByRd(DataBroker dataBroker, String rd) { + Optional vpnId = getVpnNameFromRd(dataBroker, rd); + if ( !vpnId.isPresent() ) { + LOG.debug("Could not find vpnId for RouteDistinguisher {}", rd); + return Optional.absent(); + } + + return getInterVpnLinkByVpnUuid(dataBroker, vpnId.get()); + } + + /** + * Checks if the route-distinguisher is involved in any inter-vpn-link, which is returned if its found. + * + * @param dataBroker + * @param rd + * @return + */ + public static Optional getActiveInterVpnLinkFromRd(DataBroker dataBroker, String rd) { + + Optional interVpnLink = getInterVpnLinkByRd(dataBroker, rd); + if ( interVpnLink.isPresent() ) { + if ( isInterVpnLinkActive(dataBroker, interVpnLink.get().getName()) ) { + return interVpnLink; + } else { + LOG.warn("InterVpnLink for RouteDistinguisher {} exists, but it's in error state. InterVpnLink={}", + rd, interVpnLink.get().getName()); + return Optional.absent(); + } + } + return Optional.absent(); + } + + /** + * Checks if the route-distinguisher is involved in any inter-vpn-link. In that case, this method will return + * the endpoint of the other vpn involved in the inter-vpn-link. + * + * @param dataBroker + * @param rd + * @return + */ + public static Optional getInterVpnLinkOppositeEndPointIpAddress(DataBroker dataBroker, String rd) { + Optional vpnId = getVpnNameFromRd(dataBroker, rd); + if ( !vpnId.isPresent() ) { + LOG.debug("Could not find the VpnName for RouteDistinguisher {}", rd); + return Optional.absent(); + } + List interVpnLinkList = getAllInterVpnLinks(dataBroker); + if (!interVpnLinkList.isEmpty()) { + for (InterVpnLink interVpnLink : interVpnLinkList) { + if (interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(vpnId)) { + return Optional.fromNullable(interVpnLink.getSecondEndpoint().getVpnUuid().getValue()); + } else if (interVpnLink.getSecondEndpoint().getIpAddress().getValue().equals(vpnId)) { + return Optional.fromNullable(interVpnLink.getFirstEndpoint().getIpAddress().getValue()); + } + } + } + return Optional.absent(); + } + + /** + * Obtains the route-distinguisher for a given vpn-name + * + * @param broker + * @param vpnName + * @return + */ + public static String getVpnRd(DataBroker broker, String vpnName) { + InstanceIdentifier id + = getVpnInstanceToVpnIdIdentifier(vpnName); + Optional vpnInstance + = read(broker, LogicalDatastoreType.CONFIGURATION, id); + + String rd = null; + if(vpnInstance.isPresent()) { + rd = vpnInstance.get().getVrfId(); + } + return rd; + } + + /** + * Returns a boolean value which indicates if the endpoint's IP received as parameter belongs to any InterVpnLink. + * + * @param broker + * @param endpointIp IP to serch for. + * @return + */ + public static boolean getInterVpnLinkByEndpointIp(DataBroker broker, String endpointIp) { + List allInterVpnLinks = getAllInterVpnLinks(broker); + for (InterVpnLink interVpnLink : allInterVpnLinks) { + if (interVpnLink.getFirstEndpoint().getIpAddress().getValue().equals(endpointIp) + || interVpnLink.getSecondEndpoint().getIpAddress().getValue().equals(endpointIp)) { + return true; + } + } + return false; + } + + public static int getUniqueId(IdManagerService idManager, String poolName, String idKey) { + AllocateIdInput getIdInput = new AllocateIdInputBuilder().setPoolName(poolName).setIdKey(idKey).build(); + + try { + Future> result = idManager.allocateId(getIdInput); + RpcResult rpcResult = result.get(); + if (rpcResult.isSuccessful()) { + return rpcResult.getResult().getIdValue().intValue(); + } else { + LOG.warn("RPC Call to Get Unique Id returned with Errors {}", rpcResult.getErrors()); + } + } catch (InterruptedException | ExecutionException e) { + LOG.warn("Exception when getting Unique Id", e); + } + return 0; + } + static final FutureCallback DEFAULT_CALLBACK = new FutureCallback() { + @Override public void onSuccess(Void result) { LOG.debug("Success in Datastore operation"); } + @Override public void onFailure(Throwable error) { LOG.error("Error in Datastore operation", error); - } + }; }; } diff --git a/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/L3VPNTransportTypes.java b/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/L3VPNTransportTypes.java index 89d93a9b2b..9239f61ecc 100644 --- a/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/L3VPNTransportTypes.java +++ b/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/L3VPNTransportTypes.java @@ -27,7 +27,7 @@ public enum L3VPNTransportTypes { this.transportType = transportType; } - private static final Map strToTypeMap = new HashMap<>(); + private static final Map strToTypeMap = new HashMap(); static { for (L3VPNTransportTypes type : L3VPNTransportTypes.values()) { strToTypeMap.put(type.transportType, type); 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 b4f2917808..ba7ccbad42 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 @@ -94,25 +94,31 @@ public class NexthopManager implements AutoCloseable { private static final String NEXTHOP_ID_POOL_NAME = "nextHopPointerPool"; private static final long FIXED_DELAY_IN_MILLISECONDS = 4000; private L3VPNTransportTypes configuredTransportTypeL3VPN = L3VPNTransportTypes.Invalid; + private Long waitTimeForSyncInstall; private static final FutureCallback DEFAULT_CALLBACK = - new FutureCallback() { - public void onSuccess(Void result) { - LOG.debug("Success in Datastore write operation"); - } - public void onFailure(Throwable error) { - LOG.error("Error in Datastore write operation", error); - } - }; + new FutureCallback() { + @Override + public void onSuccess(Void result) { + LOG.debug("Success in Datastore write operation"); + } + @Override + public void onFailure(Throwable error) { + LOG.error("Error in Datastore write operation", error); + }; + }; /** - * Provides nexthop functions - * Creates group ID pool - * - * @param db - dataBroker reference - */ + * Provides nexthop functions + * Creates group ID pool + * + * @param db - dataBroker reference + */ public NexthopManager(final DataBroker db) { broker = db; + waitTimeForSyncInstall = Long.getLong("wait.time.sync.install"); + if (waitTimeForSyncInstall == null) + waitTimeForSyncInstall = 1000L; } @Override @@ -139,10 +145,10 @@ public class NexthopManager implements AutoCloseable { protected void createNexthopPointerPool() { CreateIdPoolInput createPool = new CreateIdPoolInputBuilder() - .setPoolName(NEXTHOP_ID_POOL_NAME) - .setLow(150000L) - .setHigh(175000L) - .build(); + .setPoolName(NEXTHOP_ID_POOL_NAME) + .setLow(150000L) + .setHigh(175000L) + .build(); //TODO: Error handling Future> result = idManager.createIdPool(createPool); LOG.trace("NextHopPointerPool result : {}", result); @@ -167,8 +173,8 @@ public class NexthopManager implements AutoCloseable { protected long createNextHopPointer(String nexthopKey) { AllocateIdInput getIdInput = new AllocateIdInputBuilder() - .setPoolName(NEXTHOP_ID_POOL_NAME).setIdKey(nexthopKey) - .build(); + .setPoolName(NEXTHOP_ID_POOL_NAME).setIdKey(nexthopKey) + .build(); //TODO: Proper error handling once IdManager code is complete try { Future> result = idManager.allocateId(getIdInput); @@ -182,8 +188,8 @@ public class NexthopManager implements AutoCloseable { protected void removeNextHopPointer(String nexthopKey) { ReleaseIdInput idInput = new ReleaseIdInputBuilder(). - setPoolName(NEXTHOP_ID_POOL_NAME) - .setIdKey(nexthopKey).build(); + setPoolName(NEXTHOP_ID_POOL_NAME) + .setIdKey(nexthopKey).build(); try { Future> result = idManager.releaseId(idInput); RpcResult rpcResult = result.get(); @@ -196,30 +202,30 @@ public class NexthopManager implements AutoCloseable { } protected List getEgressActionsForInterface(String ifName) { - List listActionInfo = new ArrayList<>(); + List listActionInfo = new ArrayList(); try { Future> result = - interfaceManager.getEgressActionsForInterface( - new GetEgressActionsForInterfaceInputBuilder().setIntfName(ifName).build()); + interfaceManager.getEgressActionsForInterface( + new GetEgressActionsForInterfaceInputBuilder().setIntfName(ifName).build()); RpcResult rpcResult = result.get(); if(!rpcResult.isSuccessful()) { LOG.warn("RPC Call to Get egress actions for interface {} returned with Errors {}", ifName, rpcResult.getErrors()); } else { List actions = - rpcResult.getResult().getAction(); + rpcResult.getResult().getAction(); for (Action action : actions) { org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action actionClass = action.getAction(); if (actionClass instanceof OutputActionCase) { listActionInfo.add(new ActionInfo(ActionType.output, - new String[] {((OutputActionCase)actionClass).getOutputAction() - .getOutputNodeConnector().getValue()})); + new String[] {((OutputActionCase)actionClass).getOutputAction() + .getOutputNodeConnector().getValue()})); } else if (actionClass instanceof PushVlanActionCase) { listActionInfo.add(new ActionInfo(ActionType.push_vlan, new String[] {})); } else if (actionClass instanceof SetFieldCase) { if (((SetFieldCase)actionClass).getSetField().getVlanMatch() != null) { int vlanVid = ((SetFieldCase)actionClass).getSetField().getVlanMatch().getVlanId().getVlanId().getValue(); listActionInfo.add(new ActionInfo(ActionType.set_field_vlan_vid, - new String[] { Long.toString(vlanVid) })); + new String[] { Long.toString(vlanVid) })); } } } @@ -232,11 +238,13 @@ public class NexthopManager implements AutoCloseable { protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) { Class tunType = getReqTunType(getReqTransType().toUpperCase()); + Future> result; try { - Future> result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder() - .setSourceDpid(srcDpId) - .setDestinationDpid(dstDpId) - .setTunnelType(tunType).build()); + result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder() + .setSourceDpid(srcDpId) + .setDestinationDpid(dstDpId) + .setTunnelType(tunType) + .build()); RpcResult rpcResult = result.get(); if(!rpcResult.isSuccessful()) { LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors()); @@ -246,17 +254,20 @@ public class NexthopManager implements AutoCloseable { } catch (InterruptedException | ExecutionException e) { LOG.warn("Exception when getting tunnel interface Id for tunnel between {} and {}", srcDpId, dstDpId, e); } - return null; } - protected String getTunnelInterfaceName(BigInteger srcDpId, IpAddress dstIp) { + + + protected String getTunnelInterfaceName(BigInteger srcDpId, org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress dstIp) { Class tunType = getReqTunType(getReqTransType().toUpperCase()); + Future> result; try { - Future> result = itmManager.getInternalOrExternalInterfaceName(new GetInternalOrExternalInterfaceNameInputBuilder() - .setSourceDpid(srcDpId) - .setDestinationIp(dstIp) - .setTunnelType(tunType).build()); + result = itmManager.getInternalOrExternalInterfaceName(new GetInternalOrExternalInterfaceNameInputBuilder() + .setSourceDpid(srcDpId) + .setDestinationIp(dstIp) + .setTunnelType(tunType) + .build()); RpcResult rpcResult = result.get(); if(!rpcResult.isSuccessful()) { LOG.warn("RPC Call to getTunnelInterfaceName returned with Errors {}", rpcResult.getErrors()); @@ -266,7 +277,6 @@ public class NexthopManager implements AutoCloseable { } catch (InterruptedException | ExecutionException e) { LOG.warn("Exception when getting tunnel interface Id for tunnel between {} and {}", srcDpId, dstIp, e); } - return null; } @@ -276,12 +286,13 @@ public class NexthopManager implements AutoCloseable { String nextHopLockStr = new String(vpnId + ipAddress); synchronized (nextHopLockStr.intern()) { VpnNexthop nexthop = getVpnNexthop(vpnId, ipAddress); - LOG.trace("nexthop: {}", nexthop); + LOG.trace("nexthop: {} retrieved for vpnId {}, prefix {}, ifName {} on dpn {}", nexthop, + vpnId, ipAddress, ifName, dpnId); if (nexthop == null) { Optional adjacencyData = read(LogicalDatastoreType.OPERATIONAL, getAdjacencyIdentifier(ifName, ipAddress)); String macAddress = adjacencyData.isPresent() ? adjacencyData.get().getMacAddress() : null; - List listBucketInfo = new ArrayList<>(); + List listBucketInfo = new ArrayList(); List listActionInfo = getEgressActionsForInterface(ifName); BucketInfo bucket = new BucketInfo(listActionInfo); // MAC re-write @@ -294,13 +305,20 @@ public class NexthopManager implements AutoCloseable { } listBucketInfo.add(bucket); GroupEntity groupEntity = MDSALUtil.buildGroupEntity( - dpnId, groupId, ipAddress, GroupTypes.GroupIndirect, listBucketInfo); - - //update MD-SAL DS - addVpnNexthopToDS(dpnId, vpnId, ipAddress, groupId); + dpnId, groupId, ipAddress, GroupTypes.GroupAll, listBucketInfo); + LOG.trace("Install LNH Group: id {}, mac address {}, interface {} for prefix {}", groupId, macAddress, ifName, ipAddress); // install Group mdsalManager.syncInstallGroup(groupEntity, FIXED_DELAY_IN_MILLISECONDS); + try{ + LOG.info("Sleeping for {} to wait for the groups to get programmed.", waitTimeForSyncInstall); + Thread.sleep(waitTimeForSyncInstall); + }catch(InterruptedException error){ + LOG.warn("Error while waiting for group {} to install.", groupId); + LOG.debug("{}", error); + } + //update MD-SAL DS + addVpnNexthopToDS(dpnId, vpnId, ipAddress, groupId); } else { //nexthop exists already; a new flow is going to point to it, increment the flowrefCount by 1 @@ -318,7 +336,7 @@ public class NexthopManager implements AutoCloseable { protected void addVpnNexthopToDS(BigInteger dpnId, long vpnId, String ipPrefix, long egressPointer) { InstanceIdentifierBuilder idBuilder = InstanceIdentifier.builder( - L3nexthop.class) + L3nexthop.class) .child(VpnNexthops.class, new VpnNexthopsKey(vpnId)); // Add nexthop to vpn node @@ -349,8 +367,8 @@ public class NexthopManager implements AutoCloseable { // check if vpn node is there InstanceIdentifierBuilder idBuilder = - InstanceIdentifier.builder(L3nexthop.class).child(VpnNexthops.class, - new VpnNexthopsKey(vpnId)); + InstanceIdentifier.builder(L3nexthop.class).child(VpnNexthops.class, + new VpnNexthopsKey(vpnId)); InstanceIdentifier id = idBuilder.build(); Optional vpnNexthops = read(LogicalDatastoreType.OPERATIONAL, id); if (vpnNexthops.isPresent()) { @@ -369,19 +387,18 @@ public class NexthopManager implements AutoCloseable { } - public String getRemoteNextHopPointer(BigInteger localDpnId, BigInteger remoteDpnId, - long vpnId, String prefixIp, String nextHopIp) { + public String getRemoteNextHopPointer(BigInteger remoteDpnId, long vpnId, String prefixIp, String nextHopIp) { String tunnelIfName = null; - LOG.trace("getRemoteNextHopPointer: input [localDpnId {} remoteDpnId {}, vpnId {}, prefixIp {}, nextHopIp {} ]", - localDpnId, remoteDpnId, vpnId, prefixIp, nextHopIp); + LOG.trace("getRemoteNextHopPointer: input [remoteDpnId {}, vpnId {}, prefixIp {}, nextHopIp {} ]", + remoteDpnId, vpnId, prefixIp, nextHopIp); - LOG.trace("getRemoteNextHopPointer: Calling ITM with localDpnId {} ", localDpnId); if (nextHopIp != null && !nextHopIp.isEmpty()) { try{ // here use the config for tunnel type param - tunnelIfName = getTunnelInterfaceName(remoteDpnId, IpAddressBuilder.getDefaultInstance(nextHopIp)); - }catch(Exception ex){ - LOG.error("Error while retrieving nexthop pointer for nexthop {} : ", nextHopIp, ex.getMessage()); + tunnelIfName = getTunnelInterfaceName(remoteDpnId, org.opendaylight.yang.gen.v1.urn.ietf.params.xml + .ns.yang.ietf.inet.types.rev130715.IpAddressBuilder.getDefaultInstance(nextHopIp)); + } catch(Exception ex){ + LOG.error("Error while retrieving nexthop pointer for nexthop {} : ", nextHopIp, ex.getMessage()); } } return tunnelIfName; @@ -405,7 +422,7 @@ public class NexthopManager implements AutoCloseable { delete(LogicalDatastoreType.OPERATIONAL, id); } - + public void removeLocalNextHop(BigInteger dpnId, Long vpnId, String ipAddress) { String nextHopLockStr = new String(vpnId + ipAddress); @@ -415,14 +432,14 @@ public class NexthopManager implements AutoCloseable { int newFlowrefCnt = nh.getFlowrefCount() - 1; if (newFlowrefCnt == 0) { //remove the group only if there are no more flows using this group GroupEntity groupEntity = MDSALUtil.buildGroupEntity( - dpnId, nh.getEgressPointer(), ipAddress, GroupTypes.GroupIndirect, null); + dpnId, nh.getEgressPointer(), ipAddress, GroupTypes.GroupAll, null); // remove Group ... mdsalManager.removeGroup(groupEntity); //update MD-SAL DS removeVpnNexthopFromDS(vpnId, ipAddress); //release groupId removeNextHopPointer(getNextHopKey(vpnId, ipAddress)); - LOG.debug("Local Next hop for {} on dpn {} successfully deleted", ipAddress, dpnId); + LOG.debug("Local Next hop {} for {} {} on dpn {} successfully deleted", nh.getEgressPointer(), vpnId, ipAddress, dpnId); } else { //just update the flowrefCount of the vpnNexthop VpnNexthop currNh = new VpnNexthopBuilder().setKey(new VpnNexthopKey(ipAddress)).setFlowrefCount(newFlowrefCnt).build(); @@ -439,7 +456,7 @@ public class NexthopManager implements AutoCloseable { private Optional read(LogicalDatastoreType datastoreType, - InstanceIdentifier path) { + InstanceIdentifier path) { ReadOnlyTransaction tx = broker.newReadOnlyTransaction(); @@ -454,14 +471,14 @@ public class NexthopManager implements AutoCloseable { } private void asyncWrite(LogicalDatastoreType datastoreType, - InstanceIdentifier path, T data, FutureCallback callback) { + InstanceIdentifier path, T data, FutureCallback callback) { WriteTransaction tx = broker.newWriteOnlyTransaction(); tx.merge(datastoreType, path, data, true); Futures.addCallback(tx.submit(), callback); } private void syncWrite(LogicalDatastoreType datastoreType, - InstanceIdentifier path, T data, FutureCallback callback) { + InstanceIdentifier path, T data, FutureCallback callback) { WriteTransaction tx = broker.newWriteOnlyTransaction(); tx.merge(datastoreType, path, data, true); tx.submit(); @@ -475,8 +492,8 @@ public class NexthopManager implements AutoCloseable { private InstanceIdentifier getAdjacencyIdentifier(String vpnInterfaceName, String ipAddress) { return InstanceIdentifier.builder(VpnInterfaces.class) - .child(VpnInterface.class, new VpnInterfaceKey(vpnInterfaceName)).augmentation( - Adjacencies.class).child(Adjacency.class, new AdjacencyKey(ipAddress)).build(); + .child(VpnInterface.class, new VpnInterfaceKey(vpnInterfaceName)).augmentation( + Adjacencies.class).child(Adjacency.class, new AdjacencyKey(ipAddress)).build(); } InstanceIdentifier getAdjListPath(String vpnInterfaceName) { @@ -485,7 +502,6 @@ public class NexthopManager implements AutoCloseable { Adjacencies.class).build(); } - public void setConfTransType(String service,String transportType) { if (!service.toUpperCase().equals("L3VPN")) { @@ -557,7 +573,7 @@ public class NexthopManager implements AutoCloseable { return confTransType; } - Class getReqTunType(String transportType) { + public Class getReqTunType(String transportType) { if (transportType.equals("VXLAN")) { return TunnelTypeVxlan.class; } else if (transportType.equals("GRE")) { @@ -566,4 +582,16 @@ public class NexthopManager implements AutoCloseable { return TunnelTypeMplsOverGre.class; } } + + public String getTransportTypeStr ( String tunType) { + if (tunType.equals(TunnelTypeVxlan.class.toString())) { + return ITMConstants.TUNNEL_TYPE_VXLAN; + } else if (tunType.equals(TunnelTypeGre.class.toString())) { + return ITMConstants.TUNNEL_TYPE_GRE; + } else if (tunType.equals(TunnelTypeMplsOverGre.class.toString())){ + return ITMConstants.TUNNEL_TYPE_MPLS_OVER_GRE; + } else { + return ITMConstants.TUNNEL_TYPE_INVALID; + } + } } diff --git a/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/fibmanager/impl/rev150325/FibmanagerImplModule.java b/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/fibmanager/impl/rev150325/FibmanagerImplModule.java index ab4aceaf3e..e15f1cc8cc 100644 --- a/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/fibmanager/impl/rev150325/FibmanagerImplModule.java +++ b/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/fibmanager/impl/rev150325/FibmanagerImplModule.java @@ -40,4 +40,4 @@ public class FibmanagerImplModule extends org.opendaylight.yang.gen.v1.urn.opend return provider; } -} +} \ No newline at end of file diff --git a/vpnservice/fibmanager/fibmanager-impl/src/test/java/org/opendaylight/netvirt/fibmanager/test/FibManagerTest.java b/vpnservice/fibmanager/fibmanager-impl/src/test/java/org/opendaylight/netvirt/fibmanager/test/FibManagerTest.java index 90565b64be..5364660ec0 100644 --- a/vpnservice/fibmanager/fibmanager-impl/src/test/java/org/opendaylight/netvirt/fibmanager/test/FibManagerTest.java +++ b/vpnservice/fibmanager/fibmanager-impl/src/test/java/org/opendaylight/netvirt/fibmanager/test/FibManagerTest.java @@ -16,6 +16,7 @@ import static org.mockito.Matchers.any; import static org.mockito.Mockito.when; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import org.junit.runner.RunWith; @@ -27,6 +28,7 @@ import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.netvirt.bgpmanager.api.RouteOrigin; import org.opendaylight.netvirt.vpnmanager.api.IVpnManager; import org.opendaylight.netvirt.fibmanager.FibManager; import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager; @@ -72,18 +74,21 @@ public class FibManagerTest { VrfEntry vrfEntry; InstanceIdentifier identifier; VrfEntryBuilder vrfbuilder; + private static final String testVpnInstanceName = "95486250-4ad7-418f-9030-2df37f98ad24"; private static final String testRd = "100:1"; private static final String prefix = "1.1.2.3"; private static final String nexthop = "1.1.1.1"; private static final int label = 10; + RouteOrigin origin = RouteOrigin.STATIC; BigInteger Dpn; private static final long vpnId = 101L; private static final long vpnIntfCnt = 2; + private static final Boolean isCleanupComplete = Boolean.FALSE; private void SetupMocks() { Dpn = BigInteger.valueOf(100000L); identifier = buildVrfEntryId(testRd, prefix); - vrfEntry = buildVrfEntry(testRd, prefix, nexthop, label); + vrfEntry = buildVrfEntry(testRd, prefix, Arrays.asList(nexthop), label, origin); fibmgr.setMdsalManager(mdsalManager); fibmgr.setVpnmanager(vpnmanager); when(vrfTableKey.getRouteDistinguisher()).thenReturn(testRd); @@ -92,13 +97,14 @@ public class FibManagerTest { @Before public void setUp() throws Exception { when( - dataBroker.registerDataChangeListener(any(LogicalDatastoreType.class), - any(InstanceIdentifier.class), any(DataChangeListener.class), - any(DataChangeScope.class))).thenReturn(dataChangeListenerRegistration); + dataBroker.registerDataChangeListener(any(LogicalDatastoreType.class), + any(InstanceIdentifier.class), any(DataChangeListener.class), + any(DataChangeScope.class))).thenReturn(dataChangeListenerRegistration); dataChangeEvent = new MockDataChangedEvent(); vrfbuilder = new VrfEntryBuilder(); fibmgr = new FibManager(dataBroker) { + @Override protected VpnInstanceOpDataEntry getVpnInstance(String rd) { return new VpnInstanceOpDataEntry() { @@ -117,9 +123,17 @@ public class FibManagerTest { return testRd; } + @Override + public String getVpnInstanceName() { + return testVpnInstanceName; + } + @Override public Long getVpnInterfaceCount() { return vpnIntfCnt; } + @Override + public Boolean isCleanupComplete(){return isCleanupComplete;} + @Override public List getVpnToDpnList() { List vpnToDpnLists = new ArrayList<>(); @@ -144,7 +158,7 @@ public class FibManagerTest { @Override public > E getAugmentation( - Class augmentationType) { + Class augmentationType) { return null; } @@ -183,23 +197,24 @@ public class FibManagerTest { //Mockito.verify(mdsalManager, Mockito.times(2)).installFlow(any(FlowEntity.class)); } - private VrfEntry buildVrfEntry(String rd, String prefix, String nexthop, int label) { - return new VrfEntryBuilder().setDestPrefix(prefix).setNextHopAddress(nexthop) - .setLabel((long) label).build(); + private VrfEntry buildVrfEntry(String rd, String prefix, List nextHopList, int label, RouteOrigin origin) { + + return new VrfEntryBuilder().setDestPrefix(prefix).setNextHopAddressList(nextHopList) + .setLabel((long) label).setOrigin(origin.getValue()).build(); } public static InstanceIdentifier buildVrfTableId(String rd) { InstanceIdentifierBuilder idBuilder = - InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)); + InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)); InstanceIdentifier vrfTableId = idBuilder.build(); return vrfTableId; } public static InstanceIdentifier buildVrfEntryId(String rd, String prefix) { InstanceIdentifierBuilder idBuilder = - InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)) - .child(VrfEntry.class, new VrfEntryKey(prefix)); + InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)) + .child(VrfEntry.class, new VrfEntryKey(prefix)); InstanceIdentifier vrfEntryId = idBuilder.build(); return vrfEntryId; } -} +} \ No newline at end of file diff --git a/vpnservice/fibmanager/fibmanager-shell/src/main/java/org/opendaylight/netvirt/fibmanager/shell/ShowTransportTypeCommand.java b/vpnservice/fibmanager/fibmanager-shell/src/main/java/org/opendaylight/netvirt/fibmanager/shell/ShowTransportTypeCommand.java index 3b04669ab5..1400de1a46 100644 --- a/vpnservice/fibmanager/fibmanager-shell/src/main/java/org/opendaylight/netvirt/fibmanager/shell/ShowTransportTypeCommand.java +++ b/vpnservice/fibmanager/fibmanager-shell/src/main/java/org/opendaylight/netvirt/fibmanager/shell/ShowTransportTypeCommand.java @@ -32,4 +32,4 @@ public class ShowTransportTypeCommand extends OsgiCommandSupport { return null; } -} +} \ No newline at end of file diff --git a/vpnservice/fibmanager/fibmanager-shell/src/main/java/org/opendaylight/netvirt/fibmanager/shell/confTransportL3VPNCommand.java b/vpnservice/fibmanager/fibmanager-shell/src/main/java/org/opendaylight/netvirt/fibmanager/shell/confTransportL3VPNCommand.java index 119da72347..bf8688a43c 100644 --- a/vpnservice/fibmanager/fibmanager-shell/src/main/java/org/opendaylight/netvirt/fibmanager/shell/confTransportL3VPNCommand.java +++ b/vpnservice/fibmanager/fibmanager-shell/src/main/java/org/opendaylight/netvirt/fibmanager/shell/confTransportL3VPNCommand.java @@ -14,7 +14,7 @@ import org.opendaylight.netvirt.fibmanager.L3VPNTransportTypes; import org.opendaylight.netvirt.fibmanager.api.IFibManager; @Command(scope = "vpnservice", name = "configureTransportType", description = "Configure Preferred Transport Type for L3VPN service") -public class confTransportL3VPNCommand extends OsgiCommandSupport { +public class confTransportL3VPNCommand extends OsgiCommandSupport { private IFibManager fibManager; @Option(name = "-s", aliases = {"--service"}, description = "Service", required = false, multiValued = false) @@ -42,7 +42,7 @@ public class confTransportL3VPNCommand extends OsgiCommandSupport { return null; } - String cachedTransType = fibManager.getReqTransType(); + String cachedTransType = fibManager.getConfTransType(); if (cachedTransType.equals(transportType.toUpperCase())) { System.out.println("Transport type already configured as " + cachedTransType); return null; @@ -51,7 +51,6 @@ public class confTransportL3VPNCommand extends OsgiCommandSupport { if ((cachedTransType.equals(L3VPNTransportTypes.Invalid.getTransportType())) || (!fibManager.isVPNConfigured())) { fibManager.setConfTransType(service, transportType.toUpperCase()); - System.out.println("Setting it to " + transportType.toUpperCase() + "writing into the config DS as well."); fibManager.writeConfTransTypeConfigDS(); } else { System.out.println( "VPN service already configured with " + cachedTransType + @@ -60,4 +59,6 @@ public class confTransportL3VPNCommand extends OsgiCommandSupport { } return null; } -} + + +} \ No newline at end of file diff --git a/vpnservice/vpnmanager/vpnmanager-api/src/main/yang/inter-vpn-link.yang b/vpnservice/vpnmanager/vpnmanager-api/src/main/yang/inter-vpn-link.yang new file mode 100644 index 0000000000..0639588d2e --- /dev/null +++ b/vpnservice/vpnmanager/vpnmanager-api/src/main/yang/inter-vpn-link.yang @@ -0,0 +1,122 @@ +module inter-vpn-link { + + namespace "urn:opendaylight:params:xml:ns:yang:netvirt:inter-vpn-link"; + prefix "inter-vpn-link"; + + import ietf-inet-types { prefix inet; revision-date "2013-07-15"; } + + import ietf-yang-types { prefix yang; } + + import config { prefix config; revision-date 2013-04-05; } + + description + "Service definition for inter-vpn-link project"; + + revision "2016-03-11" { + description + "Initial revision"; + } + + grouping vpn-endpoint-attribs { + leaf vpn-uuid { + mandatory "true"; + type yang:uuid; + description "UUID of the VPN to which this endpoint belongs to"; + } + + leaf ip-address { + mandatory "true"; + type inet:ipv4-address; + description "IP address of the endpoint"; + } + } + + + grouping vpn-endpoint-state-attribs { + leaf vpn-uuid { + type yang:uuid; + description "UUID of the VPN to which this endpoint belongs to"; + } + + leaf-list dp-id { + type uint64; + + description "list of DPNs where this endpoint of the Link has been instantiated"; + } + + leaf lport-tag { + type uint16; + + } + } + + container inter-vpn-links { + list inter-vpn-link { + key "name"; + max-elements "unbounded"; + min-elements "0"; + + leaf name { + mandatory "true"; + type string; + description "Inter VPN link name"; + } + + + container first-endpoint { + uses vpn-endpoint-attribs; + } + + container second-endpoint { + uses vpn-endpoint-attribs; + } + + leaf bgp-routes-leaking { + mandatory "true"; + type boolean; + description "Flag to enable the leaking of BGP routes learnt from one VPN to another VPN"; + } + + must "first-endpoint and second-endpoint"; // To ensure both endpoints are present + } + } + + container inter-vpn-link-states { + list inter-vpn-link-state { + key "inter-vpn-link-name"; + + leaf inter-vpn-link-name { + type string; + } + + leaf state { + type enumeration { + enum active; + enum error; + } + description "Holds the current state of the InterVPN Link"; + } + + container first-endpoint-state { + uses vpn-endpoint-state-attribs; + } + + container second-endpoint-state { + uses vpn-endpoint-state-attribs; + } + + leaf error-description { + type string; + } + } + } + + notification inter-vpn-link-creation-error { + container inter-vpn-link-creation-error-message { + leaf error-message { + type "string"; + } + } + } + +} diff --git a/vpnservice/vpnmanager/vpnmanager-api/src/main/yang/odl-l3vpn.yang b/vpnservice/vpnmanager/vpnmanager-api/src/main/yang/odl-l3vpn.yang index 76dc9af1e3..cec1e7c5ab 100644 --- a/vpnservice/vpnmanager/vpnmanager-api/src/main/yang/odl-l3vpn.yang +++ b/vpnservice/vpnmanager/vpnmanager-api/src/main/yang/odl-l3vpn.yang @@ -102,6 +102,9 @@ module odl-l3vpn { list vpn-instance-op-data-entry { key vrf-id; leaf vpn-id { type uint32;} + leaf vpn-instance-name { + type string; + } leaf vrf-id { description "The vrf-id command configures a route distinguisher (RD) @@ -130,6 +133,7 @@ module odl-l3vpn { } } } + leaf cleanup_complete { type boolean;} } } 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 cd0ab785fd..d7dea34601 100644 --- 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 @@ -57,10 +57,15 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406. import java.math.BigInteger; import java.util.Collection; -import java.util.Iterator; import java.util.List; import java.util.ArrayList; -import java.util.concurrent.*; +import java.util.Arrays; +import java.util.Iterator; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; import com.google.common.base.Optional; @@ -741,7 +746,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener vrfEntryList = new ArrayList<>(); @@ -763,7 +768,8 @@ public class VpnInterfaceManager extends AbstractDataChangeListener vrfEntryList = new ArrayList();