Provide API support for External tunnels
[genius.git] / itm / itm-impl / src / main / java / org / opendaylight / genius / itm / rpc / ItmManagerRpcService.java
1 /*
2  * Copyright (c) 2016, 2017 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.genius.itm.rpc;
9
10 import static org.opendaylight.mdsal.binding.util.Datastore.CONFIGURATION;
11 import static org.opendaylight.serviceutils.tools.rpc.FutureRpcResults.fromListenableFuture;
12 import static org.opendaylight.yangtools.yang.common.RpcResultBuilder.failed;
13
14 import com.google.common.base.Objects;
15 import com.google.common.util.concurrent.FluentFuture;
16 import com.google.common.util.concurrent.FutureCallback;
17 import com.google.common.util.concurrent.Futures;
18 import com.google.common.util.concurrent.ListenableFuture;
19 import com.google.common.util.concurrent.MoreExecutors;
20 import com.google.common.util.concurrent.SettableFuture;
21 import java.math.BigInteger;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.Collections;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Optional;
29 import java.util.concurrent.ExecutionException;
30 import java.util.stream.Collectors;
31 import javax.annotation.PostConstruct;
32 import javax.annotation.PreDestroy;
33 import javax.inject.Inject;
34 import javax.inject.Singleton;
35 import org.eclipse.jdt.annotation.NonNull;
36 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
37 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
38 import org.opendaylight.genius.interfacemanager.interfaces.InterfaceManagerService;
39 import org.opendaylight.genius.itm.cache.DPNTEPsInfoCache;
40 import org.opendaylight.genius.itm.cache.DpnTepStateCache;
41 import org.opendaylight.genius.itm.cache.OfDpnTepConfigCache;
42 import org.opendaylight.genius.itm.cache.OfTepStateCache;
43 import org.opendaylight.genius.itm.cache.OvsBridgeRefEntryCache;
44 import org.opendaylight.genius.itm.cache.TunnelStateCache;
45 import org.opendaylight.genius.itm.confighelpers.ItmExternalTunnelAddWorker;
46 import org.opendaylight.genius.itm.confighelpers.ItmExternalTunnelDeleteWorker;
47 import org.opendaylight.genius.itm.globals.ITMConstants;
48 import org.opendaylight.genius.itm.impl.ItmUtils;
49 import org.opendaylight.genius.itm.itmdirecttunnels.renderer.ovs.utilities.DirectTunnelUtils;
50 import org.opendaylight.genius.itm.utils.DpnTepInterfaceInfo;
51 import org.opendaylight.genius.mdsalutil.ActionInfo;
52 import org.opendaylight.genius.mdsalutil.MDSALUtil;
53 import org.opendaylight.genius.mdsalutil.MatchInfo;
54 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
55 import org.opendaylight.genius.mdsalutil.NwConstants;
56 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
57 import org.opendaylight.genius.mdsalutil.actions.ActionRegLoad;
58 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
59 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
60 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
61 import org.opendaylight.mdsal.binding.api.DataBroker;
62 import org.opendaylight.mdsal.binding.util.Datastore;
63 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunner;
64 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunnerImpl;
65 import org.opendaylight.mdsal.binding.util.RetryingManagedNewTransactionRunner;
66 import org.opendaylight.mdsal.binding.util.TypedReadWriteTransaction;
67 import org.opendaylight.mdsal.binding.util.TypedWriteTransaction;
68 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
69 import org.opendaylight.mdsal.common.api.ReadFailedException;
70 import org.opendaylight.serviceutils.tools.rpc.FutureRpcResults;
71 import org.opendaylight.serviceutils.tools.rpc.FutureRpcResults.LogLevel;
72 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
73 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressBuilder;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.BridgeRefInfo;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntry;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntryKey;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeLogicalGroup;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.config.rev160406.ItmConfig;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.ovs.bridge.ref.info.OvsBridgeRefEntry;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.DpnEndpoints;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.DpnTepsState;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.ExternalTunnelList;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.DPNTEPsInfo;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.DPNTEPsInfoKey;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.dpn.teps.info.TunnelEndPoints;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.tep.config.OfDpnTep;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.teps.state.DpnsTeps;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.teps.state.DpnsTepsKey;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.teps.state.dpns.teps.RemoteDpns;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.teps.state.dpns.teps.RemoteDpnsBuilder;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.teps.state.dpns.teps.RemoteDpnsKey;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnel;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnelKey;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.of.teps.state.OfTep;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnel.list.InternalTunnel;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.DcGatewayIpList;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.TransportZones;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.dc.gateway.ip.list.DcGatewayIp;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.dc.gateway.ip.list.DcGatewayIpBuilder;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.dc.gateway.ip.list.DcGatewayIpKey;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.TransportZone;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.TransportZoneKey;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.DeviceVteps;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.DeviceVtepsBuilder;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.DeviceVtepsKey;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.Vteps;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.AddExternalTunnelEndpointInput;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.AddExternalTunnelEndpointOutput;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.AddL2GwDeviceInput;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.AddL2GwDeviceOutput;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.AddL2GwMlagDeviceInput;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.AddL2GwMlagDeviceOutput;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.BuildExternalTunnelFromDpnsInput;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.BuildExternalTunnelFromDpnsOutput;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.CreateTerminatingServiceActionsInput;
119 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.CreateTerminatingServiceActionsOutput;
120 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.DeleteL2GwDeviceInput;
121 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.DeleteL2GwDeviceOutput;
122 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.DeleteL2GwMlagDeviceInput;
123 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.DeleteL2GwMlagDeviceOutput;
124 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetDpnEndpointIpsInput;
125 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetDpnEndpointIpsOutput;
126 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetDpnEndpointIpsOutputBuilder;
127 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetDpnInfoInput;
128 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetDpnInfoOutput;
129 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetDpnInfoOutputBuilder;
130 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetEgressActionsForTunnelInput;
131 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetEgressActionsForTunnelOutput;
132 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetEgressActionsForTunnelOutputBuilder;
133 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetExternalTunnelInterfaceNameInput;
134 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetExternalTunnelInterfaceNameOutput;
135 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetExternalTunnelInterfaceNameOutputBuilder;
136 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetInternalOrExternalInterfaceNameInput;
137 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetInternalOrExternalInterfaceNameOutput;
138 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetInternalOrExternalInterfaceNameOutputBuilder;
139 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTepIpInput;
140 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTepIpOutput;
141 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTepIpOutputBuilder;
142 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInput;
143 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameOutput;
144 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameOutputBuilder;
145 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelTypeInput;
146 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelTypeOutput;
147 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelTypeOutputBuilder;
148 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetWatchPortForTunnelInput;
149 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetWatchPortForTunnelOutput;
150 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.IsDcgwPresentInput;
151 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.IsDcgwPresentOutput;
152 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.IsDcgwPresentOutputBuilder;
153 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.IsTunnelInternalOrExternalInput;
154 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.IsTunnelInternalOrExternalOutput;
155 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.IsTunnelInternalOrExternalOutputBuilder;
156 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
157 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveExternalTunnelEndpointInput;
158 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveExternalTunnelEndpointOutput;
159 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveExternalTunnelFromDpnsInput;
160 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveExternalTunnelFromDpnsOutput;
161 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveTerminatingServiceActionsInput;
162 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveTerminatingServiceActionsOutput;
163 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.SetBfdParamOnTunnelInput;
164 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.SetBfdParamOnTunnelOutput;
165 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.get.dpn.info.output.Computes;
166 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.get.dpn.info.output.ComputesBuilder;
167 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
168 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
169 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg6;
170 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
171 import org.opendaylight.yangtools.yang.common.OperationFailedException;
172 import org.opendaylight.yangtools.yang.common.RpcError;
173 import org.opendaylight.yangtools.yang.common.RpcResult;
174 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
175 import org.opendaylight.yangtools.yang.common.Uint16;
176 import org.opendaylight.yangtools.yang.common.Uint64;
177 import org.slf4j.Logger;
178 import org.slf4j.LoggerFactory;
179
180 @Singleton
181 public class ItmManagerRpcService implements ItmRpcService {
182
183     private static final Logger LOG = LoggerFactory.getLogger(ItmManagerRpcService.class);
184
185     private final DataBroker dataBroker;
186     private final IMdsalApiManager mdsalManager;
187     private final DPNTEPsInfoCache dpnTEPsInfoCache;
188     private final ItmExternalTunnelAddWorker externalTunnelAddWorker;
189     private final SingleTransactionDataBroker singleTransactionDataBroker;
190     private final IInterfaceManager interfaceManager;
191     private final InterfaceManagerService interfaceManagerService;
192     private final DpnTepStateCache dpnTepStateCache;
193     private final TunnelStateCache tunnelStateCache;
194     private final OvsBridgeRefEntryCache ovsBridgeRefEntryCache;
195     private final DirectTunnelUtils directTunnelUtils;
196     private final ManagedNewTransactionRunner txRunner;
197     private final RetryingManagedNewTransactionRunner retryingTxRunner;
198     private final ItmConfig itmConfig;
199     private final OfDpnTepConfigCache ofDpnTepConfigCache;
200     private final OfTepStateCache ofTepStateCache;
201
202     @Inject
203     public ItmManagerRpcService(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
204                                 final ItmConfig itmConfig, final DPNTEPsInfoCache dpnTEPsInfoCache,
205                                 final IInterfaceManager interfaceManager, final DpnTepStateCache dpnTepStateCache,
206                                 final TunnelStateCache tunnelStateCache,
207                                 final InterfaceManagerService interfaceManagerService,
208                                 final OvsBridgeRefEntryCache ovsBridgeRefEntryCache,
209                                 final DirectTunnelUtils directTunnelUtils, OfDpnTepConfigCache ofDpnTepConfigCache,
210                                 OfTepStateCache ofTepStateCache) {
211         this.dataBroker = dataBroker;
212         this.mdsalManager = mdsalManager;
213         this.dpnTEPsInfoCache = dpnTEPsInfoCache;
214         this.externalTunnelAddWorker = new ItmExternalTunnelAddWorker(itmConfig, dpnTEPsInfoCache);
215         this.singleTransactionDataBroker = new SingleTransactionDataBroker(dataBroker);
216         this.interfaceManager = interfaceManager;
217         this.interfaceManagerService = interfaceManagerService;
218         this.dpnTepStateCache = dpnTepStateCache;
219         this.tunnelStateCache = tunnelStateCache;
220         this.ovsBridgeRefEntryCache = ovsBridgeRefEntryCache;
221         this.directTunnelUtils = directTunnelUtils;
222         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
223         this.retryingTxRunner = new RetryingManagedNewTransactionRunner(dataBroker);
224         this.itmConfig = itmConfig;
225         this.ofDpnTepConfigCache = ofDpnTepConfigCache;
226         this.ofTepStateCache = ofTepStateCache;
227     }
228
229     @PostConstruct
230     public void start() {
231         LOG.info("ItmManagerRpcService Started");
232     }
233
234     @PreDestroy
235     public void close() {
236         LOG.info("ItmManagerRpcService Closed");
237     }
238
239     @Override
240     public ListenableFuture<RpcResult<GetTunnelInterfaceNameOutput>> getTunnelInterfaceName(
241             GetTunnelInterfaceNameInput input) {
242         RpcResultBuilder<GetTunnelInterfaceNameOutput> resultBld = null;
243         Uint64 sourceDpn = input.getSourceDpid();
244         Uint64 destinationDpn = input.getDestinationDpid();
245         Optional<InternalTunnel> optTunnel = Optional.empty();
246
247         if (interfaceManager.isItmOfTunnelsEnabled()) {
248             //Destination DPN Id is not relevant in OF Tunnel scenario and so is ignored
249             try {
250                 Optional<OfDpnTep> dpnstep = ofDpnTepConfigCache.get(sourceDpn.toJava());
251                 if (dpnstep.isPresent()) {
252                     resultBld = RpcResultBuilder.success();
253                     resultBld.withResult(new GetTunnelInterfaceNameOutputBuilder()
254                             .setInterfaceName(dpnstep.get().getOfPortName())).build();
255                     return Futures.immediateFuture(resultBld.build());
256                 } else {
257                     LOG.error("OF tunnel is not available in ITM for source dpn {}", sourceDpn);
258                     resultBld = RpcResultBuilder.failed();
259                     return Futures.immediateFuture(resultBld.build());
260                 }
261             } catch (ReadFailedException e) {
262                 LOG.error("ReadFailedException: cache read failed for source dpn {} reason: {}", sourceDpn,
263                         e.getMessage());
264                 resultBld = RpcResultBuilder.failed();
265                 return Futures.immediateFuture(resultBld.build());
266             }
267         }
268         if (interfaceManager.isItmDirectTunnelsEnabled()) {
269             DpnTepInterfaceInfo interfaceInfo = dpnTepStateCache.getDpnTepInterface(sourceDpn, destinationDpn);
270             if (interfaceInfo != null) {
271                 resultBld = RpcResultBuilder.success();
272                 resultBld.withResult(new GetTunnelInterfaceNameOutputBuilder()
273                         .setInterfaceName(interfaceInfo.getTunnelName())).build();
274                 return Futures.immediateFuture(resultBld.build());
275             }
276         }
277         if (ItmUtils.isTunnelAggregationUsed(input.getTunnelType())) {
278             optTunnel = ItmUtils.getInternalTunnelFromDS(sourceDpn, destinationDpn,
279                     TunnelTypeLogicalGroup.class, dataBroker);
280             LOG.debug("MULTIPLE_VxLAN_TUNNELS: getTunnelInterfaceName {}", optTunnel);
281         }
282         if (!optTunnel.isPresent()) {
283             optTunnel = ItmUtils.getInternalTunnelFromDS(sourceDpn, destinationDpn, input.getTunnelType(), dataBroker);
284         }
285         if (optTunnel.isPresent()) {
286             InternalTunnel tunnel = optTunnel.get();
287             GetTunnelInterfaceNameOutputBuilder output = new GetTunnelInterfaceNameOutputBuilder() ;
288             List<String> tunnelInterfaces = tunnel.getTunnelInterfaceNames();
289             if (tunnelInterfaces != null && !tunnelInterfaces.isEmpty()) {
290                 output.setInterfaceName(tunnelInterfaces.get(0));
291                 resultBld = RpcResultBuilder.success();
292                 resultBld.withResult(output.build());
293             } else {
294                 resultBld = failed();
295             }
296
297         } else {
298             resultBld = failed();
299         }
300         return Futures.immediateFuture(resultBld.build());
301     }
302
303     @Override
304     public ListenableFuture<RpcResult<GetEgressActionsForTunnelOutput>>
305         getEgressActionsForTunnel(GetEgressActionsForTunnelInput input) {
306         String tunnelName = input.getIntfName();
307         if (tunnelName == null) {
308             return Futures.immediateFuture(RpcResultBuilder.<GetEgressActionsForTunnelOutput>failed()
309                     .withError(RpcError.ErrorType.APPLICATION,
310                             "tunnel name not set for GetEgressActionsForTunnel call").build());
311         }
312         if (tunnelName.startsWith("of")
313                 || (interfaceManager.isItmDirectTunnelsEnabled() && dpnTepStateCache.isInternal(tunnelName))) {
314             return fromListenableFuture(LOG, input, () -> getEgressActionsForInternalTunnels(input.getIntfName(),
315                     input.getTunnelKey() != null ? input.getTunnelKey().toJava() : null,
316                     input.getActionKey())).onFailureLogLevel(LogLevel.ERROR).build();
317         } else {
318             // Re-direct the RPC to Interface Manager
319             // From the rpc input and get the output and copy to output
320             org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406
321                     .GetEgressActionsForInterfaceInputBuilder inputIfmBuilder =
322                     new org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406
323                             .GetEgressActionsForInterfaceInputBuilder().setIntfName(input.getIntfName())
324                             .setTunnelKey(input.getTunnelKey()).setActionKey(input.getActionKey());
325             SettableFuture<RpcResult<GetEgressActionsForTunnelOutput>> settableFuture = SettableFuture.create();
326             Futures.addCallback(interfaceManagerService.getEgressActionsForInterface(inputIfmBuilder.build()),
327                     new FutureCallback<org.opendaylight.yang.gen.v1.urn.opendaylight.genius
328                             .interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceOutput>() {
329                         @Override
330                         public void onSuccess(org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs
331                                                       .rev160406.@NonNull GetEgressActionsForInterfaceOutput result) {
332                             GetEgressActionsForTunnelOutputBuilder output =
333                                     new GetEgressActionsForTunnelOutputBuilder().setAction(result.getAction());
334                             settableFuture.set(RpcResultBuilder.<GetEgressActionsForTunnelOutput>success()
335                                     .withResult(output.build()).build());
336                         }
337
338                         @Override
339                         public void onFailure(Throwable throwable) {
340                             LOG.debug("RPC Call to Get egress actions failed for interface {}", tunnelName);
341                             String errMsg = String.format("RPC call to get egress actions failed for interface %s",
342                                     tunnelName);
343                             settableFuture.set(RpcResultBuilder.<GetEgressActionsForTunnelOutput>failed()
344                                     .withError(RpcError.ErrorType.APPLICATION, errMsg, throwable).build());
345                         }
346                     } ,MoreExecutors.directExecutor());
347             return  settableFuture;
348         }
349     }
350
351     @Override
352     public ListenableFuture<RpcResult<GetTunnelTypeOutput>> getTunnelType(GetTunnelTypeInput input) {
353         String tunnelName = input.getIntfName();
354         if (tunnelName == null) {
355             return Futures.immediateFuture(RpcResultBuilder.<GetTunnelTypeOutput>failed()
356                     .withError(RpcError.ErrorType.APPLICATION,
357                             "tunnel name not set for getTunnelType call").build());
358         }
359
360         if (!dpnTepStateCache.isInternal(tunnelName) || !interfaceManager.isItmDirectTunnelsEnabled()) {
361             org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406
362                     .GetTunnelTypeInputBuilder inputBuilder = new org.opendaylight.yang.gen.v1.urn.opendaylight
363                     .genius.interfacemanager.rpcs.rev160406.GetTunnelTypeInputBuilder()
364                     .setIntfName(input.getIntfName());
365             SettableFuture<RpcResult<GetTunnelTypeOutput>> settableFuture = SettableFuture.create();
366             Futures.addCallback(interfaceManagerService.getTunnelType(inputBuilder.build()),
367                     new FutureCallback<org.opendaylight.yang.gen.v1.urn.opendaylight.genius
368                             .interfacemanager.rpcs.rev160406.GetTunnelTypeOutput>() {
369                         @Override
370                         public void onSuccess(org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs
371                                                       .rev160406.@NonNull GetTunnelTypeOutput result) {
372                             GetTunnelTypeOutputBuilder output = new GetTunnelTypeOutputBuilder()
373                                     .setTunnelType(result.getTunnelType());
374                             settableFuture.set(RpcResultBuilder.<GetTunnelTypeOutput>success()
375                                     .withResult(output.build()).build());
376                         }
377
378                         @Override
379                         public void onFailure(Throwable throwable) {
380                             LOG.debug("RPC Call to Get tunnel type failed for interface {}", tunnelName);
381                             String errMsg = String.format("RPC to Get tunnel type failed for interface %s",
382                                     tunnelName);
383                             settableFuture.set(RpcResultBuilder.<GetTunnelTypeOutput>failed()
384                                     .withError(RpcError.ErrorType.APPLICATION, errMsg, throwable).build());
385                         }
386                     },MoreExecutors.directExecutor());
387             return settableFuture;
388         } else {
389             LOG.debug("get tunnel type from ITM for interface name {}", input.getIntfName());
390             return FutureRpcResults.fromBuilder(LOG, input, () -> {
391                 DpnTepInterfaceInfo ifInfo = dpnTepStateCache.getTunnelFromCache(input.getIntfName());
392                 return new GetTunnelTypeOutputBuilder().setTunnelType(ifInfo.getTunnelType());
393             }).build();
394         }
395     }
396
397     @Override
398     public ListenableFuture<RpcResult<SetBfdParamOnTunnelOutput>> setBfdParamOnTunnel(
399             SetBfdParamOnTunnelInput input) {
400         final Uint64 srcDpnId = Uint64.valueOf(input.getSourceNode());
401         final Uint64 destDpnId = Uint64.valueOf(input.getDestinationNode());
402         LOG.debug("setBfdParamOnTunnel srcDpnId: {}, destDpnId: {}", srcDpnId, destDpnId);
403         final SettableFuture<RpcResult<SetBfdParamOnTunnelOutput>> result = SettableFuture.create();
404         FluentFuture<?> future = txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
405             enableBFD(tx, srcDpnId, destDpnId, input.isMonitoringEnabled(), input.getMonitoringInterval().toJava());
406             enableBFD(tx, destDpnId, srcDpnId, input.isMonitoringEnabled(), input.getMonitoringInterval().toJava());
407         });
408
409         future.addCallback(new FutureCallback<Object>() {
410             @Override
411             public void onSuccess(Object voidInstance) {
412                 result.set(RpcResultBuilder.<SetBfdParamOnTunnelOutput>success().build());
413             }
414
415             @Override
416             public void onFailure(Throwable error) {
417                 String msg = "Unable to remove external tunnel from DPN";
418                 LOG.error("remove ext tunnel failed. {}.", msg, error);
419                 result.set(RpcResultBuilder.<SetBfdParamOnTunnelOutput>failed()
420                         .withError(RpcError.ErrorType.APPLICATION, msg, error).build());
421             }
422         }, MoreExecutors.directExecutor());
423         return result;
424     }
425
426     private void enableBFD(TypedWriteTransaction<Datastore.Configuration> tx, Uint64 srcDpnId, Uint64 destDpnId,
427                            final Boolean enabled, final Integer interval) throws ReadFailedException {
428         DpnTepInterfaceInfo dpnTepInterfaceInfo = dpnTepStateCache.getDpnTepInterface(srcDpnId, destDpnId);
429         RemoteDpnsBuilder remoteDpnsBuilder = new RemoteDpnsBuilder();
430         remoteDpnsBuilder.withKey(new RemoteDpnsKey(destDpnId)).setDestinationDpnId(destDpnId)
431                 .setTunnelName(dpnTepInterfaceInfo.getTunnelName()).setInternal(dpnTepInterfaceInfo.isInternal())
432                 .setMonitoringEnabled(enabled);
433         if (enabled && interval != null) {
434             remoteDpnsBuilder.setMonitoringInterval(interval);
435         }
436         RemoteDpns remoteDpn = remoteDpnsBuilder.build();
437         Optional<OvsBridgeRefEntry> ovsBridgeRefEntry = ovsBridgeRefEntryCache.get(srcDpnId);
438         LOG.debug("setBfdParamOnTunnel TunnelName: {}, ovsBridgeRefEntry: {}", dpnTepInterfaceInfo.getTunnelName(),
439                 ovsBridgeRefEntry);
440         directTunnelUtils.updateBfdConfiguration(srcDpnId, remoteDpn, ovsBridgeRefEntry);
441         InstanceIdentifier<RemoteDpns> iid = InstanceIdentifier.builder(DpnTepsState.class)
442                 .child(DpnsTeps.class, new DpnsTepsKey(srcDpnId))
443                 .child(RemoteDpns.class,
444                         new RemoteDpnsKey(destDpnId)).build();
445         tx.mergeParentStructureMerge(iid, remoteDpn);
446     }
447
448     @Override
449     public ListenableFuture<RpcResult<RemoveExternalTunnelEndpointOutput>> removeExternalTunnelEndpoint(
450             RemoveExternalTunnelEndpointInput input) {
451         //Ignore the Futures for now
452         final SettableFuture<RpcResult<RemoveExternalTunnelEndpointOutput>> result = SettableFuture.create();
453         FluentFuture<?> future = txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
454             tx -> {
455                 InstanceIdentifier<DcGatewayIp> extPath = InstanceIdentifier.builder(DcGatewayIpList.class)
456                         .child(DcGatewayIp.class, new DcGatewayIpKey(input.getDestinationIp())).build();
457                 tx.delete(extPath);
458             }
459         );
460         future.addCallback(new FutureCallback<Object>() {
461             @Override public void onSuccess(Object voidInstance) {
462                 result.set(RpcResultBuilder.<RemoveExternalTunnelEndpointOutput>success().build());
463             }
464
465             @Override public void onFailure(Throwable error) {
466                 String msg = "Unable to delete DcGatewayIp " + input.getDestinationIp()
467                         + " in datastore and tunnel type " + input.getTunnelType();
468                 LOG.error("Unable to delete DcGatewayIp {} in datastore and tunnel type {}", input.getDestinationIp(),
469                         input.getTunnelType());
470                 result.set(RpcResultBuilder.<RemoveExternalTunnelEndpointOutput>failed()
471                         .withError(RpcError.ErrorType.APPLICATION, msg, error).build());
472             }
473         }, MoreExecutors.directExecutor());
474         return result;
475     }
476
477     @Override
478     public ListenableFuture<RpcResult<RemoveExternalTunnelFromDpnsOutput>> removeExternalTunnelFromDpns(
479             RemoveExternalTunnelFromDpnsInput input) {
480         //Ignore the Futures for now
481         final SettableFuture<RpcResult<RemoveExternalTunnelFromDpnsOutput>> result = SettableFuture.create();
482         List<DPNTEPsInfo> cfgDpnList = ItmUtils.getDpnTepListFromDpnId(dpnTEPsInfoCache, input.getDpnId());
483         FluentFuture<?> future = txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
484             tx -> ItmExternalTunnelDeleteWorker.deleteTunnels(cfgDpnList, input.getDestinationIp(),
485                     input.getTunnelType(), tx));
486
487         future.addCallback(new FutureCallback<Object>() {
488             @Override
489             public void onSuccess(Object voidInstance) {
490                 result.set(RpcResultBuilder.<RemoveExternalTunnelFromDpnsOutput>success().build());
491             }
492
493             @Override
494             public void onFailure(Throwable error) {
495                 String msg = "Unable to remove external tunnel from DPN";
496                 LOG.error("remove ext tunnel failed. {}.", msg, error);
497                 result.set(RpcResultBuilder.<RemoveExternalTunnelFromDpnsOutput>failed()
498                         .withError(RpcError.ErrorType.APPLICATION, msg, error).build());
499             }
500         }, MoreExecutors.directExecutor());
501         return result;
502     }
503
504     @Override
505     public ListenableFuture<RpcResult<BuildExternalTunnelFromDpnsOutput>> buildExternalTunnelFromDpns(
506             BuildExternalTunnelFromDpnsInput input) {
507         //Ignore the Futures for now
508         final SettableFuture<RpcResult<BuildExternalTunnelFromDpnsOutput>> result = SettableFuture.create();
509         FluentFuture<?> extTunnelResultList =
510             txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
511                 tx -> externalTunnelAddWorker.buildTunnelsFromDpnToExternalEndPoint(input.getDpnId(),
512                     input.getDestinationIp(),input.getTunnelType(), tx));
513
514         extTunnelResultList.addCallback(new FutureCallback<Object>() {
515             @Override
516             public void onSuccess(Object voidInstance) {
517                 result.set(RpcResultBuilder.<BuildExternalTunnelFromDpnsOutput>success().build());
518             }
519
520             @Override
521             public void onFailure(Throwable error) {
522                 String msg = "Unable to create ext tunnel";
523                 LOG.error("create ext tunnel failed. {}.", msg, error);
524                 result.set(RpcResultBuilder.<BuildExternalTunnelFromDpnsOutput>failed()
525                         .withError(RpcError.ErrorType.APPLICATION, msg, error).build());
526             }
527         }, MoreExecutors.directExecutor());
528         return result;
529     }
530
531     @Override
532     public ListenableFuture<RpcResult<AddExternalTunnelEndpointOutput>> addExternalTunnelEndpoint(
533             AddExternalTunnelEndpointInput input) {
534         // TODO Auto-generated method stub
535
536         //Ignore the Futures for now
537         final SettableFuture<RpcResult<AddExternalTunnelEndpointOutput>> result = SettableFuture.create();
538         InstanceIdentifier<DcGatewayIp> extPath = InstanceIdentifier.builder(DcGatewayIpList.class)
539                 .child(DcGatewayIp.class, new DcGatewayIpKey(input.getDestinationIp())).build();
540         DcGatewayIp dcGatewayIp =
541                 new DcGatewayIpBuilder().setIpAddress(input.getDestinationIp())
542                         .setTunnnelType(input.getTunnelType()).build();
543
544         FluentFuture<?> future = txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
545             tx -> {
546                 tx.mergeParentStructurePut(extPath, dcGatewayIp);
547             }
548         );
549         future.addCallback(new FutureCallback<Object>() {
550             @Override public void onSuccess(Object voidInstance) {
551                 result.set(RpcResultBuilder.<AddExternalTunnelEndpointOutput>success().build());
552             }
553
554             @Override public void onFailure(Throwable error) {
555                 String msg =
556                         "Unable to create DcGatewayIp {} in datastore for ip " + input.getDestinationIp() + "and "
557                                 + "tunnel type " + input.getTunnelType();
558
559                 LOG.error("Unable to create DcGatewayIp in datastore for ip {} and tunnel type {}",
560                         input.getDestinationIp() , input.getTunnelType());
561                 result.set(RpcResultBuilder.<AddExternalTunnelEndpointOutput>failed()
562                         .withError(RpcError.ErrorType.APPLICATION, msg, error).build());
563             }
564         }, MoreExecutors.directExecutor());
565         return result;
566     }
567
568     @Override
569     public ListenableFuture<RpcResult<GetExternalTunnelInterfaceNameOutput>> getExternalTunnelInterfaceName(
570             GetExternalTunnelInterfaceNameInput input) {
571         SettableFuture.create();
572         RpcResultBuilder<GetExternalTunnelInterfaceNameOutput> resultBld;
573         String sourceNode = input.getSourceNode();
574         String dstNode = input.getDestinationNode();
575         if (interfaceManager.isItmOfTunnelsEnabled()) {
576             Optional<OfDpnTep> tepDetail;
577             try {
578                 tepDetail = ofDpnTepConfigCache.get(new BigInteger(sourceNode));
579             } catch (ReadFailedException e) {
580                 LOG.error("ReadFailedException: OF tunnel interface is not available in config DS for "
581                         + "source dpn {} reason: {}", sourceNode, e.getMessage());
582                 resultBld = failed();
583                 return Futures.immediateFuture(resultBld.build());
584             }
585             if (tepDetail.isPresent()) {
586                 GetExternalTunnelInterfaceNameOutputBuilder output =
587                         new GetExternalTunnelInterfaceNameOutputBuilder()
588                                 .setInterfaceName(tepDetail.get().getOfPortName());
589                 resultBld = RpcResultBuilder.success();
590                 resultBld.withResult(output.build());
591                 return Futures.immediateFuture(resultBld.build());
592             } else {
593                 LOG.error("OF tunnel interface is not available in config DS for source dpn {}", sourceNode);
594                 resultBld = failed();
595                 return Futures.immediateFuture(resultBld.build());
596             }
597         }
598         ExternalTunnelKey externalTunnelKey = new ExternalTunnelKey(dstNode, sourceNode, input.getTunnelType());
599         InstanceIdentifier<ExternalTunnel> path = InstanceIdentifier.create(
600                 ExternalTunnelList.class)
601                 .child(ExternalTunnel.class, externalTunnelKey);
602         ExternalTunnel exTunnel =
603                 ItmUtils.getExternalTunnelbyExternalTunnelKey(externalTunnelKey, path, this.dataBroker);
604         if (exTunnel != null) {
605             GetExternalTunnelInterfaceNameOutputBuilder output = new GetExternalTunnelInterfaceNameOutputBuilder();
606             output.setInterfaceName(exTunnel.getTunnelInterfaceName());
607             resultBld = RpcResultBuilder.success();
608             resultBld.withResult(output.build());
609         } else {
610             resultBld = failed();
611         }
612
613         return Futures.immediateFuture(resultBld.build());
614     }
615
616     @Override
617     public ListenableFuture<RpcResult<CreateTerminatingServiceActionsOutput>>
618         createTerminatingServiceActions(final CreateTerminatingServiceActionsInput input) {
619         LOG.info("create terminatingServiceAction on DpnId = {} for service id {} and instructions {}",
620                 input.getDpnId() , input.getServiceId(), input.getInstruction());
621         final SettableFuture<RpcResult<CreateTerminatingServiceActionsOutput>> result = SettableFuture.create();
622         Uint16 serviceId = input.getServiceId();
623         final List<MatchInfo> mkMatches = getTunnelMatchesForServiceId(serviceId);
624
625         Flow terminatingServiceTableFlow = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
626                 getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, serviceId), 5,
627                 "ITM Flow Entry :" + serviceId, 0, 0,
628                 Uint64.fromLongBits(ITMConstants.COOKIE_ITM.longValue() + serviceId.toJava()), mkMatches,
629                 input.getInstruction());
630
631         ListenableFuture<?> installFlowResult = txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
632             tx -> mdsalManager.addFlow(tx, input.getDpnId(), terminatingServiceTableFlow));
633         Futures.addCallback(installFlowResult, new FutureCallback<Object>() {
634
635             @Override
636             public void onSuccess(Object voidInstance) {
637                 result.set(RpcResultBuilder.<CreateTerminatingServiceActionsOutput>success().build());
638             }
639
640             @Override
641             public void onFailure(Throwable error) {
642                 String msg = String.format("Unable to install terminating service flow for %s", input.getDpnId());
643                 LOG.error("create terminating service actions failed. {}", msg, error);
644                 result.set(RpcResultBuilder.<CreateTerminatingServiceActionsOutput>failed()
645                         .withError(RpcError.ErrorType.APPLICATION, msg, error)
646                         .build());
647             }
648         }, MoreExecutors.directExecutor());
649         // result.set(RpcResultBuilder.<Void>success().build());
650         return result;
651     }
652
653     @Override
654     public ListenableFuture<RpcResult<RemoveTerminatingServiceActionsOutput>>
655         removeTerminatingServiceActions(final RemoveTerminatingServiceActionsInput input) {
656         LOG.info("remove terminatingServiceActions called with DpnId = {} and serviceId = {}",
657                 input.getDpnId(), input.getServiceId());
658         final SettableFuture<RpcResult<RemoveTerminatingServiceActionsOutput>> result = SettableFuture.create();
659
660         ListenableFuture<?> removeFlowResult = txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
661             tx -> mdsalManager.removeFlow(tx, input.getDpnId(),
662                         getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, input.getServiceId()),
663                         NwConstants.INTERNAL_TUNNEL_TABLE));
664         Futures.addCallback(removeFlowResult, new FutureCallback<Object>() {
665
666             @Override
667             public void onSuccess(Object voidInstance) {
668                 result.set(RpcResultBuilder.<RemoveTerminatingServiceActionsOutput>success().build());
669             }
670
671             @Override
672             public void onFailure(Throwable error) {
673                 String msg = String.format("Unable to remove terminating service flow for %s", input.getDpnId());
674                 LOG.error("remove terminating service actions failed. {}", msg, error);
675                 result.set(RpcResultBuilder.<RemoveTerminatingServiceActionsOutput>failed()
676                         .withError(RpcError.ErrorType.APPLICATION, msg, error)
677                         .build());
678             }
679         }, MoreExecutors.directExecutor());
680         //result.set(RpcResultBuilder.<Void>success().build());
681
682         return result ;
683     }
684
685     public List<MatchInfo> getTunnelMatchesForServiceId(Uint16 serviceId) {
686         final List<MatchInfo> mkMatches = new ArrayList<>();
687
688         // Matching metadata
689         mkMatches.add(new MatchTunnelId(Uint64.valueOf(serviceId)));
690
691         return mkMatches;
692     }
693
694     private String getFlowRef(long termSvcTable, Uint16 svcId) {
695         return String.valueOf(termSvcTable) + svcId;
696     }
697
698     @Override
699     public ListenableFuture<RpcResult<GetInternalOrExternalInterfaceNameOutput>> getInternalOrExternalInterfaceName(
700             GetInternalOrExternalInterfaceNameInput input) {
701         RpcResultBuilder<GetInternalOrExternalInterfaceNameOutput> resultBld = failed();
702         Uint64 srcDpn = input.getSourceDpid();
703         IpAddress dstIp = input.getDestinationIp();
704         if (interfaceManager.isItmOfTunnelsEnabled()) {
705             Optional<OfDpnTep> tepDetail;
706             try {
707                 tepDetail = ofDpnTepConfigCache.get(srcDpn.toJava());
708             } catch (ReadFailedException e) {
709                 LOG.error("ReadFailedException: OF tunnel interface is not available in config DS for "
710                         + "source dpn {} reason: {}", srcDpn, e.getMessage());
711                 return Futures.immediateFuture(resultBld.build());
712             }
713             if (tepDetail.isPresent()) {
714                 GetInternalOrExternalInterfaceNameOutputBuilder output =
715                         new GetInternalOrExternalInterfaceNameOutputBuilder()
716                                 .setInterfaceName(tepDetail.get().getOfPortName());
717                 resultBld = RpcResultBuilder.success();
718                 resultBld.withResult(output.build());
719                 return Futures.immediateFuture(resultBld.build());
720             } else {
721                 LOG.error("OF tunnel interface is not available in config DS for source dpn {}", srcDpn);
722                 return Futures.immediateFuture(resultBld.build());
723             }
724         }
725         InstanceIdentifier<ExternalTunnel> path1 = InstanceIdentifier.create(ExternalTunnelList.class)
726                 .child(ExternalTunnel.class,
727                         new ExternalTunnelKey(dstIp.stringValue(), srcDpn.toString(), input.getTunnelType()));
728
729         Optional<ExternalTunnel> optExtTunnel = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path1, dataBroker);
730
731         if (optExtTunnel != null && optExtTunnel.isPresent()) {
732             ExternalTunnel extTunnel = optExtTunnel.get();
733             GetInternalOrExternalInterfaceNameOutputBuilder output =
734                     new GetInternalOrExternalInterfaceNameOutputBuilder()
735                             .setInterfaceName(extTunnel.getTunnelInterfaceName());
736             resultBld = RpcResultBuilder.success();
737             resultBld.withResult(output.build()) ;
738         } else {
739             Collection<DPNTEPsInfo> meshedDpnList = dpnTEPsInfoCache.getAllPresent();
740
741             // Look for external tunnels if not look for internal tunnel
742             for (DPNTEPsInfo teps : meshedDpnList) {
743                 TunnelEndPoints firstEndPt = teps.getTunnelEndPoints().get(0);
744                 if (dstIp.equals(firstEndPt.getIpAddress())) {
745                     Optional<InternalTunnel> optTunnel = Optional.empty();
746                     if (interfaceManager.isItmDirectTunnelsEnabled()) {
747                         DpnTepInterfaceInfo interfaceInfo =
748                                 dpnTepStateCache.getDpnTepInterface(srcDpn, teps.getDPNID());
749                         if (interfaceInfo != null) {
750                             resultBld = RpcResultBuilder.success();
751                             resultBld.withResult(new GetInternalOrExternalInterfaceNameOutputBuilder()
752                                     .setInterfaceName(interfaceInfo.getTunnelName())).build();
753                             return Futures.immediateFuture(resultBld.build());
754                         }
755                     }
756
757                     if (ItmUtils.isTunnelAggregationUsed(input.getTunnelType())) {
758                         optTunnel = ItmUtils.getInternalTunnelFromDS(srcDpn, teps.getDPNID(),
759                                 TunnelTypeLogicalGroup.class, dataBroker);
760                         LOG.debug("MULTIPLE_VxLAN_TUNNELS: getInternalOrExternalInterfaceName {}", optTunnel);
761                     }
762                     if (!optTunnel.isPresent()) {
763                         optTunnel = ItmUtils.getInternalTunnelFromDS(srcDpn, teps.getDPNID(),
764                                 input.getTunnelType(), dataBroker);
765                     }
766                     if (optTunnel.isPresent()) {
767                         InternalTunnel tunnel = optTunnel.get();
768                         List<String> tunnelInterfaces = tunnel.getTunnelInterfaceNames();
769                         if (tunnelInterfaces != null && !tunnelInterfaces.isEmpty()) {
770                             GetInternalOrExternalInterfaceNameOutputBuilder
771                                     output =
772                                     new GetInternalOrExternalInterfaceNameOutputBuilder()
773                                             .setInterfaceName(tunnelInterfaces.get(0));
774                             resultBld = RpcResultBuilder.success();
775                             resultBld.withResult(output.build());
776                         } else {
777                             LOG.error("No tunnel interface found between source DPN {} ans destination IP {}", srcDpn,
778                                     dstIp);
779                         }
780                         break;
781                     } else {
782                         LOG.error("Tunnel not found for source DPN {} ans destination IP {}", srcDpn, dstIp);
783                     }
784                 }
785             }
786         }
787         return Futures.immediateFuture(resultBld.build());
788     }
789
790     @SuppressWarnings("checkstyle:IllegalCatch")
791     @Override
792     public ListenableFuture<RpcResult<DeleteL2GwDeviceOutput>> deleteL2GwDevice(DeleteL2GwDeviceInput input) {
793         final SettableFuture<RpcResult<DeleteL2GwDeviceOutput>> result = SettableFuture.create();
794         boolean foundVxlanTzone = false;
795         try {
796             final IpAddress hwIp = input.getIpAddress();
797             final String nodeId = input.getNodeId();
798             InstanceIdentifier<TransportZones> containerPath = InstanceIdentifier.create(TransportZones.class);
799             Optional<TransportZones> transportZonesOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION,
800                     containerPath, dataBroker);
801             if (transportZonesOptional.isPresent()) {
802                 TransportZones transportZones = transportZonesOptional.get();
803                 if (transportZones.getTransportZone() == null || transportZones.getTransportZone().isEmpty()) {
804                     LOG.error("No teps configured");
805                     result.set(RpcResultBuilder.<DeleteL2GwDeviceOutput>failed()
806                             .withError(RpcError.ErrorType.APPLICATION, "No teps Configured").build());
807                     return result;
808                 }
809                 for (TransportZone tzone : transportZones.getTransportZone()) {
810                     if (!TunnelTypeVxlan.class.equals(tzone.getTunnelType())) {
811                         continue;
812                     }
813                     foundVxlanTzone = true;
814                     String transportZone = tzone.getZoneName();
815                     DeviceVtepsKey deviceVtepKey = new DeviceVtepsKey(hwIp, nodeId);
816                     InstanceIdentifier<DeviceVteps> path = InstanceIdentifier
817                             .builder(TransportZones.class)
818                             .child(TransportZone.class,
819                                     new TransportZoneKey(transportZone))
820                             .child(DeviceVteps.class, deviceVtepKey)
821                             .build();
822                     FluentFuture<?> future =
823                         retryingTxRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> tx.delete(path));
824                     future.addCallback(new FutureCallback<Object>() {
825                         @Override public void onSuccess(Object voidInstance) {
826                             result.set(RpcResultBuilder.<DeleteL2GwDeviceOutput>success().build());
827                         }
828
829                         @Override public void onFailure(Throwable error) {
830                             String msg = String.format("Unable to delete HwVtep %s from datastore", nodeId);
831                             LOG.error("Unable to delete HwVtep {}, {} from datastore", nodeId, hwIp);
832                             result.set(RpcResultBuilder.<DeleteL2GwDeviceOutput>failed()
833                                     .withError(RpcError.ErrorType.APPLICATION, msg, error).build());
834                         }
835                     }, MoreExecutors.directExecutor());
836                 }
837             } else {
838                 result.set(RpcResultBuilder.<DeleteL2GwDeviceOutput>failed()
839                         .withError(RpcError.ErrorType.APPLICATION, "No TransportZones configured").build());
840                 return result;
841             }
842
843             if (!foundVxlanTzone) {
844                 result.set(RpcResultBuilder.<DeleteL2GwDeviceOutput>failed()
845                         .withError(RpcError.ErrorType.APPLICATION, "No VxLan TransportZones configured")
846                         .build());
847             }
848
849             return result;
850         } catch (Exception e) {
851             RpcResultBuilder<DeleteL2GwDeviceOutput> resultBuilder = RpcResultBuilder.<DeleteL2GwDeviceOutput>failed()
852                     .withError(RpcError.ErrorType.APPLICATION, "Deleting l2 Gateway to DS Failed", e);
853             return Futures.immediateFuture(resultBuilder.build());
854         }
855     }
856
857     @SuppressWarnings("checkstyle:IllegalCatch")
858     @Override
859     public ListenableFuture<RpcResult<AddL2GwDeviceOutput>> addL2GwDevice(AddL2GwDeviceInput input) {
860
861         final SettableFuture<RpcResult<AddL2GwDeviceOutput>> result = SettableFuture.create();
862         boolean foundVxlanTzone = false;
863         try {
864             final IpAddress hwIp = input.getIpAddress();
865             final String nodeId = input.getNodeId();
866             //iterate through all transport zones and put TORs under vxlan
867             //if no vxlan tzone is cnfigured, return an error.
868             InstanceIdentifier<TransportZones> containerPath = InstanceIdentifier.create(TransportZones.class);
869             Optional<TransportZones> transportZonesOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION,
870                     containerPath, dataBroker);
871             if (transportZonesOptional.isPresent()) {
872                 TransportZones transportZones = transportZonesOptional.get();
873                 if (transportZones.getTransportZone() == null || transportZones.getTransportZone().isEmpty()) {
874                     LOG.error("No transportZone configured");
875                     result.set(RpcResultBuilder.<AddL2GwDeviceOutput>failed()
876                             .withError(RpcError.ErrorType.APPLICATION, "No transportZone Configured").build());
877                     return result;
878                 }
879                 for (TransportZone tzone : transportZones.getTransportZone()) {
880                     if (!TunnelTypeVxlan.class.equals(tzone.getTunnelType())) {
881                         continue;
882                     }
883                     String transportZone = tzone.getZoneName();
884                     foundVxlanTzone = true;
885                     DeviceVtepsKey deviceVtepKey = new DeviceVtepsKey(hwIp, nodeId);
886                     InstanceIdentifier<DeviceVteps> path = InstanceIdentifier
887                             .builder(TransportZones.class)
888                             .child(TransportZone.class,
889                                     new TransportZoneKey(transportZone))
890                             .child(DeviceVteps.class, deviceVtepKey)
891                             .build();
892                     DeviceVteps deviceVtep = new DeviceVtepsBuilder().withKey(deviceVtepKey).setIpAddress(hwIp)
893                             .setNodeId(nodeId).setTopologyId(input.getTopologyId()).build();
894                     //TO DO: add retry if it fails
895                     FluentFuture<?> future = retryingTxRunner
896                             .callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
897                                 tx -> tx.mergeParentStructurePut(path, deviceVtep));
898
899                     future.addCallback(new FutureCallback<Object>() {
900
901                         @Override public void onSuccess(Object voidInstance) {
902                             result.set(RpcResultBuilder.<AddL2GwDeviceOutput>success().build());
903                         }
904
905                         @Override public void onFailure(Throwable error) {
906                             String msg = String.format("Unable to write HwVtep %s to datastore", nodeId);
907                             LOG.error("Unable to write HwVtep {}, {} to datastore", nodeId, hwIp);
908                             result.set(RpcResultBuilder.<AddL2GwDeviceOutput>failed()
909                                     .withError(RpcError.ErrorType.APPLICATION, msg, error).build());
910                         }
911                     }, MoreExecutors.directExecutor());
912
913                 }
914             } else {
915                 result.set(RpcResultBuilder.<AddL2GwDeviceOutput>failed()
916                         .withError(RpcError.ErrorType.APPLICATION, "No TransportZones configured").build());
917                 return result;
918             }
919
920             if (!foundVxlanTzone) {
921                 result.set(RpcResultBuilder.<AddL2GwDeviceOutput>failed()
922                         .withError(RpcError.ErrorType.APPLICATION, "No VxLan TransportZones configured")
923                         .build());
924             }
925
926             return result;
927         } catch (Exception e) {
928             RpcResultBuilder<AddL2GwDeviceOutput> resultBuilder = RpcResultBuilder.<AddL2GwDeviceOutput>failed()
929                     .withError(RpcError.ErrorType.APPLICATION, "Adding l2 Gateway to DS Failed", e);
930             return Futures.immediateFuture(resultBuilder.build());
931         }
932     }
933
934     @Override
935     public ListenableFuture<RpcResult<GetWatchPortForTunnelOutput>> getWatchPortForTunnel(
936             GetWatchPortForTunnelInput input) {
937         throw new UnsupportedOperationException("TODO");
938     }
939
940     public ListenableFuture<RpcResult<GetTepIpOutput>> getTepIp(GetTepIpInput input) {
941         RpcResultBuilder<GetTepIpOutput> resultBld;
942         Uint64 sourceDpn = input.getDpnId();
943         Optional<OfDpnTep> dpnstep;
944         try {
945             dpnstep = ofDpnTepConfigCache.get(sourceDpn.toJava());
946         } catch (ReadFailedException e) {
947             LOG.error("ReadFailedException: OF tunnel is not available in ITM for source dpn {} reason: {}",sourceDpn,
948                     e.getMessage());
949             resultBld = RpcResultBuilder.failed();
950             return Futures.immediateFuture(resultBld.build());
951         }
952         if (dpnstep.isPresent()) {
953             resultBld = RpcResultBuilder.success();
954             resultBld.withResult(new GetTepIpOutputBuilder()
955                     .setTepIp(dpnstep.get().getTepIp())).build();
956             return Futures.immediateFuture(resultBld.build());
957         } else {
958             LOG.error("OF tunnel is not available in ITM for source dpn {}",sourceDpn);
959             resultBld = RpcResultBuilder.failed();
960             return Futures.immediateFuture(resultBld.build());
961         }
962     }
963
964     @SuppressWarnings("checkstyle:IllegalCatch")
965     @Override
966     public ListenableFuture<RpcResult<AddL2GwMlagDeviceOutput>> addL2GwMlagDevice(AddL2GwMlagDeviceInput input) {
967
968         final SettableFuture<RpcResult<AddL2GwMlagDeviceOutput>> result = SettableFuture.create();
969         try {
970             final IpAddress hwIp = input.getIpAddress();
971             final List<String> nodeId = input.getNodeId();
972             InstanceIdentifier<TransportZones> containerPath = InstanceIdentifier.create(TransportZones.class);
973             Optional<TransportZones> transportZonesOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION,
974                     containerPath, dataBroker);
975             if (transportZonesOptional.isPresent()) {
976                 TransportZones transportZones = transportZonesOptional.get();
977                 if (transportZones.getTransportZone() == null || transportZones.getTransportZone()
978                     .isEmpty()) {
979                     LOG.error("No teps configured");
980                     result.set(RpcResultBuilder.<AddL2GwMlagDeviceOutput>failed()
981                         .withError(RpcError.ErrorType.APPLICATION, "No teps Configured").build());
982                     return result;
983                 }
984                 for (TransportZone tzone : transportZones.getTransportZone()) {
985                     if (!TunnelTypeVxlan.class.equals(tzone.getTunnelType())) {
986                         continue;
987                     }
988                     String transportZone = tzone.getZoneName();
989                     DeviceVtepsKey deviceVtepKey = new DeviceVtepsKey(hwIp, nodeId.get(0));
990                     InstanceIdentifier<DeviceVteps> path =
991                         InstanceIdentifier.builder(TransportZones.class)
992                             .child(TransportZone.class, new TransportZoneKey(transportZone))
993                             .child(DeviceVteps.class, deviceVtepKey).build();
994                     DeviceVteps deviceVtep = new DeviceVtepsBuilder().withKey(deviceVtepKey)
995                         .setIpAddress(hwIp)
996                         .setNodeId(nodeId.get(0)).setTopologyId(input.getTopologyId()).build();
997                     LOG.trace("writing hWvtep{}", deviceVtep);
998                     FluentFuture<?> future =
999                         retryingTxRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1000                             tx -> {
1001                                 tx.mergeParentStructurePut(path, deviceVtep);
1002                                 if (nodeId.size() == 2) {
1003                                     LOG.trace("second node-id {}", nodeId.get(1));
1004                                     DeviceVtepsKey deviceVtepKey2 = new DeviceVtepsKey(hwIp,
1005                                         nodeId.get(1));
1006                                     InstanceIdentifier<DeviceVteps> path2 = InstanceIdentifier
1007                                         .builder(TransportZones.class)
1008                                         .child(TransportZone.class, new TransportZoneKey(transportZone))
1009                                         .child(DeviceVteps.class, deviceVtepKey2).build();
1010                                     DeviceVteps deviceVtep2 = new DeviceVtepsBuilder()
1011                                         .withKey(deviceVtepKey2)
1012                                         .setIpAddress(hwIp).setNodeId(nodeId.get(1))
1013                                         .setTopologyId(input.getTopologyId()).build();
1014                                     LOG.trace("writing {}", deviceVtep2);
1015                                     tx.mergeParentStructurePut(path2, deviceVtep2);
1016                                 }
1017                             });
1018                     future.addCallback(new FutureCallback<Object>() {
1019                         @Override
1020                         public void onSuccess(Object voidInstance) {
1021                             result.set(RpcResultBuilder.<AddL2GwMlagDeviceOutput>success().build());
1022                         }
1023
1024                         @Override
1025                         public void onFailure(Throwable error) {
1026                             String msg = String
1027                                 .format("Unable to write HwVtep %s to datastore", nodeId);
1028                             LOG.error("Unable to write HwVtep {}, {} to datastore", nodeId, hwIp);
1029                             result.set(RpcResultBuilder.<AddL2GwMlagDeviceOutput>failed()
1030                                 .withError(RpcError.ErrorType.APPLICATION, msg, error)
1031                                 .build());
1032                         }
1033                     }, MoreExecutors.directExecutor());
1034                 }
1035             }
1036             return result;
1037         } catch (RuntimeException e) {
1038             RpcResultBuilder<AddL2GwMlagDeviceOutput> resultBuilder = RpcResultBuilder.<AddL2GwMlagDeviceOutput>failed()
1039                     .withError(RpcError.ErrorType.APPLICATION, "Adding l2 Gateway to DS Failed", e);
1040             return Futures.immediateFuture(resultBuilder.build());
1041         }
1042     }
1043
1044     @SuppressWarnings("checkstyle:IllegalCatch")
1045     @Override
1046     public ListenableFuture<RpcResult<DeleteL2GwMlagDeviceOutput>> deleteL2GwMlagDevice(
1047             DeleteL2GwMlagDeviceInput input) {
1048         final SettableFuture<RpcResult<DeleteL2GwMlagDeviceOutput>> result = SettableFuture.create();
1049         try {
1050             final IpAddress hwIp = input.getIpAddress();
1051             final List<String> nodeId = input.getNodeId();
1052             InstanceIdentifier<TransportZones> containerPath = InstanceIdentifier.create(TransportZones.class);
1053             Optional<TransportZones> transportZonesOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION,
1054                     containerPath, dataBroker);
1055             if (transportZonesOptional.isPresent()) {
1056                 TransportZones tzones = transportZonesOptional.get();
1057                 if (tzones.getTransportZone() == null || tzones.getTransportZone().isEmpty()) {
1058                     LOG.error("No teps configured");
1059                     result.set(RpcResultBuilder.<DeleteL2GwMlagDeviceOutput>failed()
1060                             .withError(RpcError.ErrorType.APPLICATION, "No teps Configured").build());
1061                     return result;
1062                 }
1063                 String transportZone = tzones.getTransportZone().get(0).getZoneName();
1064                 FluentFuture<?> future =
1065                     retryingTxRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1066                         tx -> {
1067                             DeviceVtepsKey deviceVtepKey = new DeviceVtepsKey(hwIp, nodeId.get(0));
1068                             InstanceIdentifier<DeviceVteps> path =
1069                                     InstanceIdentifier.builder(TransportZones.class)
1070                                             .child(TransportZone.class, new TransportZoneKey(transportZone))
1071                                             .child(DeviceVteps.class,
1072                                                     deviceVtepKey).build();
1073                             tx.delete(path);
1074                             DeviceVtepsKey deviceVtepKey2 = new DeviceVtepsKey(hwIp, nodeId.get(1));
1075                             InstanceIdentifier<DeviceVteps> path2 =
1076                                     InstanceIdentifier.builder(TransportZones.class)
1077                                             .child(TransportZone.class, new TransportZoneKey(transportZone))
1078                                             .child(DeviceVteps.class,
1079                                                     deviceVtepKey2).build();
1080                             tx.delete(path2);
1081                         }
1082                     );
1083
1084                 future.addCallback(new FutureCallback<Object>() {
1085
1086                     @Override
1087                     public void onSuccess(Object voidInstance) {
1088                         result.set(RpcResultBuilder.<DeleteL2GwMlagDeviceOutput>success().build());
1089                     }
1090
1091                     @Override
1092                     public void onFailure(Throwable error) {
1093                         String msg = String.format("Unable to write HwVtep %s to datastore", nodeId);
1094                         LOG.error("Unable to write HwVtep {}, {} to datastore", nodeId , hwIp);
1095                         result.set(RpcResultBuilder.<DeleteL2GwMlagDeviceOutput>failed()
1096                                 .withError(RpcError.ErrorType.APPLICATION, msg, error)
1097                                 .build());
1098                     }
1099                 }, MoreExecutors.directExecutor());
1100             }
1101             return result;
1102         } catch (Exception e) {
1103             RpcResultBuilder<DeleteL2GwMlagDeviceOutput> resultBuilder =
1104                     RpcResultBuilder.<DeleteL2GwMlagDeviceOutput>failed().withError(RpcError.ErrorType.APPLICATION,
1105                             "Deleting l2 Gateway to DS Failed", e);
1106             return Futures.immediateFuture(resultBuilder.build());
1107         }
1108     }
1109
1110     @Override
1111     public ListenableFuture<RpcResult<IsTunnelInternalOrExternalOutput>> isTunnelInternalOrExternal(
1112             IsTunnelInternalOrExternalInput input) {
1113         RpcResultBuilder<IsTunnelInternalOrExternalOutput> resultBld;
1114         String tunIfName = input.getTunnelInterfaceName();
1115         long tunVal = 0;
1116         IsTunnelInternalOrExternalOutputBuilder output = new IsTunnelInternalOrExternalOutputBuilder()
1117                 .setTunnelType(tunVal);
1118
1119         if (ItmUtils.ITM_CACHE.getInternalTunnel(tunIfName) != null) {
1120             tunVal = 1;
1121         } else if (ItmUtils.ITM_CACHE.getExternalTunnel(tunIfName) != null) {
1122             tunVal = 2;
1123         }
1124         output.setTunnelType(tunVal);
1125         resultBld = RpcResultBuilder.success();
1126         resultBld.withResult(output.build());
1127         return Futures.immediateFuture(resultBld.build());
1128     }
1129
1130     @Override
1131     public ListenableFuture<RpcResult<IsDcgwPresentOutput>> isDcgwPresent(IsDcgwPresentInput input) {
1132         RpcResultBuilder<IsDcgwPresentOutput> resultBld = RpcResultBuilder.success();
1133
1134         Map<DcGatewayIpKey, DcGatewayIp> dcGatewayIpList = new HashMap<>();
1135         txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
1136             tx -> dcGatewayIpList.putAll(getDcGatewayIpList(tx))).isDone();
1137         String dcgwIpStr = input.getDcgwIp();
1138         IpAddress dcgwIpAddr = IpAddressBuilder.getDefaultInstance(dcgwIpStr);
1139         long retVal;
1140
1141         if (!dcGatewayIpList.isEmpty()
1142                 && dcGatewayIpList.values().stream().anyMatch(gwIp -> Objects.equal(gwIp.getIpAddress(), dcgwIpAddr))) {
1143             //Match found
1144             retVal = 1;
1145             IsDcgwPresentOutputBuilder output = new IsDcgwPresentOutputBuilder().setRetVal(retVal);
1146             resultBld.withResult(output.build());
1147         } else {
1148             //Match not found
1149             retVal = 2;
1150             IsDcgwPresentOutputBuilder output = new IsDcgwPresentOutputBuilder().setRetVal(retVal);
1151             resultBld.withResult(output.build());
1152         }
1153         return Futures.immediateFuture(resultBld.build());
1154     }
1155
1156     @Override
1157     public ListenableFuture<RpcResult<GetDpnEndpointIpsOutput>> getDpnEndpointIps(GetDpnEndpointIpsInput input) {
1158         Uint64 srcDpn = input.getSourceDpid();
1159         RpcResultBuilder<GetDpnEndpointIpsOutput> resultBld = failed();
1160         InstanceIdentifier<DPNTEPsInfo> tunnelInfoId =
1161                 InstanceIdentifier.builder(DpnEndpoints.class).child(DPNTEPsInfo.class,
1162                         new DPNTEPsInfoKey(srcDpn)).build();
1163         Optional<DPNTEPsInfo> tunnelInfo = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, tunnelInfoId, dataBroker);
1164         if (!tunnelInfo.isPresent()) {
1165             LOG.error("tunnelInfo is not present");
1166             return Futures.immediateFuture(resultBld.build());
1167         }
1168
1169         List<TunnelEndPoints> tunnelEndPointList = tunnelInfo.get().getTunnelEndPoints();
1170         if (tunnelEndPointList == null || tunnelEndPointList.isEmpty()) {
1171             LOG.error("tunnelEndPointList is null or empty");
1172             return Futures.immediateFuture(resultBld.build());
1173         }
1174
1175         List<IpAddress> nexthopIpList = new ArrayList<>();
1176         tunnelEndPointList.forEach(tunnelEndPoint -> nexthopIpList.add(tunnelEndPoint.getIpAddress()));
1177
1178         GetDpnEndpointIpsOutputBuilder output = new GetDpnEndpointIpsOutputBuilder().setNexthopipList(nexthopIpList);
1179         resultBld = RpcResultBuilder.success();
1180         resultBld.withResult(output.build()) ;
1181         return Futures.immediateFuture(resultBld.build());
1182     }
1183
1184     @Override
1185     public ListenableFuture<RpcResult<GetDpnInfoOutput>> getDpnInfo(GetDpnInfoInput input) {
1186         return FutureRpcResults.fromListenableFuture(LOG, "getDpnInfo", input,
1187             () -> Futures.immediateFuture(getDpnInfoInternal(input))).build();
1188     }
1189
1190     private GetDpnInfoOutput getDpnInfoInternal(GetDpnInfoInput input) throws ReadFailedException {
1191         Map<String, Uint64> computeNamesVsDpnIds
1192                 = getDpnIdByComputeNodeNameFromOpInventoryNodes(input.getComputeNames());
1193         Map<Uint64, ComputesBuilder> dpnIdVsVtepsComputes
1194                 = getTunnelEndPointByDpnIdFromTranPortZone(computeNamesVsDpnIds.values());
1195         List<Computes> computes = computeNamesVsDpnIds.entrySet().stream()
1196                 .map(entry -> dpnIdVsVtepsComputes.get(entry.getValue()).setComputeName(entry.getKey()).build())
1197                 .collect(Collectors.toList());
1198         return new GetDpnInfoOutputBuilder().setComputes(computes).build();
1199     }
1200
1201     private Map<Uint64, ComputesBuilder> getTunnelEndPointByDpnIdFromTranPortZone(Collection<Uint64> dpnIds)
1202             throws ReadFailedException {
1203         TransportZones transportZones = singleTransactionDataBroker.syncRead(
1204                 LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.builder(TransportZones.class).build());
1205         if (transportZones.getTransportZone() == null || transportZones.getTransportZone().isEmpty()) {
1206             throw new IllegalStateException("Failed to find transport zones in config datastore");
1207         }
1208         Map<Uint64, ComputesBuilder> result = new HashMap<>();
1209         for (TransportZone transportZone : transportZones.getTransportZone()) {
1210             for (Vteps vtep : transportZone.getVteps().values()) {
1211                 if (dpnIds.contains(vtep.getDpnId())) {
1212                     result.putIfAbsent(vtep.getDpnId(),
1213                             new ComputesBuilder()
1214                                     .setZoneName(transportZone.getZoneName())
1215                                     .setDpnId(vtep.getDpnId())
1216                                     .setNodeId(getNodeId(vtep.getDpnId()))
1217                                     .setTepIp(Collections.singletonList(vtep.getIpAddress())));
1218                 }
1219             }
1220         }
1221         for (Uint64 dpnId : dpnIds) {
1222             if (!result.containsKey(dpnId)) {
1223                 throw new IllegalStateException("Failed to find dpn id " + dpnId + " in transport zone");
1224             }
1225         }
1226         return result;
1227     }
1228
1229     private Map<String, Uint64> getDpnIdByComputeNodeNameFromOpInventoryNodes(List<String> nodeNames)
1230             throws ReadFailedException {
1231         Nodes operInventoryNodes = singleTransactionDataBroker.syncRead(
1232                 LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.builder(Nodes.class).build());
1233         if (operInventoryNodes.getNode() == null || operInventoryNodes.getNode().isEmpty()) {
1234             throw new IllegalStateException("Failed to find operational inventory nodes datastore");
1235         }
1236         Map<String, Uint64> result = new HashMap<>();
1237         for (Node node : operInventoryNodes.getNode().values()) {
1238             String name = node.augmentation(FlowCapableNode.class).getDescription();
1239             if (nodeNames.contains(name)) {
1240                 String[] nodeId = node.getId().getValue().split(":");
1241                 result.put(name, Uint64.valueOf(nodeId[1]));
1242             }
1243         }
1244         for (String nodeName : nodeNames) {
1245             if (!result.containsKey(nodeName)) {
1246                 throw new IllegalStateException("Failed to find dpn id of compute node name from oper inventory "
1247                         + nodeName);
1248             }
1249         }
1250         return result;
1251     }
1252
1253     private String getNodeId(Uint64 dpnId) throws ReadFailedException {
1254         InstanceIdentifier<BridgeRefEntry> path = InstanceIdentifier
1255                 .builder(BridgeRefInfo.class)
1256                 .child(BridgeRefEntry.class, new BridgeRefEntryKey(dpnId)).build();
1257         BridgeRefEntry bridgeRefEntry =
1258                 singleTransactionDataBroker.syncRead(LogicalDatastoreType.OPERATIONAL, path);
1259         return bridgeRefEntry.getBridgeReference().getValue()
1260                 .firstKeyOf(org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021
1261                         .network.topology.topology.Node.class).getNodeId().getValue();
1262     }
1263
1264     private ListenableFuture<GetEgressActionsForTunnelOutput>
1265         getEgressActionsForInternalTunnels(String interfaceName, Long tunnelKey, Integer actionKey)
1266             throws ExecutionException, InterruptedException, OperationFailedException {
1267
1268         if (interfaceName.startsWith("of")) {
1269             Optional<OfTep> oftep = ofTepStateCache.get(interfaceName);
1270             if (!oftep.isPresent()) {
1271                 throw new IllegalStateException("Interface information not present in oper DS for" + interfaceName);
1272             }
1273             List<ActionInfo> actions = getEgressActionInfosForOpenFlowTunnel(oftep.get().getIfIndex(),
1274                     oftep.get().getTepIp(), tunnelKey, actionKey);
1275             return Futures.immediateFuture(new GetEgressActionsForTunnelOutputBuilder()
1276                     .setAction(actions.stream().map(ActionInfo::buildAction).collect(Collectors.toList())).build());
1277         } else {
1278             DpnTepInterfaceInfo interfaceInfo = dpnTepStateCache.getTunnelFromCache(interfaceName);
1279             if (interfaceInfo == null) {
1280                 throw new IllegalStateException("Interface information not present in config DS for" + interfaceName);
1281             }
1282
1283             String tunnelType = ItmUtils.convertTunnelTypetoString(interfaceInfo.getTunnelType());
1284             if (!tunnelType.equalsIgnoreCase(ITMConstants.TUNNEL_TYPE_VXLAN)) {
1285                 throw new IllegalArgumentException(tunnelType + " tunnel not handled by ITM");
1286             }
1287
1288             Optional<DPNTEPsInfo> dpntePsInfoOptional = dpnTEPsInfoCache.get(InstanceIdentifier
1289                     .builder(DpnEndpoints.class)
1290                     .child(DPNTEPsInfo.class, new DPNTEPsInfoKey(
1291                             // FIXME: the cache should be caching this value, not just as a String
1292                             Uint64.valueOf(dpnTepStateCache.getTunnelEndPointInfoFromCache(
1293                                     interfaceInfo.getTunnelName()).getDstEndPointInfo())))
1294                     .build());
1295             Integer dstId;
1296             if (dpntePsInfoOptional.isPresent()) {
1297                 dstId = dpntePsInfoOptional.get().getDstId();
1298             } else {
1299                 dstId = directTunnelUtils.allocateId(ITMConstants.ITM_IDPOOL_NAME,
1300                         interfaceInfo.getRemoteDPN().toString());
1301             }
1302
1303             List<ActionInfo> result = new ArrayList<>();
1304             long regValue = MetaDataUtil.getRemoteDpnMetadatForEgressTunnelTable(dstId);
1305             int actionKeyStart = actionKey == null ? 0 : actionKey;
1306             result.add(new ActionSetFieldTunnelId(actionKeyStart++,
1307                     Uint64.valueOf(tunnelKey != null ? tunnelKey : 0L)));
1308             result.add(new ActionRegLoad(actionKeyStart++, NxmNxReg6.class, MetaDataUtil.REG6_START_INDEX,
1309                     MetaDataUtil.REG6_END_INDEX, regValue));
1310             result.add(new ActionNxResubmit(actionKeyStart, NwConstants.EGRESS_TUNNEL_TABLE));
1311
1312             return Futures.immediateFuture(new GetEgressActionsForTunnelOutputBuilder()
1313                     .setAction(result.stream().map(ActionInfo::buildAction).collect(Collectors.toList())).build());
1314         }
1315     }
1316
1317     private static List<ActionInfo> getEgressActionInfosForOpenFlowTunnel(Uint16 ifIndex, IpAddress ipAddress,
1318                                                                           Long tunnelKey, Integer actionKey) {
1319         List<ActionInfo> result = new ArrayList<>();
1320         int actionKeyStart = actionKey == null ? 0 : actionKey;
1321         result.add(new ActionSetFieldTunnelId(actionKeyStart++,
1322                 Uint64.valueOf(tunnelKey != null ? tunnelKey : 0L)));
1323         long regValue = MetaDataUtil.getReg6ValueForLPortDispatcher(ifIndex.intValue() ,
1324                 NwConstants.DEFAULT_SERVICE_INDEX);
1325         result.add(new ActionRegLoad(actionKeyStart++, NxmNxReg6.class, ITMConstants.REG6_START_INDEX,
1326                 ITMConstants.REG6_END_INDEX, regValue));
1327         result.add(new ActionNxResubmit(actionKeyStart, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE));
1328
1329         return result;
1330     }
1331
1332     public static Map<DcGatewayIpKey, DcGatewayIp>
1333         getDcGatewayIpList(TypedReadWriteTransaction<Datastore.Configuration> tx)
1334             throws ExecutionException, InterruptedException {
1335         Map<DcGatewayIpKey, DcGatewayIp> dcGatewayIpMap = new HashMap<>();
1336         FluentFuture<Optional<DcGatewayIpList>> future =
1337                 tx.read(InstanceIdentifier.builder(DcGatewayIpList.class).build());
1338         future.addCallback(new FutureCallback<Optional<DcGatewayIpList>>() {
1339             @Override
1340             public void onSuccess(Optional<DcGatewayIpList> optional) {
1341                 try {
1342                     // FIXME: why not just use the provided optional?
1343                     Optional<DcGatewayIpList> opt = future.get();
1344                     if (opt.isPresent()) {
1345                         DcGatewayIpList list = opt.get();
1346                         if (list != null) {
1347                             dcGatewayIpMap.putAll(list.getDcGatewayIp());
1348                         }
1349                     }
1350                 } catch (ExecutionException | InterruptedException e) {
1351                     LOG.error("DcGateway IpList read failed", e);
1352                 }
1353             }
1354
1355             @Override
1356             public void onFailure(Throwable error) {
1357                 LOG.error("DcGateway IpList read failed", error);
1358             }
1359         }, MoreExecutors.directExecutor());
1360         return dcGatewayIpMap;
1361     }
1362 }