ELAN FT Support for BE
[vpnservice.git] / nexthopmgr / nexthopmgr-impl / src / main / java / org / opendaylight / vpnservice / nexthopmgr / NexthopManager.java
old mode 100644 (file)
new mode 100755 (executable)
index 71cfad7..cb1447f
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 package org.opendaylight.vpnservice.nexthopmgr;
-/**********************************************************************************
-** NextHop MD-SAL DS 
-** ------------------------------------------------
-** DP_ID  |  VPN   |   IP Address  |  GroupId     |
-** ------------------------------------------------
-** 
-** Listen to DCNs from vpn-inetrfaces
-** if a next-hop is added/removed in vpn-interfaces DS
-**     call add/removeNextHop(interface.dpn, interface.port, vpn_instance.vpnId, AdjacencyIpAddress);
-** 
-** if a tunnel-interface is added inn interfaces DS --
-**     call add/removeNextHop(interface.dpn, interface.port, 00, RemoteIpAddress);
-*************************************************************************************/
-import java.util.Collections;
-import java.util.Map;
-import java.util.Set;
 
+import org.opendaylight.vpnservice.mdsalutil.FlowEntity;
+import org.opendaylight.vpnservice.mdsalutil.InstructionInfo;
+import org.opendaylight.vpnservice.mdsalutil.InstructionType;
+import org.opendaylight.vpnservice.mdsalutil.MatchFieldType;
+import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
+import org.opendaylight.vpnservice.mdsalutil.NwConstants;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.Future;
 import com.google.common.base.Optional;
-import com.google.common.collect.FluentIterable;
-
-
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.FutureCallback;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
-import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
 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.LogicalDatastoreType;
-
-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.NextHopList;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.next.hop.list.L3NextHops;
-import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInterface1;
-import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
-import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey;
-*/
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150330.L3nexthop;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150330.l3nexthop.VpnNexthops;
-
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstanceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
+//import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstance1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.CreateIdPoolInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.CreateIdPoolInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.ReleaseIdInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.ReleaseIdInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.l3nexthop.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.l3nexthop.tunnelnexthops.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.l3nexthop.vpnnexthops.*;
+import org.opendaylight.vpnservice.interfacemgr.interfaces.IInterfaceManager;
+import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
+import org.opendaylight.vpnservice.mdsalutil.ActionType;
+import org.opendaylight.vpnservice.mdsalutil.BucketInfo;
+import org.opendaylight.vpnservice.mdsalutil.GroupEntity;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.idmanager.IdManager;
+import java.util.concurrent.ExecutionException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class NexthopManager extends AbstractDataChangeListener<L3nexthop> implements AutoCloseable{
-    private static final Logger LOG = LoggerFactory.getLogger(L3nexthop.class);
-    private ListenerRegistration<DataChangeListener> listenerRegistration;
+public class NexthopManager implements L3nexthopService, AutoCloseable {
+    private static final Logger LOG = LoggerFactory.getLogger(NexthopManager.class);
     private final DataBroker broker;
+    private IMdsalApiManager mdsalManager;
+    private IInterfaceManager interfaceManager;
+    private IdManagerService idManager;
+    private static final short LPORT_INGRESS_TABLE = 0;
+    private static final short LFIB_TABLE = 20;
+    private static final short FIB_TABLE = 21;
+    private static final short DEFAULT_FLOW_PRIORITY = 10;
+
+    private static final FutureCallback<Void> DEFAULT_CALLBACK =
+        new FutureCallback<Void>() {
+            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);
+            };
+        };
 
+    /**
+    * Provides nexthop functions
+    * Creates group ID pool
+    *
+    * @param db - dataBroker reference
+    */
     public NexthopManager(final DataBroker db) {
-        super(L3nexthop.class);
         broker = db;
-        registerListener(db);
     }
 
-       @Override
+    @Override
     public void close() throws Exception {
-        if (listenerRegistration != null) {
-            try {
-                listenerRegistration.close();
-            } catch (final Exception e) {
-                LOG.error("Error when cleaning up DataChangeListener.", e);
+        LOG.info("NextHop Manager Closed");
+    }
+
+    public void setInterfaceManager(IInterfaceManager ifManager) {
+        this.interfaceManager = ifManager;
+    }
+
+    public void setMdsalManager(IMdsalApiManager mdsalManager) {
+        this.mdsalManager = mdsalManager;
+    }
+
+    public void setIdManager(IdManagerService idManager) {
+        this.idManager = idManager;
+    }
+
+    protected void createNexthopPointerPool() {
+        CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
+                .setPoolName("nextHopPointerPool")
+                .setLow(150000L)
+                .setHigh(175000L)
+                .build();
+        //TODO: Error handling
+        Future<RpcResult<Void>> result = idManager.createIdPool(createPool);
+        LOG.trace("NextHopPointerPool result : {}", result);
+    }
+
+
+    protected long getVpnId(String vpnName) {
+        InstanceIdentifierBuilder<VpnInstance> idBuilder = InstanceIdentifier.builder(VpnInstances.class)
+                .child(VpnInstance.class, new VpnInstanceKey(vpnName));
+
+        InstanceIdentifier<VpnInstance> id = idBuilder.build();
+        //FIXME [ELAnBE] Commenting out below 2 lines
+        //InstanceIdentifier<VpnInstance1> idx = id.augmentation(VpnInstance1.class);
+        //Optional<VpnInstance1> vpn = read(LogicalDatastoreType.OPERATIONAL, idx);
+
+
+//        if (vpn.isPresent()) {
+//            LOG.debug("VPN id returned: {}", vpn.get().getVpnId());
+//            return vpn.get().getVpnId();
+//        } else {
+//            return -1;
+//        }
+        return -1;
+    }
+
+    private BigInteger getDpnId(String ofPortId) {
+        String[] fields = ofPortId.split(":");
+        BigInteger dpn = new BigInteger(fields[1]);
+        LOG.debug("DpnId: {}", dpn);
+        return dpn;
+    }
+
+    protected long createNextHopPointer(String nexthopKey) {
+        AllocateIdInput getIdInput = new AllocateIdInputBuilder()
+                .setPoolName("nextHopPointerPool").setIdKey(nexthopKey)
+                .build();
+        //TODO: Proper error handling once IdManager code is complete
+        try {
+            Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
+            RpcResult<AllocateIdOutput> rpcResult = result.get();
+            return rpcResult.getResult().getIdValue();
+        } catch (NullPointerException | InterruptedException | ExecutionException e) {
+            LOG.trace("",e);
+        }
+        return 0;
+    }
+
+    public void createLocalNextHop(String ifName, String vpnName, String ipAddress, String macAddress) {
+        String nhKey = new String("nexthop." + vpnName + ipAddress);
+        long groupId = createNextHopPointer(nhKey);
+
+        long vpnId = getVpnId(vpnName);
+        BigInteger dpnId = interfaceManager.getDpnForInterface(ifName);
+        VpnNexthop nexthop = getVpnNexthop(vpnId, ipAddress, 0);
+        LOG.trace("nexthop: {}", nexthop);
+        if (nexthop == null) {
+            List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
+            List<ActionInfo> listActionInfo = interfaceManager.getInterfaceEgressActions(ifName);
+            BucketInfo bucket = new BucketInfo(listActionInfo);
+            // MAC re-write
+            if (macAddress != null) {
+               listActionInfo.add(0, new ActionInfo(ActionType.set_field_eth_dest, new String[]{macAddress}));
+               listActionInfo.add(0, new ActionInfo(ActionType.pop_mpls, new String[]{}));
+            } else {
+                //FIXME: Log message here.
+                LOG.debug("mac address for new local nexthop is null");
+            }
+            listBucketInfo.add(bucket);
+            GroupEntity groupEntity = MDSALUtil.buildGroupEntity(
+                dpnId, groupId, ipAddress, GroupTypes.GroupIndirect, listBucketInfo);
+
+            // install Group
+            mdsalManager.installGroup(groupEntity);
+
+            //update MD-SAL DS
+            addVpnNexthopToDS(vpnId, ipAddress, groupId);
+        } else {
+            //check update
+        }
+    }
+
+    public void createRemoteNextHop(String ifName, String ipAddress) {
+        String nhKey = new String("nexthop." + ifName + ipAddress);
+        long groupId = createNextHopPointer(nhKey);
+
+        BigInteger dpnId = interfaceManager.getDpnForInterface(ifName);
+        TunnelNexthop nexthop = getTunnelNexthop(dpnId, ipAddress);
+        if (nexthop == null) {
+            List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
+            List<ActionInfo> listActionInfo = interfaceManager.getInterfaceEgressActions(ifName);
+            BucketInfo bucket = new BucketInfo(listActionInfo);
+            // MAC re-write??           
+            listBucketInfo.add(bucket);
+            GroupEntity groupEntity = MDSALUtil.buildGroupEntity(
+                dpnId, groupId, ipAddress, GroupTypes.GroupIndirect, listBucketInfo);
+            mdsalManager.installGroup(groupEntity);
+            //makeRemoteFlow(dpnId, ifName, NwConstants.ADD_FLOW);
+
+            //update MD-SAL DS
+            addTunnelNexthopToDS(dpnId, ipAddress, groupId);
+        } else {
+            //check update
+        }
+    }
+
+    private void makeRemoteFlow(BigInteger dpnId, String ifName, int addOrRemoveFlow) {
+        long portNo = 0;
+        String flowName = ifName;
+        String flowRef = getTunnelInterfaceFlowRef(dpnId, LPORT_INGRESS_TABLE, ifName);
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
+        List<InstructionInfo> mkInstructions = new ArrayList<InstructionInfo>();
+        if (NwConstants.ADD_FLOW == addOrRemoveFlow) {
+            portNo = interfaceManager.getPortForInterface(ifName);
+            matches.add(new MatchInfo(MatchFieldType.in_port, new BigInteger[] {
+                dpnId, BigInteger.valueOf(portNo) }));
+            mkInstructions.add(new InstructionInfo(InstructionType.goto_table, new long[] {LFIB_TABLE}));
+        }
+
+        BigInteger COOKIE_VM_INGRESS_TABLE = new BigInteger("8000001", 16);
+        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, LPORT_INGRESS_TABLE, flowRef,
+                                                          DEFAULT_FLOW_PRIORITY, flowName, 0, 0, COOKIE_VM_INGRESS_TABLE, matches, mkInstructions);
+
+        if (NwConstants.ADD_FLOW == addOrRemoveFlow) {
+            mdsalManager.installFlow(flowEntity);
+        } else {
+            mdsalManager.removeFlow(flowEntity);
+        }
+    }
+
+    private String getTunnelInterfaceFlowRef(BigInteger dpnId, short tableId, String ifName) {
+                return new StringBuilder().append(dpnId).append(tableId).append(ifName).toString();
+            }
+
+    protected void addVpnNexthopToDS(long vpnId, String ipPrefix, long egressPointer) {
+
+        InstanceIdentifierBuilder<VpnNexthops> idBuilder = InstanceIdentifier.builder(
+            L3nexthop.class)
+                .child(VpnNexthops.class, new VpnNexthopsKey(vpnId));
+
+        // Add nexthop to vpn node
+        VpnNexthop nh = new VpnNexthopBuilder().
+                setKey(new VpnNexthopKey(ipPrefix)).
+                setIpAddress(ipPrefix).
+                setEgressPointer(egressPointer).build();
+
+        InstanceIdentifier<VpnNexthop> id1 = idBuilder
+                .child(VpnNexthop.class, new VpnNexthopKey(ipPrefix)).build();
+        LOG.trace("Adding vpnnextHop {} to Operational DS", nh);
+        syncWrite(LogicalDatastoreType.OPERATIONAL, id1, nh, DEFAULT_CALLBACK);
+
+    }
+
+    private void addTunnelNexthopToDS(BigInteger dpnId, String ipPrefix, long egressPointer) {
+        InstanceIdentifierBuilder<TunnelNexthops> idBuilder = InstanceIdentifier.builder(L3nexthop.class)
+                .child(TunnelNexthops.class, new TunnelNexthopsKey(dpnId));
+
+        // Add nexthop to dpn node
+        TunnelNexthop nh = new TunnelNexthopBuilder().
+                setKey(new TunnelNexthopKey(ipPrefix)).
+                setIpAddress(ipPrefix).
+                setEgressPointer(egressPointer).build();
+
+        InstanceIdentifier<TunnelNexthop> id1 = idBuilder
+                .child(TunnelNexthop.class, new TunnelNexthopKey(ipPrefix)).build();
+        LOG.trace("Adding tunnelnextHop {} to Operational DS for a dpn node", nh);
+        asyncWrite(LogicalDatastoreType.OPERATIONAL, id1, nh, DEFAULT_CALLBACK);
+
+    }
+
+    protected VpnNexthop getVpnNexthop(long vpnId, String ipAddress, int retryCount) {
+
+        // check if vpn node is there
+        InstanceIdentifierBuilder<VpnNexthops> idBuilder =
+                        InstanceIdentifier.builder(L3nexthop.class).child(VpnNexthops.class, new VpnNexthopsKey(vpnId));
+        InstanceIdentifier<VpnNexthops> id = idBuilder.build();
+        try {
+            for (int retry = 0; retry <= retryCount; retry++) {
+                Optional<VpnNexthops> vpnNexthops = read(LogicalDatastoreType.OPERATIONAL, id);
+                if (vpnNexthops.isPresent()) {
+
+                    // get nexthops list for vpn
+                    List<VpnNexthop> nexthops = vpnNexthops.get().getVpnNexthop();
+                    for (VpnNexthop nexthop : nexthops) {
+                        if (nexthop.getIpAddress().equals(ipAddress)) {
+                            // return nexthop
+                            LOG.trace("VpnNextHop : {}", nexthop);
+                            return nexthop;
+                        }
+                    }
+                }
+                Thread.sleep(100L);
+            }
+        } catch (InterruptedException e) {
+            LOG.trace("", e);
+        }
+        // return null if not found
+        return null;
+    }
+
+    private TunnelNexthop getTunnelNexthop(BigInteger dpnId, String ipAddress) {
+        
+        InstanceIdentifierBuilder<TunnelNexthops> idBuilder = InstanceIdentifier.builder(L3nexthop.class)
+                .child(TunnelNexthops.class, new TunnelNexthopsKey(dpnId));
+
+        // check if vpn node is there 
+        InstanceIdentifier<TunnelNexthops> id = idBuilder.build();
+        Optional<TunnelNexthops> dpnNexthops = read(LogicalDatastoreType.OPERATIONAL, id);
+        if (dpnNexthops.isPresent()) {
+            List<TunnelNexthop> nexthops = dpnNexthops.get().getTunnelNexthop();
+            for (TunnelNexthop nexthop : nexthops) {
+                if (nexthop.getIpAddress().equals(ipAddress)) {
+                    LOG.trace("TunnelNextHop : {}",nexthop);
+                    return nexthop;
+                }
             }
-            listenerRegistration = null;
         }
-        LOG.info("VPN Interface Manager Closed");
+        return null;
+    }
+
+    public long getNextHopPointer(BigInteger dpnId, long vpnId, String prefixIp, String nextHopIp) {
+        String endpointIp = interfaceManager.getEndpointIpForDpn(dpnId);
+        if (nextHopIp.equals(endpointIp)) {
+            VpnNexthop vpnNextHop = getVpnNexthop(vpnId, prefixIp, 0);
+            return vpnNextHop.getEgressPointer();
+        } else {
+            TunnelNexthop tunnelNextHop = getTunnelNexthop(dpnId, nextHopIp);
+            LOG.trace("NExtHopPointer : {}", tunnelNextHop.getEgressPointer());
+            return tunnelNextHop.getEgressPointer();
+        }
+    }
+
+    private void removeTunnelNexthopFromDS(BigInteger dpnId, String ipPrefix) {
+
+        InstanceIdentifierBuilder<TunnelNexthop> idBuilder = InstanceIdentifier.builder(L3nexthop.class)
+                .child(TunnelNexthops.class, new TunnelNexthopsKey(dpnId))
+                .child(TunnelNexthop.class, new TunnelNexthopKey(ipPrefix));
+        InstanceIdentifier<TunnelNexthop> id = idBuilder.build();
+        // remove from DS     
+        LOG.trace("Removing tunnel next hop from datastore : {}", id);
+        delete(LogicalDatastoreType.OPERATIONAL, id);
+    }
+
+    private void removeVpnNexthopFromDS(long vpnId, String ipPrefix) {
+
+        InstanceIdentifierBuilder<VpnNexthop> idBuilder = InstanceIdentifier.builder(L3nexthop.class)
+                .child(VpnNexthops.class, new VpnNexthopsKey(vpnId))
+                .child(VpnNexthop.class, new VpnNexthopKey(ipPrefix));
+        InstanceIdentifier<VpnNexthop> id = idBuilder.build();
+        // remove from DS
+        LOG.trace("Removing vpn next hop from datastore : {}", id);
+        delete(LogicalDatastoreType.OPERATIONAL, id);
+    }
+
+    public void removeLocalNextHop(BigInteger dpnId, Long vpnId, String ipAddress) {
+
+        VpnNexthop nh = getVpnNexthop(vpnId, ipAddress, 0);
+        if (nh != null) {
+            // how to inform and remove dependent FIB entries??
+            // we need to do it before the group is removed
+            GroupEntity groupEntity = MDSALUtil.buildGroupEntity(
+                    dpnId, nh.getEgressPointer(), ipAddress, GroupTypes.GroupIndirect, null);
+            // remove Group ...
+            mdsalManager.removeGroup(groupEntity);
+            //update MD-SAL DS
+            removeVpnNexthopFromDS(vpnId, ipAddress);
+        } else {
+            //throw error
+            LOG.error("removal of local next hop failed");
+        }
+
     }
 
+    public void removeRemoteNextHop(BigInteger dpnId, String ifName, String ipAddress) {
 
-    private void registerListener(final DataBroker db) {
+        TunnelNexthop nh = getTunnelNexthop(dpnId, ipAddress);
+        if (nh != null) {
+            // how to inform and remove dependent FIB entries??
+            // we need to do it before the group is removed
+
+            // remove Group ...
+            GroupEntity groupEntity = MDSALUtil.buildGroupEntity(
+                    dpnId, nh.getEgressPointer(), ipAddress, GroupTypes.GroupIndirect, null);
+            // remove Group ...
+            mdsalManager.removeGroup(groupEntity);
+            //makeRemoteFlow(dpnId, ifName, NwConstants.DEL_FLOW);
+            //update MD-SAL DS
+            removeTunnelNexthopFromDS(dpnId, ipAddress);
+        } else {
+            //throw error
+            LOG.error("removal of remote next hop failed : dpnid : {}, ipaddress : {}", dpnId, ipAddress);
+        }
+
+    }
+
+    @Override
+    public Future<RpcResult<GetEgressPointerOutput>> getEgressPointer(
+            GetEgressPointerInput input) {
+
+        GetEgressPointerOutputBuilder output = new GetEgressPointerOutputBuilder();
+
+        String endpointIp = interfaceManager.getEndpointIpForDpn(input.getDpnId());
+        LOG.trace("getEgressPointer: input {}, endpointIp {}", input, endpointIp);
+        if (input.getNexthopIp() == null || input.getNexthopIp().equals(endpointIp)) {
+            VpnNexthop vpnNextHop = getVpnNexthop(input.getVpnId(), input.getIpPrefix(), 5);
+            output.setEgressPointer(vpnNextHop.getEgressPointer());
+            output.setLocalDestination(true);
+        } else {
+            TunnelNexthop tunnelNextHop = getTunnelNexthop(input.getDpnId(), input.getNexthopIp());
+            output.setEgressPointer(tunnelNextHop.getEgressPointer());
+            output.setLocalDestination(false);
+        }
+
+        RpcResultBuilder<GetEgressPointerOutput> rpcResultBuilder = RpcResultBuilder.success();
+        rpcResultBuilder.withResult(output.build());
+
+        return Futures.immediateFuture(rpcResultBuilder.build());
+        
+    }
+
+    <T extends DataObject> Optional<T> read(LogicalDatastoreType datastoreType,
+            InstanceIdentifier<T> path) {
+
+        ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
+
+        Optional<T> result = Optional.absent();
         try {
-            listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
-                    getWildCardPath(), NexthopManager.this, DataChangeScope.SUBTREE);
-        } catch (final Exception e) {
-            LOG.error("Nexthop Manager DataChange listener registration fail!", e);
-            throw new IllegalStateException("Nexthop Manager registration Listener failed.", e);
+            result = tx.read(datastoreType, path).get();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
         }
+
+        return result;
+    }
+
+    private <T extends DataObject> void asyncWrite(LogicalDatastoreType datastoreType,
+            InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
+        WriteTransaction tx = broker.newWriteOnlyTransaction();
+        tx.merge(datastoreType, path, data, true);
+        Futures.addCallback(tx.submit(), callback);
+    }
+
+    private <T extends DataObject> void syncWrite(LogicalDatastoreType datastoreType,
+            InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
+        WriteTransaction tx = broker.newWriteOnlyTransaction();
+        tx.merge(datastoreType, path, data, true);
+        tx.submit();
+    }
+
+    private <T extends DataObject> void delete(LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
+        WriteTransaction tx = broker.newWriteOnlyTransaction();
+        tx.delete(datastoreType, path);
+        Futures.addCallback(tx.submit(), DEFAULT_CALLBACK);
     }
-    
-       public void addNextHop(long dpnId, int port, String vpnRD, String IpAddress)
-       {
-               String nhKey = new String("nexthop"+vpnRD+IpAddress);
-               
-               int groupId = 1;//getIdManager().getUniqueId("nextHopGroupIdPool", nhKey);
-
-/*             if (getNextHop(groupId) == Null){
-                       List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
-                       List<ActionInfo> listActionInfo = null;//nextHop.getActions({output to port}); 
-                       BucketInfo bucket = new BucketInfo(listActionInfo);
-                       listBucketInfo.add(bucket);
-                       //GroupEntity groupEntity = MDSALUtil.buildGroupEntity(dpId, groupId, IPAddress, GroupTypes.GroupIndirect, listBucketInfo);
-                       //getMdsalApiManager().installGroup(groupEntity, objTransaction???);
-                       
-                       //update MD-SAL DS
-                       addNextHopToDS(dpId, vpn, ipAddress, groupId);
-               }else{
-                       //check update
-               }*/
-       }       
-
-       public void removeNextHop(long dpnId, int port, String vpnRD, String IpAddress)
-       {
-               String nhKey = new String("nexthop"+vpnRD+IpAddress);
-               int groupId = 1;//getIdManager().getUniqueId(L3Constants.L3NEXTHOP_GROUPID_POOL, nhKey);
-
-/*             if (getNextHop(groupId) != Null){
-                       List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
-                       List<ActionInfo> listActionInfo = null;//nextHop.getActions({output to port}); 
-                       BucketInfo bucket = new BucketInfo(listActionInfo);
-                       listBucketInfo.add(bucket);
-                       //GroupEntity groupEntity = MDSALUtil.buildGroupEntity(dpId, groupId, IPAddress, GroupTypes.GroupIndirect, listBucketInfo);
-                       //getMdsalApiManager().removeGroup(groupEntity, objTransaction???);
-                       
-                       //update MD-SAL DS
-                       removeNextHopFromDS(dpId, vpn, ipAddress);
-               }else{
-                       //check update
-               }*/
-       }       
-               
-       public long getNextHopPointer(long dpnId, int vpnId, String prefixIp, String nxetHopIp)
-       {
-/*             String endpointIp = interfaceManager.getLocalEndpointIp(dpnId);
-               if (nextHopIp.equals(endpointIp)) {
-                       return getGidFromDS(dpnId, vpnId, prefixIp);
-               } else {
-                       return getGidFromDS(dpnId, 00, nextHopIp);
-               }*/
-               return 0;
-       }
-
-    private InstanceIdentifier<L3nexthop> getWildCardPath() {
-        return InstanceIdentifier.create(L3nexthop.class);//.child(l3nexthop.vpnNexthops.class);
-    }
-
-       private void addNextHopToDS(long dpId, int vpnId, String ipAddress, long groupId)
-       {
-               
-       }
-
-       private long getGidFromDS(String ipaddress)
-       {
-               return 0;
-               
-       }
-
-       @Override
-       protected void remove(InstanceIdentifier<L3nexthop> identifier,
-                       L3nexthop del) {
-               // TODO Auto-generated method stub
-               
-       }
-
-       @Override
-       protected void update(InstanceIdentifier<L3nexthop> identifier,
-                       L3nexthop original, L3nexthop update) {
-               // TODO Auto-generated method stub
-               
-       }
-
-       @Override
-       protected void add(InstanceIdentifier<L3nexthop> identifier, L3nexthop add) {
-               // TODO Auto-generated method stub
-               
-       }
-
-}
\ No newline at end of file
+
+    @Override
+    public Future<RpcResult<Void>> removeLocalNextHop(RemoveLocalNextHopInput input) {
+        VpnNexthop vpnNextHop = getVpnNexthop(input.getVpnId(), input.getIpPrefix(), 0);
+        RpcResultBuilder<Void> rpcResultBuilder;
+        LOG.debug("vpnnexthop is: {}", vpnNextHop);
+        try {
+            removeLocalNextHop(input.getDpnId(),input.getVpnId(), input.getIpPrefix());
+            rpcResultBuilder = RpcResultBuilder.success();
+        }
+        catch(Exception e){
+            LOG.error("Removal of local next hop for vpnNextHop {} failed {}" ,vpnNextHop, e);
+            rpcResultBuilder = RpcResultBuilder.failed();
+        }
+        return Futures.immediateFuture(rpcResultBuilder.build());
+    }
+
+}