Revert "TSC-181: ITM Yang Models Cleanup"
[genius.git] / itm / itm-impl / src / main / java / org / opendaylight / genius / itm / rpc / ItmManagerRpcService.java
index 71ff9d2fc2c65c23dbd7dfd272cfe1ad83d05e4d..dfff9304338ef7b78fa2e57444aef21dd350d5db 100644 (file)
@@ -7,12 +7,14 @@
  */
 package org.opendaylight.genius.itm.rpc;
 
-import static org.opendaylight.genius.tools.mdsal.rpc.FutureRpcResults.LogLevel.ERROR;
-import static org.opendaylight.genius.tools.mdsal.rpc.FutureRpcResults.fromListenableFuture;
+import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
+import static org.opendaylight.serviceutils.tools.rpc.FutureRpcResults.LogLevel.ERROR;
+import static org.opendaylight.serviceutils.tools.rpc.FutureRpcResults.fromListenableFuture;
 import static org.opendaylight.yangtools.yang.common.RpcResultBuilder.failed;
 
 import com.google.common.base.Objects;
 import com.google.common.base.Optional;
+import com.google.common.util.concurrent.FluentFuture;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
@@ -25,41 +27,47 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.Future;
+import java.util.concurrent.ExecutionException;
 import java.util.stream.Collectors;
-import javax.annotation.Nonnull;
 import javax.annotation.PostConstruct;
 import javax.annotation.PreDestroy;
 import javax.inject.Inject;
 import javax.inject.Singleton;
+import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
+import org.opendaylight.genius.infra.Datastore;
+import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
+import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
+import org.opendaylight.genius.infra.RetryingManagedNewTransactionRunner;
+import org.opendaylight.genius.infra.TypedReadWriteTransaction;
 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
 import org.opendaylight.genius.interfacemanager.interfaces.InterfaceManagerService;
 import org.opendaylight.genius.itm.cache.DPNTEPsInfoCache;
 import org.opendaylight.genius.itm.cache.DpnTepStateCache;
+import org.opendaylight.genius.itm.cache.OvsBridgeRefEntryCache;
 import org.opendaylight.genius.itm.cache.TunnelStateCache;
 import org.opendaylight.genius.itm.confighelpers.ItmExternalTunnelAddWorker;
 import org.opendaylight.genius.itm.confighelpers.ItmExternalTunnelDeleteWorker;
 import org.opendaylight.genius.itm.globals.ITMConstants;
 import org.opendaylight.genius.itm.impl.ItmUtils;
+import org.opendaylight.genius.itm.itmdirecttunnels.renderer.ovs.utilities.DirectTunnelUtils;
 import org.opendaylight.genius.itm.utils.DpnTepInterfaceInfo;
 import org.opendaylight.genius.mdsalutil.ActionInfo;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
 import org.opendaylight.genius.mdsalutil.MatchInfo;
+import org.opendaylight.genius.mdsalutil.MetaDataUtil;
 import org.opendaylight.genius.mdsalutil.NwConstants;
-import org.opendaylight.genius.mdsalutil.actions.ActionOutput;
+import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
+import org.opendaylight.genius.mdsalutil.actions.ActionRegLoad;
 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
-import org.opendaylight.genius.tools.mdsal.rpc.FutureRpcResults;
+import org.opendaylight.serviceutils.tools.rpc.FutureRpcResults;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.BridgeRefInfo;
@@ -68,15 +76,21 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.met
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeLogicalGroup;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.config.rev160406.ItmConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.ovs.bridge.ref.info.OvsBridgeRefEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.DpnEndpoints;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.DpnTepsState;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.ExternalTunnelList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.DPNTEPsInfo;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.DPNTEPsInfoKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.dpn.teps.info.TunnelEndPoints;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.teps.state.DpnsTeps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.teps.state.DpnsTepsKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.teps.state.dpns.teps.RemoteDpns;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.teps.state.dpns.teps.RemoteDpnsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.teps.state.dpns.teps.RemoteDpnsKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnel;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnelKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnel.list.InternalTunnel;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.DcGatewayIpList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.TransportZones;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.dc.gateway.ip.list.DcGatewayIp;
@@ -91,12 +105,19 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transp
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.subnets.DeviceVtepsKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.subnets.Vteps;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.AddExternalTunnelEndpointInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.AddExternalTunnelEndpointOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.AddL2GwDeviceInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.AddL2GwDeviceOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.AddL2GwMlagDeviceInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.AddL2GwMlagDeviceOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.BuildExternalTunnelFromDpnsInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.BuildExternalTunnelFromDpnsOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.CreateTerminatingServiceActionsInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.CreateTerminatingServiceActionsOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.DeleteL2GwDeviceInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.DeleteL2GwDeviceOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.DeleteL2GwMlagDeviceInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.DeleteL2GwMlagDeviceOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetDpnEndpointIpsInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetDpnEndpointIpsOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetDpnEndpointIpsOutputBuilder;
@@ -118,6 +139,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.G
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelTypeInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelTypeOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelTypeOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetWatchPortForTunnelInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetWatchPortForTunnelOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.IsDcgwPresentInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.IsDcgwPresentOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.IsDcgwPresentOutputBuilder;
@@ -126,14 +149,21 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.I
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.IsTunnelInternalOrExternalOutputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveExternalTunnelEndpointInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveExternalTunnelEndpointOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveExternalTunnelFromDpnsInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveExternalTunnelFromDpnsOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveTerminatingServiceActionsInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.SetBfdEnableOnTunnelInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveTerminatingServiceActionsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.SetBfdParamOnTunnelInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.SetBfdParamOnTunnelOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.SetBfdParamOnTunnelOutputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.get.dpn.info.output.Computes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.get.dpn.info.output.ComputesBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg6;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.OperationFailedException;
 import org.opendaylight.yangtools.yang.common.RpcError;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
@@ -154,22 +184,34 @@ public class ItmManagerRpcService implements ItmRpcService {
     private final InterfaceManagerService interfaceManagerService;
     private final DpnTepStateCache dpnTepStateCache;
     private final TunnelStateCache tunnelStateCache;
+    private final OvsBridgeRefEntryCache ovsBridgeRefEntryCache;
+    private final DirectTunnelUtils directTunnelUtils;
+    private final ManagedNewTransactionRunner txRunner;
+    private final RetryingManagedNewTransactionRunner retryingTxRunner;
+    private final ItmConfig itmConfig;
 
     @Inject
     public ItmManagerRpcService(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
                                 final ItmConfig itmConfig, final DPNTEPsInfoCache dpnTEPsInfoCache,
                                 final IInterfaceManager interfaceManager, final DpnTepStateCache dpnTepStateCache,
                                 final TunnelStateCache tunnelStateCache,
-                                final InterfaceManagerService interfaceManagerService) {
+                                final InterfaceManagerService interfaceManagerService,
+                                final OvsBridgeRefEntryCache ovsBridgeRefEntryCache,
+                                final DirectTunnelUtils directTunnelUtils) {
         this.dataBroker = dataBroker;
         this.mdsalManager = mdsalManager;
         this.dpnTEPsInfoCache = dpnTEPsInfoCache;
-        this.externalTunnelAddWorker = new ItmExternalTunnelAddWorker(dataBroker, itmConfig, dpnTEPsInfoCache);
+        this.externalTunnelAddWorker = new ItmExternalTunnelAddWorker(itmConfig, dpnTEPsInfoCache);
         this.singleTransactionDataBroker = new SingleTransactionDataBroker(dataBroker);
         this.interfaceManager = interfaceManager;
         this.interfaceManagerService = interfaceManagerService;
         this.dpnTepStateCache = dpnTepStateCache;
         this.tunnelStateCache = tunnelStateCache;
+        this.ovsBridgeRefEntryCache = ovsBridgeRefEntryCache;
+        this.directTunnelUtils = directTunnelUtils;
+        this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
+        this.retryingTxRunner = new RetryingManagedNewTransactionRunner(dataBroker);
+        this.itmConfig = itmConfig;
     }
 
     @PostConstruct
@@ -183,12 +225,22 @@ public class ItmManagerRpcService implements ItmRpcService {
     }
 
     @Override
-    public Future<RpcResult<GetTunnelInterfaceNameOutput>> getTunnelInterfaceName(GetTunnelInterfaceNameInput input) {
+    public ListenableFuture<RpcResult<GetTunnelInterfaceNameOutput>> getTunnelInterfaceName(
+            GetTunnelInterfaceNameInput input) {
         RpcResultBuilder<GetTunnelInterfaceNameOutput> resultBld = null;
         BigInteger sourceDpn = input.getSourceDpid();
         BigInteger destinationDpn = input.getDestinationDpid();
         Optional<InternalTunnel> optTunnel = Optional.absent();
 
+        if (interfaceManager.isItmDirectTunnelsEnabled()) {
+            DpnTepInterfaceInfo interfaceInfo = dpnTepStateCache.getDpnTepInterface(sourceDpn, destinationDpn);
+            if (interfaceInfo != null) {
+                resultBld = RpcResultBuilder.success();
+                resultBld.withResult(new GetTunnelInterfaceNameOutputBuilder()
+                        .setInterfaceName(interfaceInfo.getTunnelName())).build();
+                return Futures.immediateFuture(resultBld.build());
+            }
+        }
         if (ItmUtils.isTunnelAggregationUsed(input.getTunnelType())) {
             optTunnel = ItmUtils.getInternalTunnelFromDS(sourceDpn, destinationDpn,
                                                          TunnelTypeLogicalGroup.class, dataBroker);
@@ -216,7 +268,7 @@ public class ItmManagerRpcService implements ItmRpcService {
     }
 
     @Override
-    public Future<RpcResult<GetEgressActionsForTunnelOutput>>
+    public ListenableFuture<RpcResult<GetEgressActionsForTunnelOutput>>
         getEgressActionsForTunnel(GetEgressActionsForTunnelInput input) {
         String tunnelName = input.getIntfName();
         if (tunnelName == null) {
@@ -224,8 +276,7 @@ public class ItmManagerRpcService implements ItmRpcService {
                     .withError(RpcError.ErrorType.APPLICATION,
                     "tunnel name not set for GetEgressActionsForTunnel call").build());
         }
-
-        if (!dpnTepStateCache.isInternal(tunnelName) && !interfaceManager.isItmDirectTunnelsEnabled()) {
+        if (!dpnTepStateCache.isInternal(tunnelName) || !interfaceManager.isItmDirectTunnelsEnabled()) {
             // Re-direct the RPC to Interface Manager
             // From the rpc input and get the output and copy to output
             org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406
@@ -238,8 +289,8 @@ public class ItmManagerRpcService implements ItmRpcService {
                     new FutureCallback<org.opendaylight.yang.gen.v1.urn.opendaylight.genius
                             .interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceOutput>() {
                         @Override
-                        public void onSuccess(@Nonnull org.opendaylight.yang.gen.v1.urn.opendaylight.genius
-                                .interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceOutput result) {
+                        public void onSuccess(org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs
+                                .rev160406.@NonNull GetEgressActionsForInterfaceOutput result) {
                             GetEgressActionsForTunnelOutputBuilder output =
                                     new GetEgressActionsForTunnelOutputBuilder().setAction(result.getAction());
                             settableFuture.set(RpcResultBuilder.<GetEgressActionsForTunnelOutput>success()
@@ -254,16 +305,16 @@ public class ItmManagerRpcService implements ItmRpcService {
                             settableFuture.set(RpcResultBuilder.<GetEgressActionsForTunnelOutput>failed()
                                     .withError(RpcError.ErrorType.APPLICATION, errMsg, throwable).build());
                         }
-                });
+                } ,MoreExecutors.directExecutor());
             return  settableFuture;
         } else {
-            return fromListenableFuture(LOG, input, () -> getEgressActionsForInterface(input.getIntfName(),
+            return fromListenableFuture(LOG, input, () -> getEgressActionsForInternalTunnels(input.getIntfName(),
                     input.getTunnelKey(), input.getActionKey())).onFailureLogLevel(ERROR).build();
         }
     }
 
     @Override
-    public Future<RpcResult<GetTunnelTypeOutput>> getTunnelType(GetTunnelTypeInput input) {
+    public ListenableFuture<RpcResult<GetTunnelTypeOutput>> getTunnelType(GetTunnelTypeInput input) {
         String tunnelName = input.getIntfName();
         if (tunnelName == null) {
             return Futures.immediateFuture(RpcResultBuilder.<GetTunnelTypeOutput>failed()
@@ -280,22 +331,25 @@ public class ItmManagerRpcService implements ItmRpcService {
             Futures.addCallback(interfaceManagerService.getTunnelType(inputBuilder.build()),
                     new FutureCallback<org.opendaylight.yang.gen.v1.urn.opendaylight.genius
                             .interfacemanager.rpcs.rev160406.GetTunnelTypeOutput>() {
-                        public void onSuccess(@Nonnull org.opendaylight.yang.gen.v1.urn.opendaylight.genius
-                                .interfacemanager.rpcs.rev160406.GetTunnelTypeOutput result) {
+                        @Override
+                        public void onSuccess(org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs
+                                .rev160406.@NonNull GetTunnelTypeOutput result) {
                             GetTunnelTypeOutputBuilder output = new GetTunnelTypeOutputBuilder()
                                     .setTunnelType(result.getTunnelType());
                             settableFuture.set(RpcResultBuilder.<GetTunnelTypeOutput>success()
                                     .withResult(output.build()).build());
                         }
 
+                        @Override
                         public void onFailure(Throwable throwable) {
                             LOG.debug("RPC Call to Get tunnel type failed for interface {}", tunnelName);
                             String errMsg = String.format("RPC to Get tunnel type failed for interface %s",
                                     tunnelName);
                             settableFuture.set(RpcResultBuilder.<GetTunnelTypeOutput>failed()
                                     .withError(RpcError.ErrorType.APPLICATION, errMsg, throwable).build());
+
                         }
-                });
+                },MoreExecutors.directExecutor());
             return settableFuture;
         } else {
             LOG.debug("get tunnel type from ITM for interface name {}", input.getIntfName());
@@ -307,29 +361,52 @@ public class ItmManagerRpcService implements ItmRpcService {
     }
 
     @Override
-    public Future<RpcResult<Void>> setBfdEnableOnTunnel(SetBfdEnableOnTunnelInput input) {
-        //TODO
-        return null;
+    public ListenableFuture<RpcResult<SetBfdParamOnTunnelOutput>> setBfdParamOnTunnel(
+            SetBfdParamOnTunnelInput input) {
+        BigInteger srcDpnId = new BigInteger(input.getSourceNode());
+        BigInteger destDpnId = new BigInteger(input.getDestinationNode());
+        DpnTepInterfaceInfo dpnTepInterfaceInfo = dpnTepStateCache.getDpnTepInterface(srcDpnId, destDpnId);
+        return fromListenableFuture(LOG, input,
+            () -> Futures.transform(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
+                java.util.Objects.requireNonNull(dpnTepInterfaceInfo, "dpnTepInterfaceInfo");
+                RemoteDpnsBuilder remoteDpnsBuilder = new RemoteDpnsBuilder();
+                remoteDpnsBuilder.withKey(new RemoteDpnsKey(destDpnId));
+                remoteDpnsBuilder.setDestinationDpnId(destDpnId);
+                remoteDpnsBuilder.setTunnelName(dpnTepInterfaceInfo.getTunnelName());
+                remoteDpnsBuilder.setInternal(dpnTepInterfaceInfo.isInternal());
+                if (input.isMonitoringEnabled() && input.getMonitoringInterval() != null) {
+                    remoteDpnsBuilder.setMonitoringInterval(input.getMonitoringInterval());
+                }
+                remoteDpnsBuilder.setMonitoringEnabled(input.isMonitoringEnabled());
+                RemoteDpns remoteDpn = remoteDpnsBuilder.build();
+                Optional<OvsBridgeRefEntry> ovsBridgeRefEntry = ovsBridgeRefEntryCache.get(srcDpnId);
+                directTunnelUtils.updateBfdConfiguration(srcDpnId, remoteDpn, ovsBridgeRefEntry);
+                InstanceIdentifier<RemoteDpns> iid = InstanceIdentifier.builder(DpnTepsState.class)
+                    .child(DpnsTeps.class, new DpnsTepsKey(srcDpnId))
+                    .child(RemoteDpns.class,
+                        new RemoteDpnsKey(destDpnId)).build();
+                tx.merge(LogicalDatastoreType.CONFIGURATION, iid, remoteDpn);
+            }), unused -> new SetBfdParamOnTunnelOutputBuilder().build(), MoreExecutors.directExecutor())).build();
     }
 
-
     @Override
-    public Future<RpcResult<Void>> removeExternalTunnelEndpoint(
+    public ListenableFuture<RpcResult<RemoveExternalTunnelEndpointOutput>> removeExternalTunnelEndpoint(
             RemoveExternalTunnelEndpointInput input) {
         //Ignore the Futures for now
-        final SettableFuture<RpcResult<Void>> result = SettableFuture.create();
+        final SettableFuture<RpcResult<RemoveExternalTunnelEndpointOutput>> result = SettableFuture.create();
         Collection<DPNTEPsInfo> meshedDpnList = dpnTEPsInfoCache.getAllPresent();
-        ItmExternalTunnelDeleteWorker.deleteTunnels(dataBroker, meshedDpnList,
-                input.getDestinationIp(), input.getTunnelType());
-        InstanceIdentifier<DcGatewayIp> extPath = InstanceIdentifier.builder(DcGatewayIpList.class)
-                .child(DcGatewayIp.class, new DcGatewayIpKey(input.getDestinationIp())).build();
-        WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
-        transaction.delete(LogicalDatastoreType.CONFIGURATION, extPath);
-        ListenableFuture<Void> futureCheck = transaction.submit();
-        Futures.addCallback(futureCheck, new FutureCallback<Void>() {
-
+        FluentFuture<Void> future = txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
+            tx -> {
+                ItmExternalTunnelDeleteWorker.deleteTunnels(meshedDpnList, input.getDestinationIp(),
+                    input.getTunnelType(), tx);
+                InstanceIdentifier<DcGatewayIp> extPath = InstanceIdentifier.builder(DcGatewayIpList.class)
+                    .child(DcGatewayIp.class, new DcGatewayIpKey(input.getDestinationIp())).build();
+                tx.delete(extPath);
+            }
+        );
+        future.addCallback(new FutureCallback<Void>() {
             @Override public void onSuccess(Void voidInstance) {
-                result.set(RpcResultBuilder.<Void>success().build());
+                result.set(RpcResultBuilder.<RemoveExternalTunnelEndpointOutput>success().build());
             }
 
             @Override public void onFailure(Throwable error) {
@@ -337,74 +414,92 @@ public class ItmManagerRpcService implements ItmRpcService {
                         + " in datastore and tunnel type " + input.getTunnelType();
                 LOG.error("Unable to delete DcGatewayIp {} in datastore and tunnel type {}", input.getDestinationIp(),
                         input.getTunnelType());
-                result.set(RpcResultBuilder.<Void>failed()
+                result.set(RpcResultBuilder.<RemoveExternalTunnelEndpointOutput>failed()
                         .withError(RpcError.ErrorType.APPLICATION, msg, error).build());
             }
-        });
+        }, MoreExecutors.directExecutor());
         return result;
     }
 
     @Override
-    public Future<RpcResult<Void>> removeExternalTunnelFromDpns(
+    public ListenableFuture<RpcResult<RemoveExternalTunnelFromDpnsOutput>> removeExternalTunnelFromDpns(
             RemoveExternalTunnelFromDpnsInput input) {
         //Ignore the Futures for now
-        final SettableFuture<RpcResult<Void>> result = SettableFuture.create();
-        List<DPNTEPsInfo> cfgDpnList = ItmUtils.getDpnTepListFromDpnId(dpnTEPsInfoCache, input.getDpnId()) ;
-        ItmExternalTunnelDeleteWorker.deleteTunnels(dataBroker, cfgDpnList,
-                input.getDestinationIp(), input.getTunnelType());
-        result.set(RpcResultBuilder.<Void>success().build());
+        final SettableFuture<RpcResult<RemoveExternalTunnelFromDpnsOutput>> result = SettableFuture.create();
+        List<DPNTEPsInfo> cfgDpnList = ItmUtils.getDpnTepListFromDpnId(dpnTEPsInfoCache, input.getDpnId());
+        FluentFuture<Void> future = txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
+            tx -> ItmExternalTunnelDeleteWorker.deleteTunnels(cfgDpnList, input.getDestinationIp(),
+                input.getTunnelType(), tx));
+
+        future.addCallback(new FutureCallback<Void>() {
+            @Override
+            public void onSuccess(Void voidInstance) {
+                result.set(RpcResultBuilder.<RemoveExternalTunnelFromDpnsOutput>success().build());
+            }
+
+            @Override
+            public void onFailure(Throwable error) {
+                String msg = "Unable to remove external tunnel from DPN";
+                LOG.error("remove ext tunnel failed. {}.", msg, error);
+                result.set(RpcResultBuilder.<RemoveExternalTunnelFromDpnsOutput>failed()
+                        .withError(RpcError.ErrorType.APPLICATION, msg, error).build());
+            }
+        }, MoreExecutors.directExecutor());
         return result;
     }
 
     @Override
-    public Future<RpcResult<Void>> buildExternalTunnelFromDpns(
+    public ListenableFuture<RpcResult<BuildExternalTunnelFromDpnsOutput>> buildExternalTunnelFromDpns(
             BuildExternalTunnelFromDpnsInput input) {
         //Ignore the Futures for now
-        final SettableFuture<RpcResult<Void>> result = SettableFuture.create();
-        List<ListenableFuture<Void>> extTunnelResultList = externalTunnelAddWorker
-            .buildTunnelsFromDpnToExternalEndPoint(input.getDpnId(), input.getDestinationIp(),input.getTunnelType());
-        for (ListenableFuture<Void> extTunnelResult : extTunnelResultList) {
-            Futures.addCallback(extTunnelResult, new FutureCallback<Void>() {
-
-                @Override
-                public void onSuccess(Void voidInstance) {
-                    result.set(RpcResultBuilder.<Void>success().build());
-                }
+        final SettableFuture<RpcResult<BuildExternalTunnelFromDpnsOutput>> result = SettableFuture.create();
+        FluentFuture<Void> extTunnelResultList =
+            txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
+                tx -> externalTunnelAddWorker.buildTunnelsFromDpnToExternalEndPoint(input.getDpnId(),
+                    input.getDestinationIp(),input.getTunnelType(), tx));
 
-                @Override
-                public void onFailure(Throwable error) {
-                    String msg = "Unable to create ext tunnel";
-                    LOG.error("create ext tunnel failed. {}.", msg, error);
-                    result.set(RpcResultBuilder.<Void>failed()
-                            .withError(RpcError.ErrorType.APPLICATION, msg, error).build());
-                }
-            });
-        }
+        extTunnelResultList.addCallback(new FutureCallback<Void>() {
+
+            @Override
+            public void onSuccess(Void voidInstance) {
+                result.set(RpcResultBuilder.<BuildExternalTunnelFromDpnsOutput>success().build());
+            }
+
+            @Override
+            public void onFailure(Throwable error) {
+                String msg = "Unable to create ext tunnel";
+                LOG.error("create ext tunnel failed. {}.", msg, error);
+                result.set(RpcResultBuilder.<BuildExternalTunnelFromDpnsOutput>failed()
+                        .withError(RpcError.ErrorType.APPLICATION, msg, error).build());
+            }
+        }, MoreExecutors.directExecutor());
         return result;
     }
 
     @Override
-    public Future<RpcResult<Void>> addExternalTunnelEndpoint(
+    public ListenableFuture<RpcResult<AddExternalTunnelEndpointOutput>> addExternalTunnelEndpoint(
             AddExternalTunnelEndpointInput input) {
         // TODO Auto-generated method stub
 
         //Ignore the Futures for now
-        final SettableFuture<RpcResult<Void>> result = SettableFuture.create();
+        final SettableFuture<RpcResult<AddExternalTunnelEndpointOutput>> result = SettableFuture.create();
         Collection<DPNTEPsInfo> meshedDpnList = dpnTEPsInfoCache.getAllPresent();
-        externalTunnelAddWorker.buildTunnelsToExternalEndPoint(meshedDpnList,
-                input.getDestinationIp(), input.getTunnelType());
         InstanceIdentifier<DcGatewayIp> extPath = InstanceIdentifier.builder(DcGatewayIpList.class)
                 .child(DcGatewayIp.class, new DcGatewayIpKey(input.getDestinationIp())).build();
         DcGatewayIp dcGatewayIp =
                 new DcGatewayIpBuilder().setIpAddress(input.getDestinationIp())
                         .setTunnnelType(input.getTunnelType()).build();
-        WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
-        writeTransaction.put(LogicalDatastoreType.CONFIGURATION, extPath,dcGatewayIp, true);
-        ListenableFuture<Void> futureCheck = writeTransaction.submit();
-        Futures.addCallback(futureCheck, new FutureCallback<Void>() {
 
+        FluentFuture<Void> future = txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
+            tx -> {
+                externalTunnelAddWorker.buildTunnelsToExternalEndPoint(meshedDpnList, input.getDestinationIp(),
+                        input.getTunnelType(), tx);
+                tx.put(extPath, dcGatewayIp, true);
+            }
+        );
+        future.addCallback(new FutureCallback<Void>() {
             @Override public void onSuccess(Void voidInstance) {
-                result.set(RpcResultBuilder.<Void>success().build());
+                result.set(RpcResultBuilder.<AddExternalTunnelEndpointOutput>success().build());
             }
 
             @Override public void onFailure(Throwable error) {
@@ -414,15 +509,15 @@ public class ItmManagerRpcService implements ItmRpcService {
 
                 LOG.error("Unable to create DcGatewayIp in datastore for ip {} and tunnel type {}",
                         input.getDestinationIp() , input.getTunnelType());
-                result.set(RpcResultBuilder.<Void>failed()
+                result.set(RpcResultBuilder.<AddExternalTunnelEndpointOutput>failed()
                         .withError(RpcError.ErrorType.APPLICATION, msg, error).build());
             }
-        });
+        }, MoreExecutors.directExecutor());
         return result;
     }
 
     @Override
-    public Future<RpcResult<GetExternalTunnelInterfaceNameOutput>> getExternalTunnelInterfaceName(
+    public ListenableFuture<RpcResult<GetExternalTunnelInterfaceNameOutput>> getExternalTunnelInterfaceName(
             GetExternalTunnelInterfaceNameInput input) {
         SettableFuture.create();
         RpcResultBuilder<GetExternalTunnelInterfaceNameOutput> resultBld;
@@ -447,11 +542,11 @@ public class ItmManagerRpcService implements ItmRpcService {
     }
 
     @Override
-    public Future<RpcResult<java.lang.Void>>
+    public ListenableFuture<RpcResult<CreateTerminatingServiceActionsOutput>>
         createTerminatingServiceActions(final CreateTerminatingServiceActionsInput input) {
         LOG.info("create terminatingServiceAction on DpnId = {} for service id {} and instructions {}",
                 input.getDpnId() , input.getServiceId(), input.getInstruction());
-        final SettableFuture<RpcResult<Void>> result = SettableFuture.create();
+        final SettableFuture<RpcResult<CreateTerminatingServiceActionsOutput>> result = SettableFuture.create();
         int serviceId = input.getServiceId() ;
         final List<MatchInfo> mkMatches = getTunnelMatchesForServiceId(serviceId);
 
@@ -460,20 +555,21 @@ public class ItmManagerRpcService implements ItmRpcService {
                 String.format("%s:%d","ITM Flow Entry ",serviceId), 0, 0,
                 ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(serviceId)),mkMatches, input.getInstruction());
 
-        ListenableFuture<Void> installFlowResult =
-                mdsalManager.installFlow(input.getDpnId(), terminatingServiceTableFlow);
+        ListenableFuture<Void> installFlowResult = txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
+            tx -> mdsalManager.addFlow(tx, input.getDpnId(), terminatingServiceTableFlow));
         Futures.addCallback(installFlowResult, new FutureCallback<Void>() {
 
             @Override
             public void onSuccess(Void voidInstance) {
-                result.set(RpcResultBuilder.<Void>success().build());
+                result.set(RpcResultBuilder.<CreateTerminatingServiceActionsOutput>success().build());
             }
 
             @Override
             public void onFailure(Throwable error) {
                 String msg = String.format("Unable to install terminating service flow for %s", input.getDpnId());
                 LOG.error("create terminating service actions failed. {}", msg, error);
-                result.set(RpcResultBuilder.<Void>failed().withError(RpcError.ErrorType.APPLICATION, msg, error)
+                result.set(RpcResultBuilder.<CreateTerminatingServiceActionsOutput>failed()
+                        .withError(RpcError.ErrorType.APPLICATION, msg, error)
                         .build());
             }
         }, MoreExecutors.directExecutor());
@@ -482,31 +578,29 @@ public class ItmManagerRpcService implements ItmRpcService {
     }
 
     @Override
-    public Future<RpcResult<java.lang.Void>>
+    public ListenableFuture<RpcResult<RemoveTerminatingServiceActionsOutput>>
         removeTerminatingServiceActions(final RemoveTerminatingServiceActionsInput input) {
         LOG.info("remove terminatingServiceActions called with DpnId = {} and serviceId = {}",
                 input.getDpnId(), input.getServiceId());
-        final SettableFuture<RpcResult<Void>> result = SettableFuture.create();
-        Flow terminatingServiceTableFlow = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
-                getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE,input.getServiceId()), 5,
-                String.format("%s:%d","ITM Flow Entry ",input.getServiceId()), 0, 0,
-                ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(input.getServiceId())),
-                getTunnelMatchesForServiceId(input.getServiceId()), null);
+        final SettableFuture<RpcResult<RemoveTerminatingServiceActionsOutput>> result = SettableFuture.create();
 
-        ListenableFuture<Void> installFlowResult =
-                mdsalManager.removeFlow(input.getDpnId(), terminatingServiceTableFlow);
-        Futures.addCallback(installFlowResult, new FutureCallback<Void>() {
+        ListenableFuture<Void> removeFlowResult = txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
+            tx -> mdsalManager.removeFlow(tx, input.getDpnId(),
+                getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, input.getServiceId()),
+                NwConstants.INTERNAL_TUNNEL_TABLE));
+        Futures.addCallback(removeFlowResult, new FutureCallback<Void>() {
 
             @Override
             public void onSuccess(Void voidInstance) {
-                result.set(RpcResultBuilder.<Void>success().build());
+                result.set(RpcResultBuilder.<RemoveTerminatingServiceActionsOutput>success().build());
             }
 
             @Override
             public void onFailure(Throwable error) {
                 String msg = String.format("Unable to remove terminating service flow for %s", input.getDpnId());
                 LOG.error("remove terminating service actions failed. {}", msg, error);
-                result.set(RpcResultBuilder.<Void>failed().withError(RpcError.ErrorType.APPLICATION, msg, error)
+                result.set(RpcResultBuilder.<RemoveTerminatingServiceActionsOutput>failed()
+                        .withError(RpcError.ErrorType.APPLICATION, msg, error)
                         .build());
             }
         }, MoreExecutors.directExecutor());
@@ -530,15 +624,14 @@ public class ItmManagerRpcService implements ItmRpcService {
     }
 
     @Override
-    public Future<RpcResult<GetInternalOrExternalInterfaceNameOutput>> getInternalOrExternalInterfaceName(
+    public ListenableFuture<RpcResult<GetInternalOrExternalInterfaceNameOutput>> getInternalOrExternalInterfaceName(
             GetInternalOrExternalInterfaceNameInput input) {
         RpcResultBuilder<GetInternalOrExternalInterfaceNameOutput> resultBld = failed();
         BigInteger srcDpn = input.getSourceDpid() ;
         IpAddress dstIp = input.getDestinationIp() ;
         InstanceIdentifier<ExternalTunnel> path1 = InstanceIdentifier.create(ExternalTunnelList.class)
                 .child(ExternalTunnel.class,
-                        new ExternalTunnelKey(String.valueOf(dstIp.getValue()),
-                            srcDpn.toString(), input.getTunnelType()));
+                        new ExternalTunnelKey(dstIp.stringValue(), srcDpn.toString(), input.getTunnelType()));
 
         Optional<ExternalTunnel> optExtTunnel = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path1, dataBroker);
 
@@ -557,6 +650,17 @@ public class ItmManagerRpcService implements ItmRpcService {
                 TunnelEndPoints firstEndPt = teps.getTunnelEndPoints().get(0);
                 if (dstIp.equals(firstEndPt.getIpAddress())) {
                     Optional<InternalTunnel> optTunnel = Optional.absent();
+                    if (interfaceManager.isItmDirectTunnelsEnabled()) {
+                        DpnTepInterfaceInfo interfaceInfo =
+                                dpnTepStateCache.getDpnTepInterface(srcDpn, teps.getDPNID());
+                        if (interfaceInfo != null) {
+                            resultBld = RpcResultBuilder.success();
+                            resultBld.withResult(new GetInternalOrExternalInterfaceNameOutputBuilder()
+                                    .setInterfaceName(interfaceInfo.getTunnelName())).build();
+                            return Futures.immediateFuture(resultBld.build());
+                        }
+                    }
+
                     if (ItmUtils.isTunnelAggregationUsed(input.getTunnelType())) {
                         optTunnel = ItmUtils.getInternalTunnelFromDS(srcDpn, teps.getDPNID(),
                                                                      TunnelTypeLogicalGroup.class, dataBroker);
@@ -592,8 +696,8 @@ public class ItmManagerRpcService implements ItmRpcService {
 
     @SuppressWarnings("checkstyle:IllegalCatch")
     @Override
-    public Future<RpcResult<java.lang.Void>> deleteL2GwDevice(DeleteL2GwDeviceInput input) {
-        final SettableFuture<RpcResult<Void>> result = SettableFuture.create();
+    public ListenableFuture<RpcResult<DeleteL2GwDeviceOutput>> deleteL2GwDevice(DeleteL2GwDeviceInput input) {
+        final SettableFuture<RpcResult<DeleteL2GwDeviceOutput>> result = SettableFuture.create();
         boolean foundVxlanTzone = false;
         try {
             final IpAddress hwIp = input.getIpAddress();
@@ -605,63 +709,57 @@ public class ItmManagerRpcService implements ItmRpcService {
                 TransportZones transportZones = transportZonesOptional.get();
                 if (transportZones.getTransportZone() == null || transportZones.getTransportZone().isEmpty()) {
                     LOG.error("No teps configured");
-                    result.set(RpcResultBuilder.<Void>failed()
+                    result.set(RpcResultBuilder.<DeleteL2GwDeviceOutput>failed()
                             .withError(RpcError.ErrorType.APPLICATION, "No teps Configured").build());
                     return result;
                 }
                 for (TransportZone tzone : transportZones.getTransportZone()) {
-                    if (!tzone.getTunnelType().equals(TunnelTypeVxlan.class)) {
+                    if (!TunnelTypeVxlan.class.equals(tzone.getTunnelType())) {
                         continue;
                     }
                     foundVxlanTzone = true;
                     String transportZone = tzone.getZoneName();
                     if (tzone.getSubnets() == null || tzone.getSubnets().isEmpty()) {
-                        result.set(RpcResultBuilder.<Void>failed()
+                        result.set(RpcResultBuilder.<DeleteL2GwDeviceOutput>failed()
                                 .withError(RpcError.ErrorType.APPLICATION, "No subnets Configured").build());
                         return result;
                     }
-                    SubnetsKey subnetsKey = tzone.getSubnets().get(0).getKey();
+                    SubnetsKey subnetsKey = tzone.getSubnets().get(0).key();
                     DeviceVtepsKey deviceVtepKey = new DeviceVtepsKey(hwIp, nodeId);
                     InstanceIdentifier<DeviceVteps> path = InstanceIdentifier.builder(TransportZones.class)
                             .child(TransportZone.class, new TransportZoneKey(transportZone))
                             .child(Subnets.class, subnetsKey).child(DeviceVteps.class, deviceVtepKey)
                             .build();
-                    WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
-                    //TO DO: add retry if it fails
-
-                    transaction.delete(LogicalDatastoreType.CONFIGURATION, path);
-
-                    ListenableFuture<Void> futureCheck = transaction.submit();
-                    Futures.addCallback(futureCheck, new FutureCallback<Void>() {
-
+                    FluentFuture<Void> future =
+                        retryingTxRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> tx.delete(path));
+                    future.addCallback(new FutureCallback<Void>() {
                         @Override public void onSuccess(Void voidInstance) {
-                            result.set(RpcResultBuilder.<Void>success().build());
+                            result.set(RpcResultBuilder.<DeleteL2GwDeviceOutput>success().build());
                         }
 
                         @Override public void onFailure(Throwable error) {
                             String msg = String.format("Unable to delete HwVtep %s from datastore", nodeId);
                             LOG.error("Unable to delete HwVtep {}, {} from datastore", nodeId, hwIp);
-                            result.set(RpcResultBuilder.<Void>failed()
+                            result.set(RpcResultBuilder.<DeleteL2GwDeviceOutput>failed()
                                     .withError(RpcError.ErrorType.APPLICATION, msg, error).build());
                         }
-                    });
-
+                    }, MoreExecutors.directExecutor());
                 }
             } else {
-                result.set(RpcResultBuilder.<Void>failed()
+                result.set(RpcResultBuilder.<DeleteL2GwDeviceOutput>failed()
                         .withError(RpcError.ErrorType.APPLICATION, "No TransportZones configured").build());
                 return result;
             }
 
             if (!foundVxlanTzone) {
-                result.set(RpcResultBuilder.<Void>failed()
+                result.set(RpcResultBuilder.<DeleteL2GwDeviceOutput>failed()
                         .withError(RpcError.ErrorType.APPLICATION, "No VxLan TransportZones configured")
                         .build());
             }
 
             return result;
         } catch (Exception e) {
-            RpcResultBuilder<java.lang.Void> resultBuilder = RpcResultBuilder.<Void>failed()
+            RpcResultBuilder<DeleteL2GwDeviceOutput> resultBuilder = RpcResultBuilder.<DeleteL2GwDeviceOutput>failed()
                     .withError(RpcError.ErrorType.APPLICATION, "Deleting l2 Gateway to DS Failed", e);
             return Futures.immediateFuture(resultBuilder.build());
         }
@@ -669,9 +767,9 @@ public class ItmManagerRpcService implements ItmRpcService {
 
     @SuppressWarnings("checkstyle:IllegalCatch")
     @Override
-    public Future<RpcResult<java.lang.Void>> addL2GwDevice(AddL2GwDeviceInput input) {
+    public ListenableFuture<RpcResult<AddL2GwDeviceOutput>> addL2GwDevice(AddL2GwDeviceInput input) {
 
-        final SettableFuture<RpcResult<Void>> result = SettableFuture.create();
+        final SettableFuture<RpcResult<AddL2GwDeviceOutput>> result = SettableFuture.create();
         boolean foundVxlanTzone = false;
         try {
             final IpAddress hwIp = input.getIpAddress();
@@ -685,12 +783,12 @@ public class ItmManagerRpcService implements ItmRpcService {
                 TransportZones transportZones = transportZonesOptional.get();
                 if (transportZones.getTransportZone() == null || transportZones.getTransportZone().isEmpty()) {
                     LOG.error("No transportZone configured");
-                    result.set(RpcResultBuilder.<Void>failed()
+                    result.set(RpcResultBuilder.<AddL2GwDeviceOutput>failed()
                             .withError(RpcError.ErrorType.APPLICATION, "No transportZone Configured").build());
                     return result;
                 }
                 for (TransportZone tzone : transportZones.getTransportZone()) {
-                    if (!tzone.getTunnelType().equals(TunnelTypeVxlan.class)) {
+                    if (!TunnelTypeVxlan.class.equals(tzone.getTunnelType())) {
                         continue;
                     }
                     String transportZone = tzone.getZoneName();
@@ -698,59 +796,64 @@ public class ItmManagerRpcService implements ItmRpcService {
                         continue;
                     }
                     foundVxlanTzone = true;
-                    SubnetsKey subnetsKey = tzone.getSubnets().get(0).getKey();
+                    SubnetsKey subnetsKey = tzone.getSubnets().get(0).key();
                     DeviceVtepsKey deviceVtepKey = new DeviceVtepsKey(hwIp, nodeId);
                     InstanceIdentifier<DeviceVteps> path = InstanceIdentifier.builder(TransportZones.class)
                             .child(TransportZone.class, new TransportZoneKey(transportZone))
                             .child(Subnets.class, subnetsKey).child(DeviceVteps.class, deviceVtepKey)
                             .build();
-                    DeviceVteps deviceVtep = new DeviceVtepsBuilder().setKey(deviceVtepKey).setIpAddress(hwIp)
+                    DeviceVteps deviceVtep = new DeviceVtepsBuilder().withKey(deviceVtepKey).setIpAddress(hwIp)
                             .setNodeId(nodeId).setTopologyId(input.getTopologyId()).build();
-                    WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
                     //TO DO: add retry if it fails
-                    transaction.put(LogicalDatastoreType.CONFIGURATION, path, deviceVtep, true);
+                    FluentFuture<Void> future = retryingTxRunner
+                        .callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> tx.put(path, deviceVtep, true));
 
-                    ListenableFuture<Void> futureCheck = transaction.submit();
-                    Futures.addCallback(futureCheck, new FutureCallback<Void>() {
+                    future.addCallback(new FutureCallback<Void>() {
 
                         @Override public void onSuccess(Void voidInstance) {
-                            result.set(RpcResultBuilder.<Void>success().build());
+                            result.set(RpcResultBuilder.<AddL2GwDeviceOutput>success().build());
                         }
 
                         @Override public void onFailure(Throwable error) {
                             String msg = String.format("Unable to write HwVtep %s to datastore", nodeId);
                             LOG.error("Unable to write HwVtep {}, {} to datastore", nodeId, hwIp);
-                            result.set(RpcResultBuilder.<Void>failed()
+                            result.set(RpcResultBuilder.<AddL2GwDeviceOutput>failed()
                                     .withError(RpcError.ErrorType.APPLICATION, msg, error).build());
                         }
-                    });
+                    }, MoreExecutors.directExecutor());
 
                 }
             } else {
-                result.set(RpcResultBuilder.<Void>failed()
+                result.set(RpcResultBuilder.<AddL2GwDeviceOutput>failed()
                         .withError(RpcError.ErrorType.APPLICATION, "No TransportZones configured").build());
                 return result;
             }
 
             if (!foundVxlanTzone) {
-                result.set(RpcResultBuilder.<Void>failed()
+                result.set(RpcResultBuilder.<AddL2GwDeviceOutput>failed()
                         .withError(RpcError.ErrorType.APPLICATION, "No VxLan TransportZones configured")
                         .build());
             }
 
             return result;
         } catch (Exception e) {
-            RpcResultBuilder<java.lang.Void> resultBuilder = RpcResultBuilder.<Void>failed()
+            RpcResultBuilder<AddL2GwDeviceOutput> resultBuilder = RpcResultBuilder.<AddL2GwDeviceOutput>failed()
                     .withError(RpcError.ErrorType.APPLICATION, "Adding l2 Gateway to DS Failed", e);
             return Futures.immediateFuture(resultBuilder.build());
         }
     }
 
+    @Override
+    public ListenableFuture<RpcResult<GetWatchPortForTunnelOutput>> getWatchPortForTunnel(
+            GetWatchPortForTunnelInput input) {
+        throw new UnsupportedOperationException("TODO");
+    }
+
     @SuppressWarnings("checkstyle:IllegalCatch")
     @Override
-    public Future<RpcResult<java.lang.Void>> addL2GwMlagDevice(AddL2GwMlagDeviceInput input) {
+    public ListenableFuture<RpcResult<AddL2GwMlagDeviceOutput>> addL2GwMlagDevice(AddL2GwMlagDeviceInput input) {
 
-        final SettableFuture<RpcResult<Void>> result = SettableFuture.create();
+        final SettableFuture<RpcResult<AddL2GwMlagDeviceOutput>> result = SettableFuture.create();
         try {
             final IpAddress hwIp = input.getIpAddress();
             final List<String> nodeId = input.getNodeId();
@@ -761,63 +864,63 @@ public class ItmManagerRpcService implements ItmRpcService {
                 TransportZones transportZones = transportZonesOptional.get();
                 if (transportZones.getTransportZone() == null || transportZones.getTransportZone().isEmpty()) {
                     LOG.error("No teps configured");
-                    result.set(RpcResultBuilder.<Void>failed()
+                    result.set(RpcResultBuilder.<AddL2GwMlagDeviceOutput>failed()
                             .withError(RpcError.ErrorType.APPLICATION, "No teps Configured").build());
                     return result;
                 }
                 String transportZone = transportZones.getTransportZone().get(0).getZoneName();
                 if (transportZones.getTransportZone().get(0).getSubnets() == null
                         || transportZones.getTransportZone().get(0).getSubnets().isEmpty()) {
-                    result.set(RpcResultBuilder.<Void>failed()
+                    result.set(RpcResultBuilder.<AddL2GwMlagDeviceOutput>failed()
                             .withError(RpcError.ErrorType.APPLICATION, "No subnets Configured").build());
                     return result;
                 }
-                SubnetsKey subnetsKey = transportZones.getTransportZone().get(0).getSubnets().get(0).getKey();
+                SubnetsKey subnetsKey = transportZones.getTransportZone().get(0).getSubnets().get(0).key();
                 DeviceVtepsKey deviceVtepKey = new DeviceVtepsKey(hwIp, nodeId.get(0));
                 InstanceIdentifier<DeviceVteps> path =
                         InstanceIdentifier.builder(TransportZones.class)
                                 .child(TransportZone.class, new TransportZoneKey(transportZone))
                                 .child(Subnets.class, subnetsKey).child(DeviceVteps.class, deviceVtepKey).build();
-                DeviceVteps deviceVtep = new DeviceVtepsBuilder().setKey(deviceVtepKey).setIpAddress(hwIp)
+                DeviceVteps deviceVtep = new DeviceVtepsBuilder().withKey(deviceVtepKey).setIpAddress(hwIp)
                         .setNodeId(nodeId.get(0)).setTopologyId(input.getTopologyId()).build();
-                WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
-                //TO DO: add retry if it fails
-                LOG.trace("writing hWvtep{}",deviceVtep);
-                writeTransaction.put(LogicalDatastoreType.CONFIGURATION, path, deviceVtep, true);
-
-                if (nodeId.size() == 2) {
-                    LOG.trace("second node-id {}",nodeId.get(1));
-                    DeviceVtepsKey deviceVtepKey2 = new DeviceVtepsKey(hwIp, nodeId.get(1));
-                    InstanceIdentifier<DeviceVteps> path2 = InstanceIdentifier.builder(TransportZones.class)
-                            .child(TransportZone.class, new TransportZoneKey(transportZone))
-                            .child(Subnets.class, subnetsKey).child(DeviceVteps.class, deviceVtepKey2).build();
-                    DeviceVteps deviceVtep2 = new DeviceVtepsBuilder().setKey(deviceVtepKey2).setIpAddress(hwIp)
-                            .setNodeId(nodeId.get(1))
-                            .setTopologyId(input.getTopologyId()).build();
-                    //TO DO: add retry if it fails
-                    LOG.trace("writing {}",deviceVtep2);
-                    writeTransaction.put(LogicalDatastoreType.CONFIGURATION, path2, deviceVtep2, true);
-                }
-                ListenableFuture<Void> futureCheck = writeTransaction.submit();
-                Futures.addCallback(futureCheck, new FutureCallback<Void>() {
-
+                LOG.trace("writing hWvtep{}", deviceVtep);
+                FluentFuture<Void> future =
+                    retryingTxRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
+                        tx -> {
+                            tx.put(path, deviceVtep, true);
+                            if (nodeId.size() == 2) {
+                                LOG.trace("second node-id {}", nodeId.get(1));
+                                DeviceVtepsKey deviceVtepKey2 = new DeviceVtepsKey(hwIp, nodeId.get(1));
+                                InstanceIdentifier<DeviceVteps> path2 = InstanceIdentifier.builder(TransportZones.class)
+                                        .child(TransportZone.class, new TransportZoneKey(transportZone))
+                                        .child(Subnets.class, subnetsKey)
+                                        .child(DeviceVteps.class, deviceVtepKey2).build();
+                                DeviceVteps deviceVtep2 = new DeviceVtepsBuilder().withKey(deviceVtepKey2)
+                                        .setIpAddress(hwIp).setNodeId(nodeId.get(1))
+                                        .setTopologyId(input.getTopologyId()).build();
+                                LOG.trace("writing {}", deviceVtep2);
+                                tx.put(path2, deviceVtep2, true);
+                            }
+                        });
+                future.addCallback(new FutureCallback<Void>() {
                     @Override
                     public void onSuccess(Void voidInstance) {
-                        result.set(RpcResultBuilder.<Void>success().build());
+                        result.set(RpcResultBuilder.<AddL2GwMlagDeviceOutput>success().build());
                     }
 
                     @Override
                     public void onFailure(Throwable error) {
                         String msg = String.format("Unable to write HwVtep %s to datastore", nodeId);
                         LOG.error("Unable to write HwVtep {}, {} to datastore", nodeId , hwIp);
-                        result.set(RpcResultBuilder.<Void>failed().withError(RpcError.ErrorType.APPLICATION, msg, error)
+                        result.set(RpcResultBuilder.<AddL2GwMlagDeviceOutput>failed()
+                                .withError(RpcError.ErrorType.APPLICATION, msg, error)
                                 .build());
                     }
                 }, MoreExecutors.directExecutor());
             }
             return result;
         } catch (RuntimeException e) {
-            RpcResultBuilder<java.lang.Void> resultBuilder = RpcResultBuilder.<Void>failed()
+            RpcResultBuilder<AddL2GwMlagDeviceOutput> resultBuilder = RpcResultBuilder.<AddL2GwMlagDeviceOutput>failed()
                     .withError(RpcError.ErrorType.APPLICATION, "Adding l2 Gateway to DS Failed", e);
             return Futures.immediateFuture(resultBuilder.build());
         }
@@ -825,9 +928,9 @@ public class ItmManagerRpcService implements ItmRpcService {
 
     @SuppressWarnings("checkstyle:IllegalCatch")
     @Override
-    public Future<RpcResult<Void>> deleteL2GwMlagDevice(DeleteL2GwMlagDeviceInput input) {
-
-        final SettableFuture<RpcResult<Void>> result = SettableFuture.create();
+    public ListenableFuture<RpcResult<DeleteL2GwMlagDeviceOutput>> deleteL2GwMlagDevice(
+            DeleteL2GwMlagDeviceInput input) {
+        final SettableFuture<RpcResult<DeleteL2GwMlagDeviceOutput>> result = SettableFuture.create();
         try {
             final IpAddress hwIp = input.getIpAddress();
             final List<String> nodeId = input.getNodeId();
@@ -838,64 +941,67 @@ public class ItmManagerRpcService implements ItmRpcService {
                 TransportZones tzones = transportZonesOptional.get();
                 if (tzones.getTransportZone() == null || tzones.getTransportZone().isEmpty()) {
                     LOG.error("No teps configured");
-                    result.set(RpcResultBuilder.<Void>failed()
+                    result.set(RpcResultBuilder.<DeleteL2GwMlagDeviceOutput>failed()
                             .withError(RpcError.ErrorType.APPLICATION, "No teps Configured").build());
                     return result;
                 }
                 String transportZone = tzones.getTransportZone().get(0).getZoneName();
                 if (tzones.getTransportZone().get(0).getSubnets() == null || tzones.getTransportZone()
                         .get(0).getSubnets().isEmpty()) {
-                    result.set(RpcResultBuilder.<Void>failed()
+                    result.set(RpcResultBuilder.<DeleteL2GwMlagDeviceOutput>failed()
                             .withError(RpcError.ErrorType.APPLICATION, "No subnets Configured").build());
                     return result;
                 }
-                SubnetsKey subnetsKey = tzones.getTransportZone().get(0).getSubnets().get(0).getKey();
-                DeviceVtepsKey deviceVtepKey = new DeviceVtepsKey(hwIp, nodeId.get(0));
-                InstanceIdentifier<DeviceVteps> path =
-                        InstanceIdentifier.builder(TransportZones.class)
-                                .child(TransportZone.class, new TransportZoneKey(transportZone))
-                                .child(Subnets.class, subnetsKey).child(DeviceVteps.class,
-                                deviceVtepKey).build();
-                WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
-                //TO DO: add retry if it fails
-                transaction.delete(LogicalDatastoreType.CONFIGURATION, path);
-
-                DeviceVtepsKey deviceVtepKey2 = new DeviceVtepsKey(hwIp, nodeId.get(1));
-                InstanceIdentifier<DeviceVteps> path2 =
-                        InstanceIdentifier.builder(TransportZones.class)
-                                .child(TransportZone.class, new TransportZoneKey(transportZone))
-                                .child(Subnets.class, subnetsKey).child(DeviceVteps.class,
-                                deviceVtepKey2).build();
-                //TO DO: add retry if it fails
-                transaction.delete(LogicalDatastoreType.CONFIGURATION, path2);
+                SubnetsKey subnetsKey = tzones.getTransportZone().get(0).getSubnets().get(0).key();
+
+                FluentFuture<Void> future =
+                    retryingTxRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
+                        tx -> {
+                            DeviceVtepsKey deviceVtepKey = new DeviceVtepsKey(hwIp, nodeId.get(0));
+                            InstanceIdentifier<DeviceVteps> path =
+                                    InstanceIdentifier.builder(TransportZones.class)
+                                            .child(TransportZone.class, new TransportZoneKey(transportZone))
+                                            .child(Subnets.class, subnetsKey).child(DeviceVteps.class,
+                                            deviceVtepKey).build();
+                            tx.delete(path);
+                            DeviceVtepsKey deviceVtepKey2 = new DeviceVtepsKey(hwIp, nodeId.get(1));
+                            InstanceIdentifier<DeviceVteps> path2 =
+                                    InstanceIdentifier.builder(TransportZones.class)
+                                            .child(TransportZone.class, new TransportZoneKey(transportZone))
+                                            .child(Subnets.class, subnetsKey).child(DeviceVteps.class,
+                                            deviceVtepKey2).build();
+                            tx.delete(path2);
+                        }
+                    );
 
-                ListenableFuture<Void> futureCheck = transaction.submit();
-                Futures.addCallback(futureCheck, new FutureCallback<Void>() {
+                future.addCallback(new FutureCallback<Void>() {
 
                     @Override
                     public void onSuccess(Void voidInstance) {
-                        result.set(RpcResultBuilder.<Void>success().build());
+                        result.set(RpcResultBuilder.<DeleteL2GwMlagDeviceOutput>success().build());
                     }
 
                     @Override
                     public void onFailure(Throwable error) {
                         String msg = String.format("Unable to write HwVtep %s to datastore", nodeId);
                         LOG.error("Unable to write HwVtep {}, {} to datastore", nodeId , hwIp);
-                        result.set(RpcResultBuilder.<Void>failed().withError(RpcError.ErrorType.APPLICATION, msg, error)
+                        result.set(RpcResultBuilder.<DeleteL2GwMlagDeviceOutput>failed()
+                                .withError(RpcError.ErrorType.APPLICATION, msg, error)
                                 .build());
                     }
-                });
+                }, MoreExecutors.directExecutor());
             }
             return result;
         } catch (Exception e) {
-            RpcResultBuilder<java.lang.Void> resultBuilder = RpcResultBuilder.<Void>failed()
-                    .withError(RpcError.ErrorType.APPLICATION, "Deleting l2 Gateway to DS Failed", e);
+            RpcResultBuilder<DeleteL2GwMlagDeviceOutput> resultBuilder =
+                    RpcResultBuilder.<DeleteL2GwMlagDeviceOutput>failed().withError(RpcError.ErrorType.APPLICATION,
+                            "Deleting l2 Gateway to DS Failed", e);
             return Futures.immediateFuture(resultBuilder.build());
         }
     }
 
     @Override
-    public Future<RpcResult<IsTunnelInternalOrExternalOutput>> isTunnelInternalOrExternal(
+    public ListenableFuture<RpcResult<IsTunnelInternalOrExternalOutput>> isTunnelInternalOrExternal(
             IsTunnelInternalOrExternalInput input) {
         RpcResultBuilder<IsTunnelInternalOrExternalOutput> resultBld;
         String tunIfName = input.getTunnelInterfaceName();
@@ -915,15 +1021,18 @@ public class ItmManagerRpcService implements ItmRpcService {
     }
 
     @Override
-    public Future<RpcResult<IsDcgwPresentOutput>> isDcgwPresent(IsDcgwPresentInput input) {
+    public ListenableFuture<RpcResult<IsDcgwPresentOutput>> isDcgwPresent(IsDcgwPresentInput input) {
         RpcResultBuilder<IsDcgwPresentOutput> resultBld = RpcResultBuilder.success();
 
-        List<DcGatewayIp> dcGatewayIpList = ItmUtils.getDcGatewayIpList(dataBroker);
+        List<DcGatewayIp> dcGatewayIpList = new ArrayList<>();
+        txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
+            tx -> dcGatewayIpList.addAll(getDcGatewayIpList(tx))).isDone();
+
         String dcgwIpStr = input.getDcgwIp();
         IpAddress dcgwIpAddr = IpAddressBuilder.getDefaultInstance(dcgwIpStr);
         long retVal;
 
-        if (dcGatewayIpList != null && !dcGatewayIpList.isEmpty()
+        if (!dcGatewayIpList.isEmpty()
                 && dcGatewayIpList.stream().anyMatch(gwIp -> Objects.equal(gwIp.getIpAddress(), dcgwIpAddr))) {
             //Match found
             retVal = 1;
@@ -939,7 +1048,7 @@ public class ItmManagerRpcService implements ItmRpcService {
     }
 
     @Override
-    public Future<RpcResult<GetDpnEndpointIpsOutput>> getDpnEndpointIps(GetDpnEndpointIpsInput input) {
+    public ListenableFuture<RpcResult<GetDpnEndpointIpsOutput>> getDpnEndpointIps(GetDpnEndpointIpsInput input) {
         BigInteger srcDpn = input.getSourceDpid() ;
         RpcResultBuilder<GetDpnEndpointIpsOutput> resultBld = failed();
         InstanceIdentifier<DPNTEPsInfo> tunnelInfoId =
@@ -967,7 +1076,7 @@ public class ItmManagerRpcService implements ItmRpcService {
     }
 
     @Override
-    public Future<RpcResult<GetDpnInfoOutput>> getDpnInfo(GetDpnInfoInput input) {
+    public ListenableFuture<RpcResult<GetDpnInfoOutput>> getDpnInfo(GetDpnInfoInput input) {
         return FutureRpcResults.fromListenableFuture(LOG, "getDpnInfo", input,
             () -> Futures.immediateFuture(getDpnInfoInternal(input))).build();
     }
@@ -1033,7 +1142,7 @@ public class ItmManagerRpcService implements ItmRpcService {
         }
         Map<String, BigInteger> result = new HashMap<>();
         for (Node node : operInventoryNodes.getNode()) {
-            String name = node.getAugmentation(FlowCapableNode.class).getDescription();
+            String name = node.augmentation(FlowCapableNode.class).getDescription();
             if (nodeNames.contains(name)) {
                 String[] nodeId = node.getId().getValue().split(":");
                 result.put(name, new BigInteger(nodeId[1]));
@@ -1059,45 +1168,69 @@ public class ItmManagerRpcService implements ItmRpcService {
                         .network.topology.topology.Node.class).getNodeId().getValue();
     }
 
-    private ListenableFuture<GetEgressActionsForTunnelOutput> getEgressActionsForInterface(String interfaceName,
-           long tunnelKey, Integer actionKey) throws ReadFailedException {
-        int actionKeyStart = actionKey == null ? 0 : actionKey;
+    private ListenableFuture<GetEgressActionsForTunnelOutput>
+        getEgressActionsForInternalTunnels(String interfaceName, Long tunnelKey, Integer actionKey)
+            throws ExecutionException, InterruptedException, OperationFailedException {
+
         DpnTepInterfaceInfo interfaceInfo = dpnTepStateCache.getTunnelFromCache(interfaceName);
         if (interfaceInfo == null) {
             throw new IllegalStateException("Interface information not present in config DS for" + interfaceName);
         }
-        Optional<StateTunnelList> ifState = tunnelStateCache
-                .get(tunnelStateCache.getStateTunnelListIdentifier(interfaceName));
-        if (ifState.isPresent()) {
-            String tunnelType = ItmUtils.convertTunnelTypetoString(interfaceInfo.getTunnelType());
-            List<Action> actions = getEgressActionInfosForInterface(tunnelType, ifState.get().getPortNumber(),
-                    tunnelKey, actionKeyStart).stream().map(ActionInfo::buildAction).collect(Collectors.toList());
-            return Futures.immediateFuture(new GetEgressActionsForTunnelOutputBuilder().setAction(actions).build());
+
+        String tunnelType = ItmUtils.convertTunnelTypetoString(interfaceInfo.getTunnelType());
+        if (!tunnelType.equalsIgnoreCase(ITMConstants.TUNNEL_TYPE_VXLAN)) {
+            throw new IllegalArgumentException(tunnelType + " tunnel not handled by ITM");
         }
-        throw new IllegalStateException("Interface information not present in oper DS for" + interfaceName);
-    }
 
-    private static List<ActionInfo> getEgressActionInfosForInterface(String tunnelType, String portNo, Long tunnelKey,
-                                                                     int actionKeyStart) {
-        List<ActionInfo> result = new ArrayList<>();
-        switch (tunnelType) {
-            case ITMConstants.TUNNEL_TYPE_GRE:
-            case ITMConstants.TUNNEL_TYPE_MPLSoGRE:
-                // Invoke IFM RPC and pass it on to the caller.
-                LOG.warn("Interface Type {} not handled by ITM", tunnelType);
-                break;
-            case ITMConstants.TUNNEL_TYPE_VXLAN:
-                //TODO tunnel_id to encode GRE key, once it is supported
-                // Until then, tunnel_id should be "cleaned", otherwise it stores the value coming from a VXLAN tunnel
-                result.add(new ActionSetFieldTunnelId(actionKeyStart++,
-                        BigInteger.valueOf(tunnelKey != null ? tunnelKey : 0L)));
-                result.add(new ActionOutput(actionKeyStart, new Uri(portNo)));
-                break;
-
-            default:
-                LOG.warn("Interface Type {} not handled yet", tunnelType);
-                break;
+        Optional<DPNTEPsInfo> dpntePsInfoOptional = dpnTEPsInfoCache.get(InstanceIdentifier.builder(DpnEndpoints.class)
+                .child(DPNTEPsInfo.class, new DPNTEPsInfoKey(new BigInteger(dpnTepStateCache
+                        .getTunnelEndPointInfoFromCache(interfaceInfo.getTunnelName()).getDstEndPointInfo()))).build());
+        Integer dstId;
+        if (dpntePsInfoOptional.isPresent()) {
+            dstId = dpntePsInfoOptional.get().getDstId();
+        } else {
+            dstId = directTunnelUtils.allocateId(ITMConstants.ITM_IDPOOL_NAME, interfaceInfo.getRemoteDPN().toString());
         }
-        return result;
+
+        List<ActionInfo> result = new ArrayList<>();
+        long regValue = MetaDataUtil.getRemoteDpnMetadatForEgressTunnelTable(dstId);
+        int actionKeyStart = actionKey == null ? 0 : actionKey;
+        result.add(new ActionSetFieldTunnelId(actionKeyStart++,
+                BigInteger.valueOf(tunnelKey != null ? tunnelKey : 0L)));
+        result.add(new ActionRegLoad(actionKeyStart++, NxmNxReg6.class, MetaDataUtil.REG6_START_INDEX,
+                MetaDataUtil.REG6_END_INDEX, regValue));
+        result.add(new ActionNxResubmit(actionKeyStart, NwConstants.EGRESS_TUNNEL_TABLE));
+
+        return Futures.immediateFuture(new GetEgressActionsForTunnelOutputBuilder()
+                .setAction(result.stream().map(ActionInfo::buildAction).collect(Collectors.toList())).build());
+    }
+
+    public static List<DcGatewayIp> getDcGatewayIpList(TypedReadWriteTransaction<Datastore.Configuration> tx)
+            throws ExecutionException, InterruptedException {
+        List<DcGatewayIp> dcGatewayIpList = new ArrayList<>();
+        FluentFuture<Optional<DcGatewayIpList>> future =
+                tx.read(InstanceIdentifier.builder(DcGatewayIpList.class).build());
+        future.addCallback(new FutureCallback<Optional<DcGatewayIpList>>() {
+            @Override
+            public void onSuccess(@NonNull  Optional<DcGatewayIpList> optional) {
+                try {
+                    Optional<DcGatewayIpList> opt = future.get();
+                    if (opt.isPresent()) {
+                        DcGatewayIpList list = opt.get();
+                        if (list != null) {
+                            dcGatewayIpList.addAll(list.getDcGatewayIp());
+                        }
+                    }
+                } catch (ExecutionException | InterruptedException e) {
+                    LOG.error("DcGateway IpList read failed", e);
+                }
+            }
+
+            @Override
+            public void onFailure(Throwable error) {
+                LOG.error("DcGateway IpList read failed", error);
+            }
+        }, MoreExecutors.directExecutor());
+        return dcGatewayIpList;
     }
 }