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