Adding IdManager/LockManager and related Changes
[vpnservice.git] / nexthopmgr / nexthopmgr-impl / src / main / java / org / opendaylight / vpnservice / nexthopmgr / NexthopManager.java
index 8e1a4fc2e37d7cdf0d1eeec7af8d750baa389570..f44e84197cefcc0e44f93613a41be0cb850fab7a 100644 (file)
@@ -7,23 +7,27 @@
  */
 package org.opendaylight.vpnservice.nexthopmgr;
 
+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.util.concurrent.Futures;
 import com.google.common.util.concurrent.FutureCallback;
-
-//import org.opendaylight.controller.netconf.confignetconfconnector.mapping.rpc.Rpcs;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 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.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
@@ -31,11 +35,14 @@ import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev14081
 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.GetUniqueIdOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.GetUniqueIdInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.GetUniqueIdInput;
+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.*;
@@ -48,9 +55,7 @@ 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;
 
@@ -60,11 +65,15 @@ public class NexthopManager implements L3nexthopService, AutoCloseable {
     private IMdsalApiManager mdsalManager;
     private IInterfaceManager interfaceManager;
     private IdManager 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.info("Success in Datastore write operation");
+                LOG.debug("Success in Datastore write operation");
             }
             public void onFailure(Throwable error) {
                 LOG.error("Error in Datastore write operation", error);
@@ -79,7 +88,6 @@ public class NexthopManager implements L3nexthopService, AutoCloseable {
     */
     public NexthopManager(final DataBroker db) {
         broker = db;
-        createNexthopPointerPool();
     }
 
     @Override
@@ -99,54 +107,50 @@ public class NexthopManager implements L3nexthopService, AutoCloseable {
         this.idManager = idManager;
     }
 
-    private void createNexthopPointerPool() {
+    protected void createNexthopPointerPool() {
         CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
-            .setPoolName("nextHopPointerPool")
-            .setIdStart(1L)
-            .setPoolSize(new BigInteger("65535"))
-            .build();
+                .setPoolName("nextHopPointerPool")
+                .setLow(150000L)
+                .setHigh(175000L)
+                .build();
         //TODO: Error handling
         Future<RpcResult<Void>> result = idManager.createIdPool(createPool);
-//            try {
-//                LOG.info("Result2: {}",result.get());
-//            } catch (InterruptedException | ExecutionException e) {
-//                // TODO Auto-generated catch block
-//                LOG.error("Error in result.get");
-//            }
-
+        LOG.trace("NextHopPointerPool result : {}", result);
     }
 
 
-    private long getVpnId(String vpnName) {
+    protected long getVpnId(String vpnName) {
         InstanceIdentifierBuilder<VpnInstance> idBuilder = InstanceIdentifier.builder(VpnInstances.class)
                 .child(VpnInstance.class, new VpnInstanceKey(vpnName));
 
         InstanceIdentifier<VpnInstance> id = idBuilder.build();
         InstanceIdentifier<VpnInstance1> idx = id.augmentation(VpnInstance1.class);
-        Optional<VpnInstance1> vpn = read(LogicalDatastoreType.CONFIGURATION, idx);
+        Optional<VpnInstance1> vpn = read(LogicalDatastoreType.OPERATIONAL, idx);
 
         if (vpn.isPresent()) {
+            LOG.debug("VPN id returned: {}", vpn.get().getVpnId());
             return vpn.get().getVpnId();
         } else {
-            return 0;
+            return -1;
         }
     }
 
-    private long getDpnId(String ifName) {
-        String[] fields = ifName.split(":");
-        long dpn = Integer.parseInt(fields[1]);
+    private BigInteger getDpnId(String ofPortId) {
+        String[] fields = ofPortId.split(":");
+        BigInteger dpn = new BigInteger(fields[1]);
+        LOG.debug("DpnId: {}", dpn);
         return dpn;
     }
 
-    private int createNextHopPointer(String nexthopKey) {
-        GetUniqueIdInput getIdInput = new GetUniqueIdInputBuilder()
-            .setPoolName("nextHopPointerPool").setIdKey(nexthopKey)
-            .build();
+    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<GetUniqueIdOutput>> result = idManager.getUniqueId(getIdInput);
-            RpcResult<GetUniqueIdOutput> rpcResult = result.get();
-            return rpcResult.getResult().getIdValue().intValue();
+            Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
+            RpcResult<AllocateIdOutput> rpcResult = result.get();
+            return rpcResult.getResult().getIdValue();
         } catch (NullPointerException | InterruptedException | ExecutionException e) {
             LOG.trace("",e);
         }
@@ -155,20 +159,23 @@ public class NexthopManager implements L3nexthopService, AutoCloseable {
 
     public void createLocalNextHop(String ifName, String vpnName, String ipAddress, String macAddress) {
         String nhKey = new String("nexthop." + vpnName + ipAddress);
-        int groupId = createNextHopPointer(nhKey);
+        long groupId = createNextHopPointer(nhKey);
 
         long vpnId = getVpnId(vpnName);
-        long dpnId = interfaceManager.getDpnForInterface(ifName);
-        VpnNexthop nexthop = getVpnNexthop(vpnId, ipAddress);
+        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(new ActionInfo(ActionType.set_field_eth_dest, new String[]{macAddress}));
+               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(
@@ -184,14 +191,13 @@ public class NexthopManager implements L3nexthopService, AutoCloseable {
         }
     }
 
-    public void createRemoteNextHop(String ifName, String ofPortId, String ipAddress) {
+    public void createRemoteNextHop(String ifName, String ipAddress) {
         String nhKey = new String("nexthop." + ifName + ipAddress);
-        int groupId = createNextHopPointer(nhKey);
+        long groupId = createNextHopPointer(nhKey);
 
-        long dpnId = getDpnId(ofPortId);
+        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);
@@ -200,6 +206,7 @@ public class NexthopManager implements L3nexthopService, AutoCloseable {
             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);
@@ -208,19 +215,39 @@ public class NexthopManager implements L3nexthopService, AutoCloseable {
         }
     }
 
-    private void addVpnNexthopToDS(long vpnId, String ipPrefix, long egressPointer) {
+    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}));
+        }
 
-        InstanceIdentifierBuilder<VpnNexthops> idBuilder = InstanceIdentifier.builder(L3nexthop.class)
-                .child(VpnNexthops.class, new VpnNexthopsKey(vpnId));
+        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);
 
-        // check if vpn node is there or to be created
-        InstanceIdentifier<VpnNexthops> id = idBuilder.build();
-        Optional<VpnNexthops> nexthops = read(LogicalDatastoreType.CONFIGURATION, id);
-        if (!nexthops.isPresent()) {
-            // create a new node
-            VpnNexthops node = new VpnNexthopsBuilder().setKey(new VpnNexthopsKey(vpnId)).setVpnId(vpnId).build();
-            asyncWrite(LogicalDatastoreType.OPERATIONAL, id, node, DEFAULT_CALLBACK);
+        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().
@@ -230,27 +257,15 @@ public class NexthopManager implements L3nexthopService, AutoCloseable {
 
         InstanceIdentifier<VpnNexthop> id1 = idBuilder
                 .child(VpnNexthop.class, new VpnNexthopKey(ipPrefix)).build();
-
-        asyncWrite(LogicalDatastoreType.OPERATIONAL, id1, nh, DEFAULT_CALLBACK);
+        LOG.trace("Adding vpnnextHop {} to Operational DS", nh);
+        syncWrite(LogicalDatastoreType.OPERATIONAL, id1, nh, DEFAULT_CALLBACK);
 
     }
 
-    private void addTunnelNexthopToDS(long dpnId, String ipPrefix, long egressPointer) {
+    private void addTunnelNexthopToDS(BigInteger dpnId, String ipPrefix, long egressPointer) {
         InstanceIdentifierBuilder<TunnelNexthops> idBuilder = InstanceIdentifier.builder(L3nexthop.class)
                 .child(TunnelNexthops.class, new TunnelNexthopsKey(dpnId));
 
-        // check if dpn node is there or to be created
-        InstanceIdentifier<TunnelNexthops> id = idBuilder.build();
-        Optional<TunnelNexthops> nexthops = read(LogicalDatastoreType.CONFIGURATION, id);
-        if (!nexthops.isPresent()) {
-            // create a new node
-            TunnelNexthops node = new TunnelNexthopsBuilder()
-                .setKey(new TunnelNexthopsKey(dpnId))
-                .setDpnId(dpnId)
-                .build();
-            asyncWrite(LogicalDatastoreType.OPERATIONAL, id, node, DEFAULT_CALLBACK);
-        }
-
         // Add nexthop to dpn node
         TunnelNexthop nh = new TunnelNexthopBuilder().
                 setKey(new TunnelNexthopKey(ipPrefix)).
@@ -259,45 +274,54 @@ public class NexthopManager implements L3nexthopService, AutoCloseable {
 
         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);
 
     }
 
-    private VpnNexthop getVpnNexthop(long vpnId, String ipAddress) {
+    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));
+        // check if vpn node is there
+        InstanceIdentifierBuilder<VpnNexthops> idBuilder =
+                        InstanceIdentifier.builder(L3nexthop.class).child(VpnNexthops.class, new VpnNexthopsKey(vpnId));
         InstanceIdentifier<VpnNexthops> id = idBuilder.build();
-        Optional<VpnNexthops> vpnNexthops = read(LogicalDatastoreType.CONFIGURATION, 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 
-                    return nexthop;
+        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 if not found
         return null;
     }
 
-    private TunnelNexthop getTunnelNexthop(long dpnId, String ipAddress) {
+    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.CONFIGURATION, id);
-        if (!dpnNexthops.isPresent()) {
+        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;
                 }
             }
@@ -305,24 +329,26 @@ public class NexthopManager implements L3nexthopService, AutoCloseable {
         return null;
     }
 
-    public long getNextHopPointer(long dpnId, long vpnId, String prefixIp, String nextHopIp) {
+    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);
+            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(long dpnId, String ipPrefix) {
+    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);
     }
 
@@ -333,30 +359,31 @@ public class NexthopManager implements L3nexthopService, AutoCloseable {
                 .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(String vpnName, String ipAddress) {
+    public void removeLocalNextHop(BigInteger dpnId, Long vpnId, String ipAddress) {
 
-        long vpnId = getVpnId(vpnName);
-
-        VpnNexthop nh = getVpnNexthop(vpnId, 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(long dpnId, String ipAddress) {
+    public void removeRemoteNextHop(BigInteger dpnId, String ifName, String ipAddress) {
 
         TunnelNexthop nh = getTunnelNexthop(dpnId, ipAddress);
         if (nh != null) {
@@ -364,10 +391,16 @@ public class NexthopManager implements L3nexthopService, AutoCloseable {
             // 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);
         }
 
     }
@@ -375,18 +408,29 @@ public class NexthopManager implements L3nexthopService, AutoCloseable {
     @Override
     public Future<RpcResult<GetEgressPointerOutput>> getEgressPointer(
             GetEgressPointerInput input) {
-        long egressGroupId =
-                getNextHopPointer(input.getDpnId(), input.getVpnId(), input.getIpPrefix(), input.getNexthopIp());
 
         GetEgressPointerOutputBuilder output = new GetEgressPointerOutputBuilder();
-        output.setEgressPointer(egressGroupId);
 
-        RpcResult<GetEgressPointerOutput> result = null;
-        //Rpcs.<GetEgressPointerOutput> getRpcResult(false, output.build());
-        return Futures.immediateFuture(result); 
+        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());
+        
     }
 
-    private <T extends DataObject> Optional<T> read(LogicalDatastoreType datastoreType,
+    <T extends DataObject> Optional<T> read(LogicalDatastoreType datastoreType,
             InstanceIdentifier<T> path) {
 
         ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
@@ -404,10 +448,16 @@ public class NexthopManager implements L3nexthopService, AutoCloseable {
     private <T extends DataObject> void asyncWrite(LogicalDatastoreType datastoreType,
             InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
         WriteTransaction tx = broker.newWriteOnlyTransaction();
-        tx.put(datastoreType, path, data, true);
+        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();
@@ -415,4 +465,20 @@ public class NexthopManager implements L3nexthopService, AutoCloseable {
         Futures.addCallback(tx.submit(), DEFAULT_CALLBACK);
     }
 
-}
\ 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());
+    }
+
+}