c98aa4e6d40e5322c4a16c62a1d0bdce44e3ce0c
[netvirt.git] /
1 /*
2  * Copyright (c) 2015 - 2016 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.netvirt.fibmanager;
9
10 import com.google.common.base.Optional;
11 import com.google.common.util.concurrent.CheckedFuture;
12 import com.google.common.util.concurrent.FutureCallback;
13 import com.google.common.util.concurrent.Futures;
14
15 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
16 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
17 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
18 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
19 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
20 import org.opendaylight.genius.mdsalutil.ActionInfo;
21 import org.opendaylight.genius.mdsalutil.ActionType;
22 import org.opendaylight.genius.mdsalutil.BucketInfo;
23 import org.opendaylight.genius.mdsalutil.GroupEntity;
24 import org.opendaylight.genius.mdsalutil.MDSALUtil;
25 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
26 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
27 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
28 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCase;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushVlanActionCase;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetFieldCase;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetInternalOrExternalInterfaceNameInputBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetInternalOrExternalInterfaceNameOutput;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInputBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameOutput;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInput;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInputBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceInputBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceOutput;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.L3nexthop;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.VpnNexthops;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.VpnNexthopsKey;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthop;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthopBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthopKey;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.add.group.input.buckets.bucket.action.action.NxActionResubmitRpcAddGroupCase;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionRegLoadNodesNodeTableFlowApplyActionsCase;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.load.grouping.NxRegLoad;
62 import org.opendaylight.yangtools.yang.binding.DataObject;
63 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
64 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
65 import org.opendaylight.yangtools.yang.common.RpcResult;
66 import org.slf4j.Logger;
67 import org.slf4j.LoggerFactory;
68 import org.opendaylight.genius.itm.globals.ITMConstants;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.ConfTransportTypeL3vpn;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.ConfTransportTypeL3vpnBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeGre;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeMplsOverGre;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
75
76 import java.math.BigInteger;
77 import java.util.ArrayList;
78 import java.util.List;
79 import java.util.concurrent.ExecutionException;
80 import java.util.concurrent.Future;
81
82 public class NexthopManager implements AutoCloseable {
83     private static final Logger LOG = LoggerFactory.getLogger(NexthopManager.class);
84     private final DataBroker dataBroker;
85     private final IMdsalApiManager mdsalApiManager;
86     private final OdlInterfaceRpcService interfaceManager;
87     private final ItmRpcService itmManager;
88     private final IdManagerService idManager;
89     private static final short LPORT_INGRESS_TABLE = 0;
90     private static final short LFIB_TABLE = 20;
91     private static final short FIB_TABLE = 21;
92     private static final short DEFAULT_FLOW_PRIORITY = 10;
93     private static final String NEXTHOP_ID_POOL_NAME = "nextHopPointerPool";
94     private static final long FIXED_DELAY_IN_MILLISECONDS = 4000;
95     private L3VPNTransportTypes configuredTransportTypeL3VPN = L3VPNTransportTypes.Invalid;
96     private Long waitTimeForSyncInstall;
97
98     private static final FutureCallback<Void> DEFAULT_CALLBACK =
99             new FutureCallback<Void>() {
100                 @Override
101                 public void onSuccess(Void result) {
102                     LOG.debug("Success in Datastore write operation");
103                 }
104                 @Override
105                 public void onFailure(Throwable error) {
106                     LOG.error("Error in Datastore write operation", error);
107                 };
108             };
109
110     /**
111      * Provides nexthop functions
112      * Creates group ID pool
113      *
114      * @param dataBroker - dataBroker reference
115      * @param mdsalApiManager - mdsalApiManager reference
116      * @param idManager - idManager reference
117      * @param interfaceManager - interfaceManager reference
118      * @param itmManager - itmManager reference
119      */
120     public NexthopManager(final DataBroker dataBroker,
121                           final IMdsalApiManager mdsalApiManager,
122                           final IdManagerService idManager,
123                           final OdlInterfaceRpcService interfaceManager,
124                           final ItmRpcService itmManager) {
125         this.dataBroker = dataBroker;
126         this.mdsalApiManager = mdsalApiManager;
127         this.idManager = idManager;
128         this.interfaceManager = interfaceManager;
129         this.itmManager = itmManager;
130         waitTimeForSyncInstall = Long.getLong("wait.time.sync.install");
131         if (waitTimeForSyncInstall == null) {
132             waitTimeForSyncInstall = 1000L;
133         }
134
135         createIdPool();
136     }
137
138     private void createIdPool() {
139         CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
140                 .setPoolName(NEXTHOP_ID_POOL_NAME)
141                 .setLow(150000L)
142                 .setHigh(175000L)
143                 .build();
144         try {
145             Future<RpcResult<Void>> result = idManager.createIdPool(createPool);
146             if ((result != null) && (result.get().isSuccessful())) {
147                 LOG.info("Created IdPool for NextHopPointerPool");
148             }
149         } catch (InterruptedException | ExecutionException e) {
150             LOG.error("Failed to create idPool for NextHopPointerPool",e);
151         }
152     }
153
154     private BigInteger getDpnId(String ofPortId) {
155         String[] fields = ofPortId.split(":");
156         BigInteger dpn = new BigInteger(fields[1]);
157         LOG.debug("DpnId: {}", dpn);
158         return dpn;
159     }
160
161     private String getNextHopKey(long vpnId, String ipAddress){
162         String nhKey = new String("nexthop." + vpnId + ipAddress);
163         return nhKey;
164     }
165
166     private String getNextHopKey(String ifName, String ipAddress){
167         String nhKey = new String("nexthop." + ifName + ipAddress);
168         return nhKey;
169     }
170
171     protected long createNextHopPointer(String nexthopKey) {
172         AllocateIdInput getIdInput = new AllocateIdInputBuilder()
173                 .setPoolName(NEXTHOP_ID_POOL_NAME).setIdKey(nexthopKey)
174                 .build();
175         //TODO: Proper error handling once IdManager code is complete
176         try {
177             Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
178             RpcResult<AllocateIdOutput> rpcResult = result.get();
179             return rpcResult.getResult().getIdValue();
180         } catch (NullPointerException | InterruptedException | ExecutionException e) {
181             LOG.trace("",e);
182         }
183         return 0;
184     }
185
186     protected void removeNextHopPointer(String nexthopKey) {
187         ReleaseIdInput idInput = new ReleaseIdInputBuilder().
188                 setPoolName(NEXTHOP_ID_POOL_NAME)
189                 .setIdKey(nexthopKey).build();
190         try {
191             Future<RpcResult<Void>> result = idManager.releaseId(idInput);
192             RpcResult<Void> rpcResult = result.get();
193             if(!rpcResult.isSuccessful()) {
194                 LOG.warn("RPC Call to Get Unique Id returned with Errors {}", rpcResult.getErrors());
195             }
196         } catch (InterruptedException | ExecutionException e) {
197             LOG.warn("Exception when getting Unique Id for key {}", nexthopKey, e);
198         }
199     }
200
201     protected List<ActionInfo> getEgressActionsForInterface(String ifName) {
202         List<ActionInfo> listActionInfo = new ArrayList<ActionInfo>();
203         try {
204             Future<RpcResult<GetEgressActionsForInterfaceOutput>> result =
205                     interfaceManager.getEgressActionsForInterface(
206                             new GetEgressActionsForInterfaceInputBuilder().setIntfName(ifName).build());
207             RpcResult<GetEgressActionsForInterfaceOutput> rpcResult = result.get();
208             if(!rpcResult.isSuccessful()) {
209                 LOG.warn("RPC Call to Get egress actions for interface {} returned with Errors {}", ifName, rpcResult.getErrors());
210             } else {
211                 List<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action> actions =
212                         rpcResult.getResult().getAction();
213                 for (Action action : actions) {
214                     org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action actionClass = action.getAction();
215                     if (actionClass instanceof OutputActionCase) {
216                         listActionInfo.add(new ActionInfo(ActionType.output,
217                                 new String[] {((OutputActionCase)actionClass).getOutputAction()
218                                         .getOutputNodeConnector().getValue()}));
219                     } else if (actionClass instanceof PushVlanActionCase) {
220                         listActionInfo.add(new ActionInfo(ActionType.push_vlan, new String[] {}));
221                     } else if (actionClass instanceof SetFieldCase) {
222                         if (((SetFieldCase)actionClass).getSetField().getVlanMatch() != null) {
223                             int vlanVid = ((SetFieldCase)actionClass).getSetField().getVlanMatch().getVlanId().getVlanId().getValue();
224                             listActionInfo.add(new ActionInfo(ActionType.set_field_vlan_vid,
225                                     new String[] { Long.toString(vlanVid) }));
226                         }
227                     } else if (actionClass instanceof NxActionResubmitRpcAddGroupCase) {
228                         Short tableId = ((NxActionResubmitRpcAddGroupCase)actionClass).getNxResubmit().getTable();
229                         listActionInfo.add(new ActionInfo(ActionType.nx_resubmit,
230                             new String[] { tableId.toString() }, action.getKey().getOrder() + 1));
231                     } else if (actionClass instanceof NxActionRegLoadNodesNodeTableFlowApplyActionsCase) {
232                         NxRegLoad nxRegLoad =
233                             ((NxActionRegLoadNodesNodeTableFlowApplyActionsCase)actionClass).getNxRegLoad();
234                         listActionInfo.add(new ActionInfo(ActionType.nx_load_reg_6,
235                             new String[] { nxRegLoad.getDst().getStart().toString(),
236                                 nxRegLoad.getDst().getEnd().toString(),
237                                 nxRegLoad.getValue().toString(10)}, action.getKey().getOrder() + 1));
238                     }
239                 }
240             }
241         } catch (InterruptedException | ExecutionException e) {
242             LOG.warn("Exception when egress actions for interface {}", ifName, e);
243         }
244         return listActionInfo;
245     }
246
247     protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
248         Class<? extends TunnelTypeBase> tunType = getReqTunType(getReqTransType().toUpperCase());
249         Future<RpcResult<GetTunnelInterfaceNameOutput>> result;
250         try {
251             result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
252                     .setSourceDpid(srcDpId)
253                     .setDestinationDpid(dstDpId)
254                     .setTunnelType(tunType)
255                     .build());
256             RpcResult<GetTunnelInterfaceNameOutput> rpcResult = result.get();
257             if(!rpcResult.isSuccessful()) {
258                 LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
259             } else {
260                 return rpcResult.getResult().getInterfaceName();
261             }
262         } catch (InterruptedException | ExecutionException e) {
263             LOG.warn("Exception when getting tunnel interface Id for tunnel between {} and  {}", srcDpId, dstDpId, e);
264         }
265         return null;
266     }
267
268     protected String getTunnelInterfaceName(BigInteger srcDpId, org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress dstIp) {
269         Class<? extends TunnelTypeBase> tunType = getReqTunType(getReqTransType().toUpperCase());
270         Future<RpcResult<GetInternalOrExternalInterfaceNameOutput>> result;
271         try {
272             result = itmManager.getInternalOrExternalInterfaceName(new GetInternalOrExternalInterfaceNameInputBuilder()
273                     .setSourceDpid(srcDpId)
274                     .setDestinationIp(dstIp)
275                     .setTunnelType(tunType)
276                     .build());
277             RpcResult<GetInternalOrExternalInterfaceNameOutput> rpcResult = result.get();
278             if(!rpcResult.isSuccessful()) {
279                 LOG.warn("RPC Call to getTunnelInterfaceName returned with Errors {}", rpcResult.getErrors());
280             } else {
281                 return rpcResult.getResult().getInterfaceName();
282             }
283         } catch (InterruptedException | ExecutionException e) {
284             LOG.warn("Exception when getting tunnel interface Id for tunnel between {} and  {}", srcDpId, dstIp, e);
285         }
286         return null;
287     }
288
289     public long createLocalNextHop(long vpnId, BigInteger dpnId,
290                                    String ifName, String ipAddress) {
291         long groupId = createNextHopPointer(getNextHopKey(vpnId, ipAddress));
292         String nextHopLockStr = new String(vpnId + ipAddress);
293         synchronized (nextHopLockStr.intern()) {
294             VpnNexthop nexthop = getVpnNexthop(vpnId, ipAddress);
295             LOG.trace("nexthop: {} retrieved for vpnId {}, prefix {}, ifName {} on dpn {}", nexthop,
296                     vpnId, ipAddress, ifName, dpnId);
297             if (nexthop == null) {
298                 Optional<Adjacency> adjacencyData =
299                         read(LogicalDatastoreType.OPERATIONAL, getAdjacencyIdentifier(ifName, ipAddress));
300                 String macAddress = adjacencyData.isPresent() ? adjacencyData.get().getMacAddress() : null;
301                 List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
302                 List<ActionInfo> listActionInfo = new ArrayList<>();
303                 // MAC re-write
304                 if (macAddress != null) {
305                     int actionKey = listActionInfo.size();
306                     listActionInfo.add(new ActionInfo(ActionType.set_field_eth_dest,
307                         new String[]{macAddress}, actionKey));
308                     //listActionInfo.add(0, new ActionInfo(ActionType.pop_mpls, new String[]{}));
309                 } else {
310                     //FIXME: Log message here.
311                     LOG.debug("mac address for new local nexthop is null");
312                 }
313                 listActionInfo.addAll(getEgressActionsForInterface(ifName));
314                 BucketInfo bucket = new BucketInfo(listActionInfo);
315
316                 listBucketInfo.add(bucket);
317                 GroupEntity groupEntity = MDSALUtil.buildGroupEntity(
318                         dpnId, groupId, ipAddress, GroupTypes.GroupAll, listBucketInfo);
319                 LOG.trace("Install LNH Group: id {}, mac address {}, interface {} for prefix {}", groupId, macAddress, ifName, ipAddress);
320
321                 // install Group
322                 mdsalApiManager.syncInstallGroup(groupEntity, FIXED_DELAY_IN_MILLISECONDS);
323                 try{
324                     LOG.info("Sleeping for {} to wait for the groups to get programmed.", waitTimeForSyncInstall);
325                     Thread.sleep(waitTimeForSyncInstall);
326                 }catch(InterruptedException error){
327                     LOG.warn("Error while waiting for group {} to install.", groupId);
328                     LOG.debug("{}", error);
329                 }
330                 //update MD-SAL DS
331                 addVpnNexthopToDS(dpnId, vpnId, ipAddress, groupId);
332
333             } else {
334                 //nexthop exists already; a new flow is going to point to it, increment the flowrefCount by 1
335                 int flowrefCnt = nexthop.getFlowrefCount() + 1;
336                 VpnNexthop nh = new VpnNexthopBuilder().setKey(new VpnNexthopKey(ipAddress)).setFlowrefCount(flowrefCnt).build();
337                 LOG.trace("Updating vpnnextHop {} for refCount {} to Operational DS", nh, flowrefCnt);
338                 syncWrite(LogicalDatastoreType.OPERATIONAL, getVpnNextHopIdentifier(vpnId, ipAddress), nh, DEFAULT_CALLBACK);
339
340             }
341         }
342         return groupId;
343     }
344
345     protected void addVpnNexthopToDS(BigInteger dpnId, long vpnId, String ipPrefix, long egressPointer) {
346
347         InstanceIdentifierBuilder<VpnNexthops> idBuilder = InstanceIdentifier.builder(
348                 L3nexthop.class)
349                 .child(VpnNexthops.class, new VpnNexthopsKey(vpnId));
350
351         // Add nexthop to vpn node
352         VpnNexthop nh = new VpnNexthopBuilder().
353                 setKey(new VpnNexthopKey(ipPrefix)).
354                 setDpnId(dpnId).
355                 setIpAddress(ipPrefix).
356                 setFlowrefCount(1).
357                 setEgressPointer(egressPointer).build();
358
359         InstanceIdentifier<VpnNexthop> id1 = idBuilder
360                 .child(VpnNexthop.class, new VpnNexthopKey(ipPrefix)).build();
361         LOG.trace("Adding vpnnextHop {} to Operational DS", nh);
362         syncWrite(LogicalDatastoreType.OPERATIONAL, id1, nh, DEFAULT_CALLBACK);
363
364     }
365
366     protected InstanceIdentifier<VpnNexthop> getVpnNextHopIdentifier(long vpnId, String ipAddress) {
367         InstanceIdentifier<VpnNexthop> id = InstanceIdentifier.builder(
368                 L3nexthop.class)
369                 .child(VpnNexthops.class, new VpnNexthopsKey(vpnId)).child(VpnNexthop.class, new VpnNexthopKey(ipAddress)).build();
370         return id;
371     }
372
373     protected VpnNexthop getVpnNexthop(long vpnId, String ipAddress) {
374
375         // check if vpn node is there
376         InstanceIdentifierBuilder<VpnNexthops> idBuilder =
377                 InstanceIdentifier.builder(L3nexthop.class).child(VpnNexthops.class,
378                         new VpnNexthopsKey(vpnId));
379         InstanceIdentifier<VpnNexthops> id = idBuilder.build();
380         Optional<VpnNexthops> vpnNexthops = read(LogicalDatastoreType.OPERATIONAL, id);
381         if (vpnNexthops.isPresent()) {
382             // get nexthops list for vpn
383             List<VpnNexthop> nexthops = vpnNexthops.get().getVpnNexthop();
384             for (VpnNexthop nexthop : nexthops) {
385                 if (nexthop.getIpAddress().equals(ipAddress)) {
386                     // return nexthop
387                     LOG.trace("VpnNextHop : {}", nexthop);
388                     return nexthop;
389                 }
390             }
391             // return null if not found
392         }
393         return null;
394     }
395
396     public String getRemoteNextHopPointer(BigInteger remoteDpnId, long vpnId, String prefixIp, String nextHopIp) {
397         String tunnelIfName = null;
398         LOG.trace("getRemoteNextHopPointer: input [remoteDpnId {}, vpnId {}, prefixIp {}, nextHopIp {} ]",
399                 remoteDpnId, vpnId, prefixIp, nextHopIp);
400
401         if (nextHopIp != null && !nextHopIp.isEmpty()) {
402             try{
403                 // here use the config for tunnel type param
404                 tunnelIfName = getTunnelInterfaceName(remoteDpnId, org.opendaylight.yang.gen.v1.urn.ietf.params.xml
405                         .ns.yang.ietf.inet.types.rev130715.IpAddressBuilder.getDefaultInstance(nextHopIp));
406             } catch(Exception ex){
407                 LOG.error("Error while retrieving nexthop pointer for nexthop {} : ", nextHopIp, ex);
408             }
409         }
410         return tunnelIfName;
411     }
412
413     public BigInteger getDpnForPrefix(long vpnId, String prefixIp) {
414         VpnNexthop vpnNexthop = getVpnNexthop(vpnId, prefixIp);
415         BigInteger localDpnId = (vpnNexthop == null) ? null : vpnNexthop.getDpnId();
416         return localDpnId;
417     }
418
419     private void removeVpnNexthopFromDS(long vpnId, String ipPrefix) {
420
421         InstanceIdentifierBuilder<VpnNexthop> idBuilder = InstanceIdentifier.builder(L3nexthop.class)
422                 .child(VpnNexthops.class, new VpnNexthopsKey(vpnId))
423                 .child(VpnNexthop.class, new VpnNexthopKey(ipPrefix));
424         InstanceIdentifier<VpnNexthop> id = idBuilder.build();
425         // remove from DS
426         LOG.trace("Removing vpn next hop from datastore : {}", id);
427         syncDelete(LogicalDatastoreType.OPERATIONAL, id);
428     }
429
430     public void removeLocalNextHop(BigInteger dpnId, Long vpnId, String ipAddress) {
431
432         String nextHopLockStr = new String(vpnId + ipAddress);
433         synchronized (nextHopLockStr.intern()) {
434             VpnNexthop nh = getVpnNexthop(vpnId, ipAddress);
435             if (nh != null) {
436                 int newFlowrefCnt = nh.getFlowrefCount() - 1;
437                 if (newFlowrefCnt == 0) { //remove the group only if there are no more flows using this group
438                     GroupEntity groupEntity = MDSALUtil.buildGroupEntity(
439                             dpnId, nh.getEgressPointer(), ipAddress, GroupTypes.GroupAll, null);
440                     // remove Group ...
441                     mdsalApiManager.removeGroup(groupEntity);
442                     //update MD-SAL DS
443                     removeVpnNexthopFromDS(vpnId, ipAddress);
444                     //release groupId
445                     removeNextHopPointer(getNextHopKey(vpnId, ipAddress));
446                     LOG.debug("Local Next hop {} for {} {} on dpn {} successfully deleted", nh.getEgressPointer(), vpnId, ipAddress, dpnId);
447                 } else {
448                     //just update the flowrefCount of the vpnNexthop
449                     VpnNexthop currNh = new VpnNexthopBuilder().setKey(new VpnNexthopKey(ipAddress)).setFlowrefCount(newFlowrefCnt).build();
450                     LOG.trace("Updating vpnnextHop {} for refCount {} to Operational DS", currNh, newFlowrefCnt);
451                     syncWrite(LogicalDatastoreType.OPERATIONAL, getVpnNextHopIdentifier(vpnId, ipAddress), currNh, DEFAULT_CALLBACK);
452                 }
453             } else {
454                 //throw error
455                 LOG.error("Local Next hop for {} on dpn {} not deleted", ipAddress, dpnId);
456             }
457         }
458
459     }
460
461
462     private <T extends DataObject> Optional<T> read(LogicalDatastoreType datastoreType,
463                                                     InstanceIdentifier<T> path) {
464
465         ReadOnlyTransaction tx = dataBroker.newReadOnlyTransaction();
466
467         Optional<T> result = Optional.absent();
468         try {
469             result = tx.read(datastoreType, path).get();
470         } catch (Exception e) {
471             throw new RuntimeException(e);
472         }
473
474         return result;
475     }
476
477     private <T extends DataObject> void asyncWrite(LogicalDatastoreType datastoreType,
478                                                    InstanceIdentifier<T> path, T data,
479                                                    FutureCallback<Void> callback) {
480         WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
481         tx.merge(datastoreType, path, data, true);
482         Futures.addCallback(tx.submit(), callback);
483     }
484
485     private <T extends DataObject> void syncWrite(LogicalDatastoreType datastoreType,
486                                                   InstanceIdentifier<T> path, T data,
487                                                   FutureCallback<Void> callback) {
488         WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
489         tx.merge(datastoreType, path, data, true);
490         CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
491         try {
492             futures.get();
493         } catch (InterruptedException | ExecutionException e) {
494             LOG.error("Error writing to datastore (path, data) : ({}, {})", path, data, e);
495             throw new RuntimeException(e.getMessage());
496         }
497     }
498
499     private <T extends DataObject> void syncDelete(LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
500         WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
501         tx.delete(datastoreType, path);
502         CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
503         try {
504             futures.get();
505         } catch (InterruptedException | ExecutionException e) {
506             LOG.error("Error deleting from datastore (path) : ({})", path, e);
507             throw new RuntimeException(e.getMessage());
508         }
509     }
510
511     private InstanceIdentifier<Adjacency> getAdjacencyIdentifier(String vpnInterfaceName, String ipAddress) {
512         return InstanceIdentifier.builder(VpnInterfaces.class)
513                 .child(VpnInterface.class, new VpnInterfaceKey(vpnInterfaceName)).augmentation(
514                         Adjacencies.class).child(Adjacency.class, new AdjacencyKey(ipAddress)).build();
515     }
516
517     InstanceIdentifier<Adjacencies> getAdjListPath(String vpnInterfaceName) {
518         return InstanceIdentifier.builder(VpnInterfaces.class)
519                 .child(VpnInterface.class, new VpnInterfaceKey(vpnInterfaceName)).augmentation(
520                         Adjacencies.class).build();
521     }
522
523     public void setConfTransType(String service,String transportType) {
524
525         if (!service.toUpperCase().equals("L3VPN")) {
526             System.out.println("Please provide a valid service name. Available value(s): L3VPN");
527             LOG.error("Incorrect service {} provided for setting the transport type.", service);
528             return;
529         }
530
531         L3VPNTransportTypes transType = L3VPNTransportTypes.validateTransportType(transportType.toUpperCase());
532
533         if (transType != L3VPNTransportTypes.Invalid) {
534             configuredTransportTypeL3VPN = transType;
535         }
536     }
537
538     public void writeConfTransTypeConfigDS() {
539         FibUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, getConfTransportTypeIdentifier(),
540                 createConfTransportType(configuredTransportTypeL3VPN.getTransportType()),
541                 FibUtil.DEFAULT_CALLBACK);
542     }
543
544     public L3VPNTransportTypes getConfiguredTransportTypeL3VPN() {
545         return this.configuredTransportTypeL3VPN;
546     }
547
548     public String getReqTransType() {
549         if (configuredTransportTypeL3VPN == L3VPNTransportTypes.Invalid) {
550             /*
551             * Restart scenario, Read from the ConfigDS.
552             * if the value is Unset, cache value as VxLAN.
553             */
554             LOG.trace("configureTransportType is not yet set.");
555             Optional<ConfTransportTypeL3vpn>  configuredTransTypeFromConfig =
556                     FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, getConfTransportTypeIdentifier());
557
558             if (configuredTransTypeFromConfig.isPresent()) {
559                 if (configuredTransTypeFromConfig.get().getTransportType().equals(TunnelTypeGre.class)) {
560                     configuredTransportTypeL3VPN.setL3VPNTransportTypes(ITMConstants.TUNNEL_TYPE_GRE);
561                 } else {
562                     configuredTransportTypeL3VPN.setL3VPNTransportTypes(ITMConstants.TUNNEL_TYPE_VXLAN);
563                 }
564                 LOG.trace("configuredTransportType set from config DS to " + getConfiguredTransportTypeL3VPN().getTransportType());
565             } else {
566                 setConfTransType("L3VPN", L3VPNTransportTypes.VxLAN.getTransportType());
567                 LOG.trace("configuredTransportType is not set in the Config DS. VxLAN as default will be used.");
568             }
569         } else {
570             LOG.trace("configuredTransportType is set as {}", getConfiguredTransportTypeL3VPN().getTransportType());
571         }
572         return getConfiguredTransportTypeL3VPN().getTransportType();
573     }
574     public InstanceIdentifier<ConfTransportTypeL3vpn> getConfTransportTypeIdentifier() {
575         return InstanceIdentifier.builder(ConfTransportTypeL3vpn.class).build();
576     }
577
578     private ConfTransportTypeL3vpn createConfTransportType (String type) {
579         ConfTransportTypeL3vpn confTransType;
580         if (type.equals(ITMConstants.TUNNEL_TYPE_GRE)) {
581             confTransType = new ConfTransportTypeL3vpnBuilder().setTransportType(TunnelTypeGre.class).build();
582             LOG.trace("Setting the confTransportType to GRE.");
583         } else if (type.equals(ITMConstants.TUNNEL_TYPE_VXLAN)) {
584             confTransType = new ConfTransportTypeL3vpnBuilder().setTransportType(TunnelTypeVxlan.class).build();
585             LOG.trace("Setting the confTransportType to VxLAN.");
586         } else {
587             LOG.trace("Invalid transport type {} passed to Config DS ", type);
588             confTransType = null;
589         }
590         return  confTransType;
591     }
592
593     public Class<? extends TunnelTypeBase> getReqTunType(String transportType) {
594         if (transportType.equals("VXLAN")) {
595             return TunnelTypeVxlan.class;
596         } else if (transportType.equals("GRE")) {
597             return TunnelTypeGre.class;
598         } else {
599             return TunnelTypeMplsOverGre.class;
600         }
601     }
602
603     public String getTransportTypeStr ( String tunType) {
604         if (tunType.equals(TunnelTypeVxlan.class.toString())) {
605             return ITMConstants.TUNNEL_TYPE_VXLAN;
606         } else if (tunType.equals(TunnelTypeGre.class.toString())) {
607             return ITMConstants.TUNNEL_TYPE_GRE;
608         } else if (tunType.equals(TunnelTypeMplsOverGre.class.toString())){
609             return ITMConstants.TUNNEL_TYPE_MPLSoGRE;
610         } else {
611             return ITMConstants.TUNNEL_TYPE_INVALID;
612         }
613     }
614
615     @Override
616     public void close() throws Exception {
617         LOG.info("{} close", getClass().getSimpleName());
618     }
619 }