ELAN FT Support for BE
[vpnservice.git] / nexthopmgr / nexthopmgr-impl / src / main / java / org / opendaylight / vpnservice / nexthopmgr / NexthopManager.java
1 /*
2  * Copyright (c) 2015 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.vpnservice.nexthopmgr;
9
10 import org.opendaylight.vpnservice.mdsalutil.FlowEntity;
11 import org.opendaylight.vpnservice.mdsalutil.InstructionInfo;
12 import org.opendaylight.vpnservice.mdsalutil.InstructionType;
13 import org.opendaylight.vpnservice.mdsalutil.MatchFieldType;
14 import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
15 import org.opendaylight.vpnservice.mdsalutil.NwConstants;
16
17 import java.math.BigInteger;
18 import java.util.ArrayList;
19 import java.util.List;
20 import java.util.concurrent.Future;
21 import com.google.common.base.Optional;
22 import com.google.common.util.concurrent.Futures;
23 import com.google.common.util.concurrent.FutureCallback;
24 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
25 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
26 import org.opendaylight.yangtools.yang.binding.DataObject;
27 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
28 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
29 import org.opendaylight.yangtools.yang.common.RpcResult;
30 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
31 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
32 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
33 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
34 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
35 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstanceKey;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
37 //import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstance1;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdInput;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdInputBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdOutput;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.CreateIdPoolInput;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.CreateIdPoolInputBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.ReleaseIdInput;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.ReleaseIdInputBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.*;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.l3nexthop.*;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.l3nexthop.tunnelnexthops.*;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.l3nexthop.vpnnexthops.*;
50 import org.opendaylight.vpnservice.interfacemgr.interfaces.IInterfaceManager;
51 import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
52 import org.opendaylight.vpnservice.mdsalutil.ActionType;
53 import org.opendaylight.vpnservice.mdsalutil.BucketInfo;
54 import org.opendaylight.vpnservice.mdsalutil.GroupEntity;
55 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
56 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
57 import org.opendaylight.idmanager.IdManager;
58 import java.util.concurrent.ExecutionException;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
61
62 public class NexthopManager implements L3nexthopService, AutoCloseable {
63     private static final Logger LOG = LoggerFactory.getLogger(NexthopManager.class);
64     private final DataBroker broker;
65     private IMdsalApiManager mdsalManager;
66     private IInterfaceManager interfaceManager;
67     private IdManagerService idManager;
68     private static final short LPORT_INGRESS_TABLE = 0;
69     private static final short LFIB_TABLE = 20;
70     private static final short FIB_TABLE = 21;
71     private static final short DEFAULT_FLOW_PRIORITY = 10;
72
73     private static final FutureCallback<Void> DEFAULT_CALLBACK =
74         new FutureCallback<Void>() {
75             public void onSuccess(Void result) {
76                 LOG.debug("Success in Datastore write operation");
77             }
78             public void onFailure(Throwable error) {
79                 LOG.error("Error in Datastore write operation", error);
80             };
81         };
82
83     /**
84     * Provides nexthop functions
85     * Creates group ID pool
86     *
87     * @param db - dataBroker reference
88     */
89     public NexthopManager(final DataBroker db) {
90         broker = db;
91     }
92
93     @Override
94     public void close() throws Exception {
95         LOG.info("NextHop Manager Closed");
96     }
97
98     public void setInterfaceManager(IInterfaceManager ifManager) {
99         this.interfaceManager = ifManager;
100     }
101
102     public void setMdsalManager(IMdsalApiManager mdsalManager) {
103         this.mdsalManager = mdsalManager;
104     }
105
106     public void setIdManager(IdManagerService idManager) {
107         this.idManager = idManager;
108     }
109
110     protected void createNexthopPointerPool() {
111         CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
112                 .setPoolName("nextHopPointerPool")
113                 .setLow(150000L)
114                 .setHigh(175000L)
115                 .build();
116         //TODO: Error handling
117         Future<RpcResult<Void>> result = idManager.createIdPool(createPool);
118         LOG.trace("NextHopPointerPool result : {}", result);
119     }
120
121
122     protected long getVpnId(String vpnName) {
123         InstanceIdentifierBuilder<VpnInstance> idBuilder = InstanceIdentifier.builder(VpnInstances.class)
124                 .child(VpnInstance.class, new VpnInstanceKey(vpnName));
125
126         InstanceIdentifier<VpnInstance> id = idBuilder.build();
127         //FIXME [ELAnBE] Commenting out below 2 lines
128         //InstanceIdentifier<VpnInstance1> idx = id.augmentation(VpnInstance1.class);
129         //Optional<VpnInstance1> vpn = read(LogicalDatastoreType.OPERATIONAL, idx);
130
131
132 //        if (vpn.isPresent()) {
133 //            LOG.debug("VPN id returned: {}", vpn.get().getVpnId());
134 //            return vpn.get().getVpnId();
135 //        } else {
136 //            return -1;
137 //        }
138         return -1;
139     }
140
141     private BigInteger getDpnId(String ofPortId) {
142         String[] fields = ofPortId.split(":");
143         BigInteger dpn = new BigInteger(fields[1]);
144         LOG.debug("DpnId: {}", dpn);
145         return dpn;
146     }
147
148     protected long createNextHopPointer(String nexthopKey) {
149         AllocateIdInput getIdInput = new AllocateIdInputBuilder()
150                 .setPoolName("nextHopPointerPool").setIdKey(nexthopKey)
151                 .build();
152         //TODO: Proper error handling once IdManager code is complete
153         try {
154             Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
155             RpcResult<AllocateIdOutput> rpcResult = result.get();
156             return rpcResult.getResult().getIdValue();
157         } catch (NullPointerException | InterruptedException | ExecutionException e) {
158             LOG.trace("",e);
159         }
160         return 0;
161     }
162
163     public void createLocalNextHop(String ifName, String vpnName, String ipAddress, String macAddress) {
164         String nhKey = new String("nexthop." + vpnName + ipAddress);
165         long groupId = createNextHopPointer(nhKey);
166
167         long vpnId = getVpnId(vpnName);
168         BigInteger dpnId = interfaceManager.getDpnForInterface(ifName);
169         VpnNexthop nexthop = getVpnNexthop(vpnId, ipAddress, 0);
170         LOG.trace("nexthop: {}", nexthop);
171         if (nexthop == null) {
172             List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
173             List<ActionInfo> listActionInfo = interfaceManager.getInterfaceEgressActions(ifName);
174             BucketInfo bucket = new BucketInfo(listActionInfo);
175             // MAC re-write
176             if (macAddress != null) {
177                listActionInfo.add(0, new ActionInfo(ActionType.set_field_eth_dest, new String[]{macAddress}));
178                listActionInfo.add(0, new ActionInfo(ActionType.pop_mpls, new String[]{}));
179             } else {
180                 //FIXME: Log message here.
181                 LOG.debug("mac address for new local nexthop is null");
182             }
183             listBucketInfo.add(bucket);
184             GroupEntity groupEntity = MDSALUtil.buildGroupEntity(
185                 dpnId, groupId, ipAddress, GroupTypes.GroupIndirect, listBucketInfo);
186
187             // install Group
188             mdsalManager.installGroup(groupEntity);
189
190             //update MD-SAL DS
191             addVpnNexthopToDS(vpnId, ipAddress, groupId);
192         } else {
193             //check update
194         }
195     }
196
197     public void createRemoteNextHop(String ifName, String ipAddress) {
198         String nhKey = new String("nexthop." + ifName + ipAddress);
199         long groupId = createNextHopPointer(nhKey);
200
201         BigInteger dpnId = interfaceManager.getDpnForInterface(ifName);
202         TunnelNexthop nexthop = getTunnelNexthop(dpnId, ipAddress);
203         if (nexthop == null) {
204             List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
205             List<ActionInfo> listActionInfo = interfaceManager.getInterfaceEgressActions(ifName);
206             BucketInfo bucket = new BucketInfo(listActionInfo);
207             // MAC re-write??           
208             listBucketInfo.add(bucket);
209             GroupEntity groupEntity = MDSALUtil.buildGroupEntity(
210                 dpnId, groupId, ipAddress, GroupTypes.GroupIndirect, listBucketInfo);
211             mdsalManager.installGroup(groupEntity);
212             //makeRemoteFlow(dpnId, ifName, NwConstants.ADD_FLOW);
213
214             //update MD-SAL DS
215             addTunnelNexthopToDS(dpnId, ipAddress, groupId);
216         } else {
217             //check update
218         }
219     }
220
221     private void makeRemoteFlow(BigInteger dpnId, String ifName, int addOrRemoveFlow) {
222         long portNo = 0;
223         String flowName = ifName;
224         String flowRef = getTunnelInterfaceFlowRef(dpnId, LPORT_INGRESS_TABLE, ifName);
225         List<MatchInfo> matches = new ArrayList<MatchInfo>();
226         List<InstructionInfo> mkInstructions = new ArrayList<InstructionInfo>();
227         if (NwConstants.ADD_FLOW == addOrRemoveFlow) {
228             portNo = interfaceManager.getPortForInterface(ifName);
229             matches.add(new MatchInfo(MatchFieldType.in_port, new BigInteger[] {
230                 dpnId, BigInteger.valueOf(portNo) }));
231             mkInstructions.add(new InstructionInfo(InstructionType.goto_table, new long[] {LFIB_TABLE}));
232         }
233
234         BigInteger COOKIE_VM_INGRESS_TABLE = new BigInteger("8000001", 16);
235         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, LPORT_INGRESS_TABLE, flowRef,
236                                                           DEFAULT_FLOW_PRIORITY, flowName, 0, 0, COOKIE_VM_INGRESS_TABLE, matches, mkInstructions);
237
238         if (NwConstants.ADD_FLOW == addOrRemoveFlow) {
239             mdsalManager.installFlow(flowEntity);
240         } else {
241             mdsalManager.removeFlow(flowEntity);
242         }
243     }
244
245     private String getTunnelInterfaceFlowRef(BigInteger dpnId, short tableId, String ifName) {
246                 return new StringBuilder().append(dpnId).append(tableId).append(ifName).toString();
247             }
248
249     protected void addVpnNexthopToDS(long vpnId, String ipPrefix, long egressPointer) {
250
251         InstanceIdentifierBuilder<VpnNexthops> idBuilder = InstanceIdentifier.builder(
252             L3nexthop.class)
253                 .child(VpnNexthops.class, new VpnNexthopsKey(vpnId));
254
255         // Add nexthop to vpn node
256         VpnNexthop nh = new VpnNexthopBuilder().
257                 setKey(new VpnNexthopKey(ipPrefix)).
258                 setIpAddress(ipPrefix).
259                 setEgressPointer(egressPointer).build();
260
261         InstanceIdentifier<VpnNexthop> id1 = idBuilder
262                 .child(VpnNexthop.class, new VpnNexthopKey(ipPrefix)).build();
263         LOG.trace("Adding vpnnextHop {} to Operational DS", nh);
264         syncWrite(LogicalDatastoreType.OPERATIONAL, id1, nh, DEFAULT_CALLBACK);
265
266     }
267
268     private void addTunnelNexthopToDS(BigInteger dpnId, String ipPrefix, long egressPointer) {
269         InstanceIdentifierBuilder<TunnelNexthops> idBuilder = InstanceIdentifier.builder(L3nexthop.class)
270                 .child(TunnelNexthops.class, new TunnelNexthopsKey(dpnId));
271
272         // Add nexthop to dpn node
273         TunnelNexthop nh = new TunnelNexthopBuilder().
274                 setKey(new TunnelNexthopKey(ipPrefix)).
275                 setIpAddress(ipPrefix).
276                 setEgressPointer(egressPointer).build();
277
278         InstanceIdentifier<TunnelNexthop> id1 = idBuilder
279                 .child(TunnelNexthop.class, new TunnelNexthopKey(ipPrefix)).build();
280         LOG.trace("Adding tunnelnextHop {} to Operational DS for a dpn node", nh);
281         asyncWrite(LogicalDatastoreType.OPERATIONAL, id1, nh, DEFAULT_CALLBACK);
282
283     }
284
285     protected VpnNexthop getVpnNexthop(long vpnId, String ipAddress, int retryCount) {
286
287         // check if vpn node is there
288         InstanceIdentifierBuilder<VpnNexthops> idBuilder =
289                         InstanceIdentifier.builder(L3nexthop.class).child(VpnNexthops.class, new VpnNexthopsKey(vpnId));
290         InstanceIdentifier<VpnNexthops> id = idBuilder.build();
291         try {
292             for (int retry = 0; retry <= retryCount; retry++) {
293                 Optional<VpnNexthops> vpnNexthops = read(LogicalDatastoreType.OPERATIONAL, id);
294                 if (vpnNexthops.isPresent()) {
295
296                     // get nexthops list for vpn
297                     List<VpnNexthop> nexthops = vpnNexthops.get().getVpnNexthop();
298                     for (VpnNexthop nexthop : nexthops) {
299                         if (nexthop.getIpAddress().equals(ipAddress)) {
300                             // return nexthop
301                             LOG.trace("VpnNextHop : {}", nexthop);
302                             return nexthop;
303                         }
304                     }
305                 }
306                 Thread.sleep(100L);
307             }
308         } catch (InterruptedException e) {
309             LOG.trace("", e);
310         }
311         // return null if not found
312         return null;
313     }
314
315     private TunnelNexthop getTunnelNexthop(BigInteger dpnId, String ipAddress) {
316         
317         InstanceIdentifierBuilder<TunnelNexthops> idBuilder = InstanceIdentifier.builder(L3nexthop.class)
318                 .child(TunnelNexthops.class, new TunnelNexthopsKey(dpnId));
319
320         // check if vpn node is there 
321         InstanceIdentifier<TunnelNexthops> id = idBuilder.build();
322         Optional<TunnelNexthops> dpnNexthops = read(LogicalDatastoreType.OPERATIONAL, id);
323         if (dpnNexthops.isPresent()) {
324             List<TunnelNexthop> nexthops = dpnNexthops.get().getTunnelNexthop();
325             for (TunnelNexthop nexthop : nexthops) {
326                 if (nexthop.getIpAddress().equals(ipAddress)) {
327                     LOG.trace("TunnelNextHop : {}",nexthop);
328                     return nexthop;
329                 }
330             }
331         }
332         return null;
333     }
334
335     public long getNextHopPointer(BigInteger dpnId, long vpnId, String prefixIp, String nextHopIp) {
336         String endpointIp = interfaceManager.getEndpointIpForDpn(dpnId);
337         if (nextHopIp.equals(endpointIp)) {
338             VpnNexthop vpnNextHop = getVpnNexthop(vpnId, prefixIp, 0);
339             return vpnNextHop.getEgressPointer();
340         } else {
341             TunnelNexthop tunnelNextHop = getTunnelNexthop(dpnId, nextHopIp);
342             LOG.trace("NExtHopPointer : {}", tunnelNextHop.getEgressPointer());
343             return tunnelNextHop.getEgressPointer();
344         }
345     }
346
347     private void removeTunnelNexthopFromDS(BigInteger dpnId, String ipPrefix) {
348
349         InstanceIdentifierBuilder<TunnelNexthop> idBuilder = InstanceIdentifier.builder(L3nexthop.class)
350                 .child(TunnelNexthops.class, new TunnelNexthopsKey(dpnId))
351                 .child(TunnelNexthop.class, new TunnelNexthopKey(ipPrefix));
352         InstanceIdentifier<TunnelNexthop> id = idBuilder.build();
353         // remove from DS     
354         LOG.trace("Removing tunnel next hop from datastore : {}", id);
355         delete(LogicalDatastoreType.OPERATIONAL, id);
356     }
357
358     private void removeVpnNexthopFromDS(long vpnId, String ipPrefix) {
359
360         InstanceIdentifierBuilder<VpnNexthop> idBuilder = InstanceIdentifier.builder(L3nexthop.class)
361                 .child(VpnNexthops.class, new VpnNexthopsKey(vpnId))
362                 .child(VpnNexthop.class, new VpnNexthopKey(ipPrefix));
363         InstanceIdentifier<VpnNexthop> id = idBuilder.build();
364         // remove from DS
365         LOG.trace("Removing vpn next hop from datastore : {}", id);
366         delete(LogicalDatastoreType.OPERATIONAL, id);
367     }
368
369  
370     public void removeLocalNextHop(BigInteger dpnId, Long vpnId, String ipAddress) {
371
372         VpnNexthop nh = getVpnNexthop(vpnId, ipAddress, 0);
373         if (nh != null) {
374             // how to inform and remove dependent FIB entries??
375             // we need to do it before the group is removed
376             GroupEntity groupEntity = MDSALUtil.buildGroupEntity(
377                     dpnId, nh.getEgressPointer(), ipAddress, GroupTypes.GroupIndirect, null);
378             // remove Group ...
379             mdsalManager.removeGroup(groupEntity);
380             //update MD-SAL DS
381             removeVpnNexthopFromDS(vpnId, ipAddress);
382         } else {
383             //throw error
384             LOG.error("removal of local next hop failed");
385         }
386
387     }
388
389     public void removeRemoteNextHop(BigInteger dpnId, String ifName, String ipAddress) {
390
391         TunnelNexthop nh = getTunnelNexthop(dpnId, ipAddress);
392         if (nh != null) {
393             // how to inform and remove dependent FIB entries??
394             // we need to do it before the group is removed
395
396             // remove Group ...
397             GroupEntity groupEntity = MDSALUtil.buildGroupEntity(
398                     dpnId, nh.getEgressPointer(), ipAddress, GroupTypes.GroupIndirect, null);
399             // remove Group ...
400             mdsalManager.removeGroup(groupEntity);
401             //makeRemoteFlow(dpnId, ifName, NwConstants.DEL_FLOW);
402             //update MD-SAL DS
403             removeTunnelNexthopFromDS(dpnId, ipAddress);
404         } else {
405             //throw error
406             LOG.error("removal of remote next hop failed : dpnid : {}, ipaddress : {}", dpnId, ipAddress);
407         }
408
409     }
410
411     @Override
412     public Future<RpcResult<GetEgressPointerOutput>> getEgressPointer(
413             GetEgressPointerInput input) {
414
415         GetEgressPointerOutputBuilder output = new GetEgressPointerOutputBuilder();
416
417         String endpointIp = interfaceManager.getEndpointIpForDpn(input.getDpnId());
418         LOG.trace("getEgressPointer: input {}, endpointIp {}", input, endpointIp);
419         if (input.getNexthopIp() == null || input.getNexthopIp().equals(endpointIp)) {
420             VpnNexthop vpnNextHop = getVpnNexthop(input.getVpnId(), input.getIpPrefix(), 5);
421             output.setEgressPointer(vpnNextHop.getEgressPointer());
422             output.setLocalDestination(true);
423         } else {
424             TunnelNexthop tunnelNextHop = getTunnelNexthop(input.getDpnId(), input.getNexthopIp());
425             output.setEgressPointer(tunnelNextHop.getEgressPointer());
426             output.setLocalDestination(false);
427         }
428
429         RpcResultBuilder<GetEgressPointerOutput> rpcResultBuilder = RpcResultBuilder.success();
430         rpcResultBuilder.withResult(output.build());
431
432         return Futures.immediateFuture(rpcResultBuilder.build());
433         
434     }
435
436     <T extends DataObject> Optional<T> read(LogicalDatastoreType datastoreType,
437             InstanceIdentifier<T> path) {
438
439         ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
440
441         Optional<T> result = Optional.absent();
442         try {
443             result = tx.read(datastoreType, path).get();
444         } catch (Exception e) {
445             throw new RuntimeException(e);
446         }
447
448         return result;
449     }
450
451     private <T extends DataObject> void asyncWrite(LogicalDatastoreType datastoreType,
452             InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
453         WriteTransaction tx = broker.newWriteOnlyTransaction();
454         tx.merge(datastoreType, path, data, true);
455         Futures.addCallback(tx.submit(), callback);
456     }
457
458     private <T extends DataObject> void syncWrite(LogicalDatastoreType datastoreType,
459             InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
460         WriteTransaction tx = broker.newWriteOnlyTransaction();
461         tx.merge(datastoreType, path, data, true);
462         tx.submit();
463     }
464
465     private <T extends DataObject> void delete(LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
466         WriteTransaction tx = broker.newWriteOnlyTransaction();
467         tx.delete(datastoreType, path);
468         Futures.addCallback(tx.submit(), DEFAULT_CALLBACK);
469     }
470
471     @Override
472     public Future<RpcResult<Void>> removeLocalNextHop(RemoveLocalNextHopInput input) {
473         VpnNexthop vpnNextHop = getVpnNexthop(input.getVpnId(), input.getIpPrefix(), 0);
474         RpcResultBuilder<Void> rpcResultBuilder;
475         LOG.debug("vpnnexthop is: {}", vpnNextHop);
476         try {
477             removeLocalNextHop(input.getDpnId(),input.getVpnId(), input.getIpPrefix());
478             rpcResultBuilder = RpcResultBuilder.success();
479         }
480         catch(Exception e){
481             LOG.error("Removal of local next hop for vpnNextHop {} failed {}" ,vpnNextHop, e);
482             rpcResultBuilder = RpcResultBuilder.failed();
483         }
484         return Futures.immediateFuture(rpcResultBuilder.build());
485     }
486
487 }