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