From: Deepthi V V Date: Tue, 19 Jan 2016 14:00:14 +0000 (+0530) Subject: Bug: 5011 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=vpnservice.git;a=commitdiff_plain;h=ab27b7d22b7b23d63391621aad715d803ffdbf8c Bug: 5011 1) Extra routes should use switch's tunnel ip as nexthop 2) Fib should be in config datastore for clean up and stale marking on controller restart. Change-Id: I60cb38212ae9945b8e8e225e6734402747616a55 Signed-off-by: Deepthi V V --- diff --git a/fibmanager/fibmanager-api/src/main/yang/odl-fib.yang b/fibmanager/fibmanager-api/src/main/yang/odl-fib.yang index bea6c951..046855e3 100644 --- a/fibmanager/fibmanager-api/src/main/yang/odl-fib.yang +++ b/fibmanager/fibmanager-api/src/main/yang/odl-fib.yang @@ -32,7 +32,7 @@ module odl-fib { } container fibEntries { - config false; + config true; list vrfTables{ key "routeDistinguisher"; leaf routeDistinguisher {type string;} diff --git a/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibManager.java b/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibManager.java index 0135f1d1..80500315 100644 --- a/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibManager.java +++ b/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibManager.java @@ -43,6 +43,7 @@ import org.opendaylight.vpnservice.mdsalutil.NwConstants; import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager; import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.PrefixToInterface; import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstanceOpData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnToExtraroute; import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.VpnIds; import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.VpnIdsKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes; @@ -52,6 +53,11 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instanc import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.Vpn; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.VpnKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.vpn.Extraroute; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.vpn.ExtrarouteBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.vpn.ExtrarouteKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.FibEntries; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTables; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTablesKey; @@ -64,6 +70,9 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpc import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetTunnelTypeOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthop; +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.l3vpn.rev130911.Adjacencies; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.Adjacency; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; @@ -90,17 +99,6 @@ public class FibManager extends AbstractDataChangeListener implements public static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16); - 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); - }; - }; - public FibManager(final DataBroker db) { super(VrfEntry.class); broker = db; @@ -142,7 +140,7 @@ public class FibManager extends AbstractDataChangeListener implements private void registerListener(final DataBroker db) { try { - listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, + listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, getWildCardPath(), FibManager.this, DataChangeScope.SUBTREE); } catch (final Exception e) { LOG.error("FibManager DataChange listener registration fail!", e); @@ -150,31 +148,11 @@ public class FibManager extends AbstractDataChangeListener implements } } - private Optional read(LogicalDatastoreType datastoreType, - InstanceIdentifier path) { - - 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 InstanceIdentifier getWildCardPath() { return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class).child(VrfEntry.class); } - private void asyncWrite(LogicalDatastoreType datastoreType, - InstanceIdentifier path, T data, FutureCallback callback) { - WriteTransaction tx = broker.newWriteOnlyTransaction(); - tx.put(datastoreType, path, data, true); - Futures.addCallback(tx.submit(), callback); - } @Override protected void add(final InstanceIdentifier identifier, @@ -221,18 +199,20 @@ public class FibManager extends AbstractDataChangeListener implements public BigInteger createLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) { BigInteger localDpnId = BigInteger.ZERO; Prefixes localNextHopInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix()); - boolean staticRoute = false; + String localNextHopIP = vrfEntry.getDestPrefix(); - //If the vrf entry is a static/extra route, the nexthop of the entry would be a adjacency in the vpn if(localNextHopInfo == null) { - localNextHopInfo = getPrefixToInterface(vpnId, vrfEntry.getNextHopAddress() + "/32"); - staticRoute = true; + //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"; + } } if(localNextHopInfo != null) { localDpnId = localNextHopInfo.getDpnId(); - long groupId = nextHopManager.createLocalNextHop(vpnId, localDpnId, localNextHopInfo.getVpnInterfaceName(), - (staticRoute == true) ? vrfEntry.getNextHopAddress() + "/32" : vrfEntry.getDestPrefix()); + long groupId = nextHopManager.createLocalNextHop(vpnId, localDpnId, localNextHopInfo.getVpnInterfaceName(), localNextHopIP); List actionInfos = new ArrayList(); actionInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId)})); @@ -296,23 +276,28 @@ public class FibManager extends AbstractDataChangeListener implements public BigInteger deleteLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) { BigInteger localDpnId = BigInteger.ZERO; VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix()); - boolean staticRoute = false; + String localNextHopIP = vrfEntry.getDestPrefix(); - //If the vrf entry is a static/extra route, the nexthop of the entry would be a adjacency in the vpn if(localNextHopInfo == null) { - localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getNextHopAddress() + "/32"); - staticRoute = true; + //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()); + localNextHopIP = extra_route.getNexthopIp() + "/32"; + } } + if(localNextHopInfo != null) { localDpnId = localNextHopInfo.getDpnId(); - if (getPrefixToInterface(vpnId, (staticRoute == true) ? vrfEntry.getNextHopAddress() + "/32" : vrfEntry.getDestPrefix()) == null) { + //if (getPrefixToInterface(vpnId, (staticRoute == true) ? extra_route.getNextHopAddress() + "/32" : vrfEntry.getDestPrefix()) == null) + { makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, null /* invalid */, NwConstants.DEL_FLOW); makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), 0 /* invalid */, vrfEntry.getNextHopAddress(), NwConstants.DEL_FLOW); removeTunnelTableEntry(localDpnId, vrfEntry.getLabel()); - deleteLocalAdjacency(localDpnId, vpnId, (staticRoute == true) ? vrfEntry.getNextHopAddress() + "/32" : vrfEntry.getDestPrefix()); + deleteLocalAdjacency(localDpnId, vpnId, localNextHopIP); } } return localDpnId; @@ -325,10 +310,22 @@ public class FibManager extends AbstractDataChangeListener implements private Prefixes getPrefixToInterface(Long vpnId, String ipPrefix) { Optional localNextHopInfoData = - read(LogicalDatastoreType.OPERATIONAL, getPrefixToInterfaceIdentifier(vpnId, ipPrefix)); + 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) + .child(Vpn.class, new VpnKey(vrfId)).child(Extraroute.class, + new ExtrarouteKey(ipPrefix)).build(); + } + + private Extraroute getVpnToExtraroute(String rd, String ipPrefix) { + Optional extraRouteInfo = + FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, getVpnToExtrarouteIdentifier(rd, ipPrefix)); + return extraRouteInfo.isPresent() ? extraRouteInfo.get() : null; + + } private Class getTunnelType(String ifName) { try { @@ -354,7 +351,7 @@ public class FibManager extends AbstractDataChangeListener implements String rd = vrfTableKey.getRouteDistinguisher(); LOG.debug("adding route " + vrfEntry.getDestPrefix() + " " + rd); /********************************************/ - String tunnelInterface = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry); + String tunnelInterface = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry, rd); if(tunnelInterface == null) { LOG.error("Could not get interface for nexthop: {} in vpn {}", vrfEntry.getNextHopAddress(), rd); @@ -414,6 +411,67 @@ public class FibManager extends AbstractDataChangeListener implements "Successfully added fib entry for " + vrfEntry.getDestPrefix() + " vpnId " + 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.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.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()) { + //FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id); + cleanUpDpnForVpn(dpnId, vpnId, rd); + } else { + FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id.child( + org.opendaylight.yang.gen.v1.urn.opendaylight.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.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. + If adjacency removed is the last adjacency, clean up the following: + - vpn interface from dpntovpn list, dpn if last vpn interface on dpn + - prefix to interface entry + - vpn interface op DS + */ + Prefixes prefixInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix()); + boolean extra_route = false; + if (prefixInfo == null) { + prefixInfo = getPrefixToInterface(vpnId, vrfEntry.getNextHopAddress() + "/32"); + extra_route = true; + } + if (prefixInfo == null) + return; //Don't have any info for this prefix (shouldn't happen); need to return + String ifName = prefixInfo.getVpnInterfaceName(); + 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 + 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 + delIntfFromDpnToVpnList(vpnId, prefixInfo.getDpnId(), ifName, rd); + FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, + FibUtil.getPrefixToInterfaceIdentifier( + vpnId, + (extra_route) ? vrfEntry.getNextHopAddress() + "/32" : vrfEntry.getDestPrefix())); + FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, + FibUtil.getVpnInterfaceIdentifier(ifName)); + } + } + private void deleteFibEntries(final InstanceIdentifier identifier, final VrfEntry vrfEntry) { final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class); @@ -431,8 +489,10 @@ public class FibManager extends AbstractDataChangeListener implements deleteRemoteRoute(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry); } } - } + //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, @@ -440,7 +500,7 @@ public class FibManager extends AbstractDataChangeListener implements final VrfEntry vrfEntry) { LOG.debug("deleting route "+ vrfEntry.getDestPrefix() + " "+vpnId); String rd = vrfTableKey.getRouteDistinguisher(); - String egressInterface = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry); + String egressInterface = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry, rd); if(egressInterface == null) { LOG.error("Could not get nexthop group id for nexthop: {} in vpn {}", vrfEntry.getNextHopAddress(), rd); @@ -506,13 +566,9 @@ public class FibManager extends AbstractDataChangeListener implements * 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. */ - // FIXME: sync calls. - //mdsalManager.syncInstallFlow(flowEntity, 1); - mdsalManager.installFlow(flowEntity); + mdsalManager.syncInstallFlow(flowEntity, 1); } else { - // FIXME: sync calls. - // mdsalManager.syncRemoveFlow(flowEntity, 1); - mdsalManager.removeFlow(flowEntity); + mdsalManager.syncRemoveFlow(flowEntity, 1); } } @@ -544,13 +600,9 @@ public class FibManager extends AbstractDataChangeListener implements * 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. */ - // FIXME: - // mdsalManager.syncInstallFlow(flowEntity, 1); - mdsalManager.installFlow(flowEntity); + mdsalManager.syncInstallFlow(flowEntity, 1); } else { - // FIXME: - // mdsalManager.syncRemoveFlow(flowEntity, 1); - mdsalManager.removeFlow(flowEntity); + mdsalManager.syncRemoveFlow(flowEntity, 1); } LOG.debug("LFIB Entry for dpID {} : label : {} group {} modified successfully {}",dpId, label, groupId ); } @@ -567,7 +619,7 @@ public class FibManager extends AbstractDataChangeListener implements public void populateFibOnNewDpn(BigInteger dpnId, long vpnId, String rd) { LOG.trace("New dpn {} for vpn {} : populateFibOnNewDpn", dpnId, rd); InstanceIdentifier id = buildVrfId(rd); - Optional vrfTable = read(LogicalDatastoreType.OPERATIONAL, id); + 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 @@ -580,7 +632,7 @@ public class FibManager extends AbstractDataChangeListener implements public void cleanUpDpnForVpn(BigInteger dpnId, long vpnId, String rd) { LOG.trace("Remove dpn {} for vpn {} : cleanUpDpnForVpn", dpnId, rd); InstanceIdentifier id = buildVrfId(rd); - Optional vrfTable = read(LogicalDatastoreType.OPERATIONAL, id); + 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 @@ -612,14 +664,20 @@ public class FibManager extends AbstractDataChangeListener implements } protected String resolveAdjacency(final BigInteger localDpnId, final BigInteger remoteDpnId, - final long vpnId, final VrfEntry vrfEntry) { + final long vpnId, final VrfEntry vrfEntry, String rd) { String adjacency = null; - LOG.trace("resolveAdjacency called with localdpid{} remotedpid {}, vpnId{}, VrfEntry {}", localDpnId, remoteDpnId, vpnId, vrfEntry);; + boolean staticRoute = false; + LOG.trace("resolveAdjacency called with localdpid{} remotedpid {}, vpnId{}, VrfEntry {}", localDpnId, remoteDpnId, vpnId, vrfEntry); try { - adjacency = + Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix()); + if(extra_route != null) { + staticRoute = true; + } + + adjacency = nextHopManager.getRemoteNextHopPointer(localDpnId, remoteDpnId, vpnId, vrfEntry.getDestPrefix(), - vrfEntry.getNextHopAddress()); + (staticRoute == true) ? extra_route.getNexthopIp() : vrfEntry.getNextHopAddress()); } catch (NullPointerException e) { LOG.trace("", e); } @@ -629,7 +687,7 @@ public class FibManager extends AbstractDataChangeListener implements protected VpnInstanceOpDataEntry getVpnInstance(String rd) { InstanceIdentifier id = InstanceIdentifier.create(VpnInstanceOpData.class).child( VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd)); - Optional vpnInstanceOpData = read(LogicalDatastoreType.OPERATIONAL, id); + Optional vpnInstanceOpData = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id); if(vpnInstanceOpData.isPresent()) { return vpnInstanceOpData.get(); } @@ -707,7 +765,7 @@ public class FibManager extends AbstractDataChangeListener implements result.add(String.format(" %-7s %-20s %-20s %-7s", "RD", "Prefix", "Nexthop", "Label")); result.add("-------------------------------------------------------------------"); InstanceIdentifier id = InstanceIdentifier.create(FibEntries.class); - Optional fibEntries = read(LogicalDatastoreType.OPERATIONAL, id); + Optional fibEntries = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id); if (fibEntries.isPresent()) { List vrfTables = fibEntries.get().getVrfTables(); for (VrfTables vrfTable : vrfTables) { diff --git a/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibUtil.java b/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibUtil.java new file mode 100644 index 00000000..273d6481 --- /dev/null +++ b/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibUtil.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.vpnservice.fibmanager; + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; + +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.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.Adjacencies; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.Adjacency; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.math.BigInteger; + +public class FibUtil { + private static final Logger LOG = LoggerFactory.getLogger(FibUtil.class); + static Optional read(DataBroker broker, LogicalDatastoreType datastoreType, + InstanceIdentifier path) { + + ReadOnlyTransaction tx = broker.newReadOnlyTransaction(); + + Optional result = Optional.absent(); + try { + result = tx.read(datastoreType, path).get(); + } catch (Exception e) { + throw new RuntimeException(e); + } + + return result; + } + + static void asyncWrite(DataBroker broker, LogicalDatastoreType datastoreType, + InstanceIdentifier path, T data, FutureCallback callback) { + WriteTransaction tx = broker.newWriteOnlyTransaction(); + tx.merge(datastoreType, path, data, true); + Futures.addCallback(tx.submit(), callback); + } + + static void syncWrite(DataBroker broker, LogicalDatastoreType datastoreType, + InstanceIdentifier path, T data, FutureCallback callback) { + WriteTransaction tx = broker.newWriteOnlyTransaction(); + tx.merge(datastoreType, path, data, true); + tx.submit(); + } + + static void delete(DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier path) { + WriteTransaction tx = broker.newWriteOnlyTransaction(); + tx.delete(datastoreType, path); + Futures.addCallback(tx.submit(), DEFAULT_CALLBACK); + } + + 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.l3vpn.rev130911.Adjacencies.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.Adjacency.class, new org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.AdjacencyKey(ipAddress)).build(); + } + + static InstanceIdentifier getAdjListPath(String vpnInterfaceName) { + 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.l3vpn.rev130911.Adjacencies.class).build(); + } + + static InstanceIdentifier getPrefixToInterfaceIdentifier(long vpnId, String ipPrefix) { + return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.PrefixToInterface.class) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.VpnIds.class, new org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.VpnIdsKey(vpnId)).child(org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes.class, + new org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.vpn.ids.PrefixesKey(ipPrefix)).build(); + } + + static InstanceIdentifier getVpnInterfaceIdentifier(String vpnInterfaceName) { + 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)).build(); + } + + static InstanceIdentifier getVpnToDpnListIdentifier(String rd, BigInteger dpnId) { + return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstanceOpData.class) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry.class, new org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey(rd)) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList.class, new org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListKey(dpnId)).build(); + } + + static final FutureCallback DEFAULT_CALLBACK = + new FutureCallback() { + public void onSuccess(Void result) { + LOG.debug("Success in Datastore operation"); + } + + public void onFailure(Throwable error) { + LOG.error("Error in Datastore operation", error); + }; + }; + +} diff --git a/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/NexthopManager.java b/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/NexthopManager.java index 83c6feb9..28ea399d 100644 --- a/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/NexthopManager.java +++ b/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/NexthopManager.java @@ -83,6 +83,7 @@ public class NexthopManager implements AutoCloseable { private static final short FIB_TABLE = 21; private static final short DEFAULT_FLOW_PRIORITY = 10; private static final String NEXTHOP_ID_POOL_NAME = "nextHopPointerPool"; + private static final long FIXED_DELAY_IN_MILLISECONDS = 4000; private static final FutureCallback DEFAULT_CALLBACK = new FutureCallback() { @@ -285,8 +286,7 @@ public class NexthopManager implements AutoCloseable { addVpnNexthopToDS(dpnId, vpnId, ipAddress, groupId); // install Group - // FIXME: mdsalManager.syncInstallGroup(groupEntity); - mdsalManager.installGroup(groupEntity); + mdsalManager.syncInstallGroup(groupEntity, FIXED_DELAY_IN_MILLISECONDS); } else { //nexthop exists already; a new flow is going to point to it, increment the flowrefCount by 1 @@ -401,8 +401,7 @@ public class NexthopManager implements AutoCloseable { GroupEntity groupEntity = MDSALUtil.buildGroupEntity( dpnId, nh.getEgressPointer(), ipAddress, GroupTypes.GroupIndirect, null); // remove Group ... - // FIXME: mdsalManager.syncRemoveGroup(groupEntity); - mdsalManager.removeGroup(groupEntity); + mdsalManager.syncRemoveGroup(groupEntity); //update MD-SAL DS removeVpnNexthopFromDS(vpnId, ipAddress); //release groupId @@ -463,4 +462,10 @@ public class NexthopManager implements AutoCloseable { .child(VpnInterface.class, new VpnInterfaceKey(vpnInterfaceName)).augmentation( Adjacencies.class).child(Adjacency.class, new AdjacencyKey(ipAddress)).build(); } + + InstanceIdentifier getAdjListPath(String vpnInterfaceName) { + return InstanceIdentifier.builder(VpnInterfaces.class) + .child(VpnInterface.class, new VpnInterfaceKey(vpnInterfaceName)).augmentation( + Adjacencies.class).build(); + } } diff --git a/fibmanager/fibmanager-impl/src/test/java/org/opendaylight/vpnservice/fibmanager/test/FibManagerTest.java b/fibmanager/fibmanager-impl/src/test/java/org/opendaylight/vpnservice/fibmanager/test/FibManagerTest.java index f68a5f5f..89841010 100644 --- a/fibmanager/fibmanager-impl/src/test/java/org/opendaylight/vpnservice/fibmanager/test/FibManagerTest.java +++ b/fibmanager/fibmanager-impl/src/test/java/org/opendaylight/vpnservice/fibmanager/test/FibManagerTest.java @@ -77,6 +77,7 @@ public class FibManagerTest { private static final int label = 10; BigInteger Dpn; private static final long vpnId = 101L; + private static final long vpnIntfCnt = 2; private void SetupMocks() { Dpn = BigInteger.valueOf(100000L); @@ -115,6 +116,9 @@ public class FibManagerTest { return testRd; } + @Override + public Long getVpnInterfaceCount() { return vpnIntfCnt; } + @Override public List getVpnToDpnList() { List vpnToDpnLists = new ArrayList<>(); diff --git a/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/interfaces/IMdsalApiManager.java b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/interfaces/IMdsalApiManager.java index 3535c435..d581347d 100644 --- a/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/interfaces/IMdsalApiManager.java +++ b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/interfaces/IMdsalApiManager.java @@ -53,6 +53,7 @@ public interface IMdsalApiManager { * @param delayTime */ public void syncRemoveFlow(FlowEntity flowEntity, long delayTime); + public void syncInstallFlow(FlowEntity flowEntity, long delayTime); /** * API to install the Group on Data Plane Node synchronously. It internally waits for diff --git a/mdsalutil/mdsalutil-impl/src/main/java/org/opendaylight/vpnservice/mdsalutil/internal/MDSALUtilProvider.java b/mdsalutil/mdsalutil-impl/src/main/java/org/opendaylight/vpnservice/mdsalutil/internal/MDSALUtilProvider.java index c617cfcd..cacb6344 100644 --- a/mdsalutil/mdsalutil-impl/src/main/java/org/opendaylight/vpnservice/mdsalutil/internal/MDSALUtilProvider.java +++ b/mdsalutil/mdsalutil-impl/src/main/java/org/opendaylight/vpnservice/mdsalutil/internal/MDSALUtilProvider.java @@ -130,6 +130,11 @@ public class MDSALUtilProvider implements BindingAwareConsumer, IMdsalApiManager mdSalMgr.syncSetUpFlow(flowEntity, delayTime, true); } + @Override + public void syncInstallFlow(FlowEntity flowEntity, long delayTime) { + mdSalMgr.syncSetUpFlow(flowEntity, delayTime, false); + } + @Override public void syncInstallGroup(GroupEntity groupEntity, long delayTime) { mdSalMgr.syncSetUpGroup(groupEntity, delayTime, false); diff --git a/vpnmanager/vpnmanager-api/src/main/yang/odl-l3vpn.yang b/vpnmanager/vpnmanager-api/src/main/yang/odl-l3vpn.yang index f097eaee..4beb21ec 100644 --- a/vpnmanager/vpnmanager-api/src/main/yang/odl-l3vpn.yang +++ b/vpnmanager/vpnmanager-api/src/main/yang/odl-l3vpn.yang @@ -49,6 +49,27 @@ module odl-l3vpn { } } + container vpn-to-extraroute { + config false; + list vpn { + key vrf-id; + leaf vrf-id { + description + "The vrf-id command configures a route distinguisher (RD) + for the IPv4 or IPv6 address family of a VPN instance or + vpn instance name for internal vpn case."; + type string; + } + list extraroute { + key prefix; + leaf prefix {type string;} + leaf nexthop-ip { + type string; + } + } + } + } + /* Data models to adhere to restart requirements */ container vpn-instance-to-vpn-id { list vpn-instance { @@ -82,6 +103,7 @@ module odl-l3vpn { type string; } + leaf vpn-interface-count { type uint32; } uses vpn-route-list; list vpn-to-dpn-list { key dpnId; diff --git a/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnConstants.java b/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnConstants.java index 75b07639..862a6c49 100644 --- a/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnConstants.java +++ b/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnConstants.java @@ -21,4 +21,5 @@ public class VpnConstants { public static final BigInteger COOKIE_VM_INGRESS_TABLE = new BigInteger("8000001", 16); public static final BigInteger COOKIE_L3_BASE = new BigInteger("8000000", 16); public static final String FLOWID_PREFIX = "L3."; + public static final long WAIT_TIME_IN_MILLISECONDS = 5000; } diff --git a/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnInterfaceManager.java b/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnInterfaceManager.java index 525d30bd..61ff3b81 100644 --- a/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnInterfaceManager.java +++ b/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnInterfaceManager.java @@ -18,6 +18,7 @@ import org.opendaylight.vpnservice.mdsalutil.*; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.AdjacencyKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry; import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList; import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesBuilder; @@ -41,7 +42,7 @@ import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.ArrayList; -import java.util.concurrent.Future; +import java.util.concurrent.*; import com.google.common.base.Optional; @@ -73,7 +74,9 @@ import org.slf4j.LoggerFactory; public class VpnInterfaceManager extends AbstractDataChangeListener implements AutoCloseable { private static final Logger LOG = LoggerFactory.getLogger(VpnInterfaceManager.class); - private ListenerRegistration listenerRegistration; + private ListenerRegistration listenerRegistration, opListenerRegistration; + private ConcurrentMap vpnIntfMap = new ConcurrentHashMap(); + private ExecutorService executorService = Executors.newSingleThreadExecutor(); private final DataBroker broker; private final IBgpManager bgpManager; private IFibManager fibManager; @@ -83,6 +86,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener identifier, final VpnInterface vpnInterface) { - LOG.trace("key: {} , value: {}", identifier, vpnInterface ); + LOG.trace("VPN Interface key: {} , value: {}", identifier, vpnInterface ); addInterface(identifier, vpnInterface); } private void addInterface(final InstanceIdentifier identifier, final VpnInterface vpnInterface) { - LOG.trace("Add event - key: {}, value: {}" ,identifier, vpnInterface ); + LOG.trace("VPN Interface add event - key: {}, value: {}" ,identifier, vpnInterface ); final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class); String interfaceName = key.getName(); @@ -174,10 +183,12 @@ public class VpnInterfaceManager extends AbstractDataChangeListener vpnInterfaces = new ArrayList<>(); @@ -429,7 +452,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener identifier = VpnUtil.getVpnInterfaceIdentifier(interfaceName); - removeAdjacenciesFromVpn(identifier, vpnInterface); - LOG.info("Unbinding vpn service from interface {} ", interfaceName); - unbindService(vpnName, interfaceName, lPortTag, isInterfaceStateDown); - updateDpnDbs(vpnName, interfaceName, false); - VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, identifier, VpnUtil.DEFAULT_CALLBACK); + synchronized (interfaceName.intern()) { + removeAdjacenciesFromVpn(identifier, vpnInterface); + LOG.info("Unbinding vpn service from interface {} ", interfaceName); + unbindService(vpnName, interfaceName, lPortTag, isInterfaceStateDown); + + //wait till DCN for removal of vpn interface in operational DS arrives + Runnable notifyTask = new VpnNotifyTask(); + synchronized (interfaceName.intern()) { + vpnIntfMap.put(interfaceName, notifyTask); + synchronized (notifyTask) { + try { + notifyTask.wait(VpnConstants.WAIT_TIME_IN_MILLISECONDS); + } catch (InterruptedException e) { + } + } + } + + } } private void removeAdjacenciesFromVpn(final InstanceIdentifier identifier, VpnInterface intf) { @@ -459,11 +495,11 @@ public class VpnInterfaceManager extends AbstractDataChangeListener idBuilder = InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)).child(VrfEntry.class, new VrfEntryKey(prefix)); InstanceIdentifier vrfEntryId = idBuilder.build(); - VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, vrfEntryId, VpnUtil.DEFAULT_CALLBACK); + VpnUtil.delete(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId, VpnUtil.DEFAULT_CALLBACK); } @@ -643,7 +679,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener vrfTableId = idBuilder.build(); - VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, vrfTableId, VpnUtil.DEFAULT_CALLBACK); + VpnUtil.delete(broker, LogicalDatastoreType.CONFIGURATION, vrfTableId, VpnUtil.DEFAULT_CALLBACK); } @@ -676,7 +712,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener { + + public VpnInterfaceOpListener() { + super(VpnInterface.class); + } + + @Override + protected void remove(InstanceIdentifier identifier, VpnInterface del) { + final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class); + String interfaceName = key.getName(); + + //increment the vpn interface count in Vpn Instance Op Data + Long ifCnt = 0L; + String rd = getRouteDistinguisher(del.getVpnInstanceName()); + if(rd.isEmpty()) rd = del.getVpnInstanceName(); + VpnInstanceOpDataEntry vpnInstOp = VpnUtil.getVpnInstanceOpData(broker, rd); + if(vpnInstOp != null && vpnInstOp.getVpnInterfaceCount() != null) { + ifCnt = vpnInstOp.getVpnInterfaceCount(); + } + + LOG.trace("VpnInterfaceOpListener remove: interface name {} rd {} interface count in Vpn Op Instance {}", interfaceName, rd, ifCnt); + + VpnUtil.asyncUpdate(broker, LogicalDatastoreType.OPERATIONAL, + VpnUtil.getVpnInstanceOpDataIdentifier(rd), + VpnUtil.updateIntfCntInVpnInstOpData(ifCnt - 1, rd), VpnUtil.DEFAULT_CALLBACK); + + //TODO: Clean up the DPN List in Vpn Instance Op if ifCnt is zero + + notifyTaskIfRequired(interfaceName); + } + + private void notifyTaskIfRequired(String intfName) { + Runnable notifyTask = vpnIntfMap.remove(intfName); + if (notifyTask == null) { + return; + } + executorService.execute(notifyTask); + } + + @Override + protected void update(InstanceIdentifier identifier, VpnInterface original, VpnInterface update) { + } + + @Override + protected void add(InstanceIdentifier identifier, VpnInterface add) { + final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class); + String interfaceName = key.getName(); + + //increment the vpn interface count in Vpn Instance Op Data + Long ifCnt = 0L; + String rd = getRouteDistinguisher(add.getVpnInstanceName()); + if(rd.isEmpty()) rd = add.getVpnInstanceName(); + VpnInstanceOpDataEntry vpnInstOp = VpnUtil.getVpnInstanceOpData(broker, rd); + if(vpnInstOp != null && vpnInstOp.getVpnInterfaceCount() != null) { + ifCnt = vpnInstOp.getVpnInterfaceCount(); + } + + LOG.trace("VpnInterfaceOpListener add: interface name {} rd {} interface count in Vpn Op Instance {}", interfaceName, rd, ifCnt); + + VpnUtil.asyncUpdate(broker, LogicalDatastoreType.OPERATIONAL, + VpnUtil.getVpnInstanceOpDataIdentifier(rd), + VpnUtil.updateIntfCntInVpnInstOpData(ifCnt + 1, rd), VpnUtil.DEFAULT_CALLBACK); + + + } + } + protected void updatePrefixesForDPN(BigInteger dpnId, UpdateRouteAction action) { InstanceIdentifierBuilder idBuilder = InstanceIdentifier.builder(VpnInstances.class); diff --git a/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnManager.java b/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnManager.java index 5567d3e6..1a454018 100644 --- a/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnManager.java +++ b/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnManager.java @@ -10,12 +10,15 @@ package org.opendaylight.vpnservice; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.concurrent.*; +import com.google.common.util.concurrent.CheckedFuture; import org.opendaylight.bgpmanager.api.IBgpManager; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.vpntargets.VpnTarget; import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstanceToVpnId; import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstanceToVpnIdBuilder; @@ -51,12 +54,15 @@ import com.google.common.util.concurrent.Futures; public class VpnManager extends AbstractDataChangeListener implements AutoCloseable { private static final Logger LOG = LoggerFactory.getLogger(VpnManager.class); - private ListenerRegistration listenerRegistration, fibListenerRegistration; + private ListenerRegistration listenerRegistration, fibListenerRegistration, opListenerRegistration; + private ConcurrentMap vpnOpMap = new ConcurrentHashMap(); + private ExecutorService executorService = Executors.newSingleThreadExecutor(); private final DataBroker broker; private final IBgpManager bgpManager; private IdManagerService idManager; private VpnInterfaceManager vpnInterfaceManager; private final FibEntriesListener fibListener; + private final VpnInstanceOpListener vpnInstOpListener; private static final FutureCallback DEFAULT_CALLBACK = new FutureCallback() { @@ -80,6 +86,7 @@ public class VpnManager extends AbstractDataChangeListener implemen broker = db; this.bgpManager = bgpManager; this.fibListener = new FibEntriesListener(); + this.vpnInstOpListener = new VpnInstanceOpListener(); registerListener(db); } @@ -89,6 +96,9 @@ public class VpnManager extends AbstractDataChangeListener implemen getWildCardPath(), VpnManager.this, DataChangeScope.SUBTREE); fibListenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, getFibEntryListenerPath(), fibListener, DataChangeScope.BASE); + opListenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, + getVpnInstanceOpListenerPath(), vpnInstOpListener, DataChangeScope.SUBTREE); + } catch (final Exception e) { LOG.error("VPN Service DataChange listener registration fail !", e); throw new IllegalStateException("VPN Service registration Listener failed.", e); @@ -103,6 +113,21 @@ public class VpnManager extends AbstractDataChangeListener implemen this.vpnInterfaceManager = vpnInterfaceManager; } + private void waitForOpDataRemoval(String id) { + //wait till DCN for removal of all DPNs in VPN arrivaes + Runnable notifyTask = new VpnNotifyTask(); + synchronized (id.intern()) { + vpnOpMap.put(id, notifyTask); + synchronized (notifyTask) { + try { + notifyTask.wait(VpnConstants.WAIT_TIME_IN_MILLISECONDS); + } catch (InterruptedException e) { + } + } + } + + } + @Override protected void remove(InstanceIdentifier identifier, VpnInstance del) { LOG.trace("Remove VPN event - Key: {}, value: {}", identifier, del); @@ -131,13 +156,15 @@ public class VpnManager extends AbstractDataChangeListener implemen if (rd !=null) { - delete(LogicalDatastoreType.OPERATIONAL, VpnUtil.getVpnInstanceOpDataIdentifier(rd)); try { bgpManager.deleteVrf(rd); - } catch(Exception e) { + } catch (Exception e) { LOG.error("Exception when removing VRF from BGP", e); } + waitForOpDataRemoval(rd); + delete(LogicalDatastoreType.OPERATIONAL, VpnUtil.getVpnInstanceOpDataIdentifier(rd)); } else { + waitForOpDataRemoval(vpnName); delete(LogicalDatastoreType.OPERATIONAL, VpnUtil.getVpnInstanceOpDataIdentifier(vpnName)); } } @@ -151,30 +178,30 @@ public class VpnManager extends AbstractDataChangeListener implemen @Override protected void add(InstanceIdentifier identifier, VpnInstance value) { - LOG.trace("key: {}, value: {}", identifier, value); + LOG.trace("VPN Instance key: {}, value: {}", identifier, value); VpnAfConfig config = value.getIpv4Family(); String rd = config.getRouteDistinguisher(); long vpnId = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME, value.getVpnInstanceName()); - + LOG.trace("VPN instance to ID generated."); org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance vpnInstanceToVpnId = VpnUtil.getVpnInstanceToVpnId(value.getVpnInstanceName(), vpnId, (rd != null) ? rd : value.getVpnInstanceName()); - asyncWrite(LogicalDatastoreType.CONFIGURATION, + syncWrite(LogicalDatastoreType.CONFIGURATION, VpnUtil.getVpnInstanceToVpnIdIdentifier(value.getVpnInstanceName()), vpnInstanceToVpnId, DEFAULT_CALLBACK); if(rd == null) { - asyncWrite(LogicalDatastoreType.OPERATIONAL, + syncWrite(LogicalDatastoreType.OPERATIONAL, VpnUtil.getVpnInstanceOpDataIdentifier(value.getVpnInstanceName()), - VpnUtil.getVpnInstanceOpData(value.getVpnInstanceName(), vpnId), DEFAULT_CALLBACK); + VpnUtil.getVpnInstanceOpDataBuilder(value.getVpnInstanceName(), vpnId), DEFAULT_CALLBACK); } else { - asyncWrite(LogicalDatastoreType.OPERATIONAL, + syncWrite(LogicalDatastoreType.OPERATIONAL, VpnUtil.getVpnInstanceOpDataIdentifier(rd), - VpnUtil.getVpnInstanceOpData(rd, vpnId), DEFAULT_CALLBACK); + VpnUtil.getVpnInstanceOpDataBuilder(rd, vpnId), DEFAULT_CALLBACK); List vpnTargetList = config.getVpnTargets().getVpnTarget(); @@ -200,6 +227,22 @@ public class VpnManager extends AbstractDataChangeListener implemen LOG.error("Exception when adding VRF to BGP", e); } } + //Try to add up vpn Interfaces if already in Operational Datastore + LOG.trace("Trying to add the vpn interfaces -1."); + InstanceIdentifier vpnInterfacesId = InstanceIdentifier.builder(VpnInterfaces.class).build(); + Optional optionalVpnInterfaces = read(LogicalDatastoreType.CONFIGURATION, vpnInterfacesId); + + if(optionalVpnInterfaces.isPresent()) { + List vpnInterfaces = optionalVpnInterfaces.get().getVpnInterface(); + for(VpnInterface vpnInterface : vpnInterfaces) { + if(vpnInterface.getVpnInstanceName().equals(value.getVpnInstanceName())) { + LOG.debug("VpnInterface {} will be added from VPN {}", vpnInterface.getName(), value.getVpnInstanceName()); + vpnInterfaceManager.add( + VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()), vpnInterface); + + } + } + } } private InstanceIdentifier getWildCardPath() { @@ -211,6 +254,11 @@ public class VpnManager extends AbstractDataChangeListener implemen .child(VrfEntry.class); } + private InstanceIdentifier getVpnInstanceOpListenerPath() { + return InstanceIdentifier.create(VpnInstanceOpData.class).child(VpnInstanceOpDataEntry.class); + + } + @Override public void close() throws Exception { if (listenerRegistration != null) { @@ -229,6 +277,15 @@ public class VpnManager extends AbstractDataChangeListener implemen } fibListenerRegistration = null; } + if (opListenerRegistration != null) { + try { + opListenerRegistration.close(); + } catch (final Exception e) { + LOG.error("Error when cleaning up VPN Instance Operational entries DataChangeListener.", e); + } + opListenerRegistration = null; + } + LOG.trace("VPN Manager Closed"); } @@ -254,6 +311,19 @@ public class VpnManager extends AbstractDataChangeListener implemen Futures.addCallback(tx.submit(), callback); } + private void syncWrite(LogicalDatastoreType datastoreType, + InstanceIdentifier path, T data, FutureCallback callback) { + WriteTransaction tx = broker.newWriteOnlyTransaction(); + tx.put(datastoreType, path, data, true); + CheckedFuture futures = tx.submit(); + try { + futures.get(); + } catch (InterruptedException | ExecutionException e) { + LOG.error("Error writing VPN instance to ID info to datastore (path, data) : ({}, {})", path, data); + throw new RuntimeException(e.getMessage()); + } + } + protected VpnInstanceOpDataEntry getVpnInstanceOpData(String rd) { InstanceIdentifier id = VpnUtil.getVpnInstanceOpDataIdentifier(rd); Optional vpnInstanceOpData = read(LogicalDatastoreType.OPERATIONAL, id); @@ -327,4 +397,42 @@ public class VpnManager extends AbstractDataChangeListener implemen } } } + + class VpnInstanceOpListener extends org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener { + + public VpnInstanceOpListener() { + super(VpnInstanceOpDataEntry.class); + } + + @Override + protected void remove(InstanceIdentifier identifier, VpnInstanceOpDataEntry del) { + + } + + @Override + protected void update(InstanceIdentifier identifier, VpnInstanceOpDataEntry original, VpnInstanceOpDataEntry update) { + final VpnInstanceOpDataEntryKey key = identifier.firstKeyOf(VpnInstanceOpDataEntry.class, VpnInstanceOpDataEntryKey.class); + String vpnName = key.getVrfId(); + + LOG.trace("VpnInstanceOpListener update: vpn name {} interface count in Old VpnOp Instance {} in New VpnOp Instance {}" , + vpnName, original.getVpnInterfaceCount(), update.getVpnInterfaceCount() ); + + //if((original.getVpnToDpnList().size() != update.getVpnToDpnList().size()) && (update.getVpnToDpnList().size() == 0)) { + if((original.getVpnInterfaceCount() != update.getVpnInterfaceCount()) && (update.getVpnInterfaceCount() == 0)) { + notifyTaskIfRequired(vpnName); + } + } + + private void notifyTaskIfRequired(String vpnName) { + Runnable notifyTask = vpnOpMap.remove(vpnName); + if (notifyTask == null) { + return; + } + executorService.execute(notifyTask); + } + + @Override + protected void add(InstanceIdentifier identifier, VpnInstanceOpDataEntry add) { + } + } } diff --git a/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnNotifyTask.java b/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnNotifyTask.java new file mode 100644 index 00000000..0611e34e --- /dev/null +++ b/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnNotifyTask.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.vpnservice; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +class VpnNotifyTask implements Runnable{ + private static final Logger logger = LoggerFactory.getLogger(VpnNotifyTask.class); + + @Override + public void run() { + logger.debug("Notify Task is running for the task {}", this); + synchronized (this) { + notifyAll(); + } + } + +} diff --git a/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnUtil.java b/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnUtil.java index 29ad638f..10d69f96 100644 --- a/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnUtil.java +++ b/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnUtil.java @@ -34,9 +34,7 @@ import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev14081 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.PrefixToInterface; -import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstanceOpData; -import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstanceToVpnId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.*; import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.Adjacency; import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.Adjacencies; import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.AdjacenciesBuilder; @@ -50,6 +48,11 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instanc import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList; import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.Vpn; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.VpnKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.vpn.Extraroute; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.vpn.ExtrarouteBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.vpn.ExtrarouteKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdPools; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.id.pools.IdPool; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.id.pools.IdPoolKey; @@ -97,6 +100,16 @@ public class VpnUtil { vpnInterfaceName).setIpAddress(ipPrefix).build(); } + static InstanceIdentifier getVpnToExtrarouteIdentifier(String vrfId, String ipPrefix) { + return InstanceIdentifier.builder(VpnToExtraroute.class) + .child(Vpn.class, new VpnKey(vrfId)).child(Extraroute.class, + new ExtrarouteKey(ipPrefix)).build(); + } + + static Extraroute getVpnToExtraroute(String ipPrefix, String nextHop) { + return new ExtrarouteBuilder().setPrefix(ipPrefix).setNexthopIp(nextHop).build(); + } + static Adjacencies getVpnInterfaceAugmentation(List nextHops) { return new AdjacenciesBuilder().setAdjacency(nextHops).build(); @@ -219,10 +232,23 @@ public class VpnUtil { .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd)).build(); } - static VpnInstanceOpDataEntry getVpnInstanceOpData(String rd, long vpnId) { + static VpnInstanceOpDataEntry getVpnInstanceOpDataBuilder(String rd, long vpnId) { return new VpnInstanceOpDataEntryBuilder().setVrfId(rd).setVpnId(vpnId).build(); } + static VpnInstanceOpDataEntry updateIntfCntInVpnInstOpData(Long count, String vrfId) { + return new VpnInstanceOpDataEntryBuilder().setVpnInterfaceCount(count).setVrfId(vrfId).build(); + } + + static VpnInstanceOpDataEntry getVpnInstanceOpData(DataBroker broker, String rd) { + InstanceIdentifier id = VpnUtil.getVpnInstanceOpDataIdentifier(rd); + Optional vpnInstanceOpData = read(broker, LogicalDatastoreType.OPERATIONAL, id); + if(vpnInstanceOpData.isPresent()) { + return vpnInstanceOpData.get(); + } + return null; + } + static VpnInterface getConfiguredVpnInterface(DataBroker broker, String interfaceName) { InstanceIdentifier interfaceId = getVpnInterfaceIdentifier(interfaceName); Optional configuredVpnInterface = read(broker, LogicalDatastoreType.CONFIGURATION, interfaceId); diff --git a/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnserviceProvider.java b/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnserviceProvider.java index 3dd66445..ce72eb6a 100644 --- a/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnserviceProvider.java +++ b/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnserviceProvider.java @@ -130,7 +130,7 @@ public class VpnserviceProvider implements BindingAwareProvider, IVpnManager, @Override public void addExtraRoute(String destination, String nextHop, String rd, String routerID, int label) { LOG.info("Adding extra route with destination {} and nexthop {}", destination, nextHop); - vpnInterfaceManager.addExtraRoute(destination, nextHop, rd, routerID, label); + vpnInterfaceManager.addExtraRoute(destination, nextHop, rd, routerID, label, null); } @Override