2 * Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
8 package org.opendaylight.netvirt.fibmanager;
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 import java.math.BigInteger;
15 import java.util.ArrayList;
16 import java.util.List;
17 import java.util.concurrent.ExecutionException;
18 import java.util.concurrent.Future;
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
21 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
22 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
23 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
24 import org.opendaylight.genius.itm.globals.ITMConstants;
25 import org.opendaylight.genius.mdsalutil.ActionInfo;
26 import org.opendaylight.genius.mdsalutil.BucketInfo;
27 import org.opendaylight.genius.mdsalutil.GroupEntity;
28 import org.opendaylight.genius.mdsalutil.MDSALUtil;
29 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
30 import org.opendaylight.genius.mdsalutil.actions.ActionOutput;
31 import org.opendaylight.genius.mdsalutil.actions.ActionPushVlan;
32 import org.opendaylight.genius.mdsalutil.actions.ActionRegLoad;
33 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldEthernetDestination;
34 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldVlanVid;
35 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
36 import org.opendaylight.netvirt.elanmanager.api.IElanService;
37 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
38 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
39 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.L2vlan;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType;
43 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCase;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushVlanActionCase;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetFieldCase;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInput;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInputBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeGre;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeMplsOverGre;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceInputBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceOutput;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetInternalOrExternalInterfaceNameInputBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetInternalOrExternalInterfaceNameOutput;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInputBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameOutput;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.SegmentTypeBase;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.SegmentTypeFlat;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.SegmentTypeVlan;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.L3nexthop;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.VpnNexthops;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.VpnNexthopsKey;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthop;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthopBuilder;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthopKey;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.ConfTransportTypeL3vpn;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.ConfTransportTypeL3vpnBuilder;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyKey;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg6;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.add.group.input.buckets.bucket.action.action.NxActionResubmitRpcAddGroupCase;
88 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;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.load.grouping.NxRegLoad;
90 import org.opendaylight.yangtools.yang.binding.DataObject;
91 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
92 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
93 import org.opendaylight.yangtools.yang.common.RpcResult;
94 import org.slf4j.Logger;
95 import org.slf4j.LoggerFactory;
97 public class NexthopManager implements AutoCloseable {
98 private static final Logger LOG = LoggerFactory.getLogger(NexthopManager.class);
99 private final DataBroker dataBroker;
100 private final IMdsalApiManager mdsalApiManager;
101 private final OdlInterfaceRpcService interfaceManager;
102 private final ItmRpcService itmManager;
103 private final IdManagerService idManager;
104 private final IElanService elanService;
105 private static final short LPORT_INGRESS_TABLE = 0;
106 private static final short LFIB_TABLE = 20;
107 private static final short FIB_TABLE = 21;
108 private static final short DEFAULT_FLOW_PRIORITY = 10;
109 private static final String NEXTHOP_ID_POOL_NAME = "nextHopPointerPool";
110 private static final long FIXED_DELAY_IN_MILLISECONDS = 4000;
111 private L3VPNTransportTypes configuredTransportTypeL3VPN = L3VPNTransportTypes.Invalid;
112 private Long waitTimeForSyncInstall;
114 private static final FutureCallback<Void> DEFAULT_CALLBACK =
115 new FutureCallback<Void>() {
117 public void onSuccess(Void result) {
118 LOG.debug("Success in Datastore write operation");
122 public void onFailure(Throwable error) {
123 LOG.error("Error in Datastore write operation", error);
130 * Provides nexthop functions.
131 * Creates group ID pool
133 * @param dataBroker - dataBroker reference
134 * @param mdsalApiManager - mdsalApiManager reference
135 * @param idManager - idManager reference
136 * @param interfaceManager - interfaceManager reference
137 * @param itmManager - itmManager reference
139 public NexthopManager(final DataBroker dataBroker,
140 final IMdsalApiManager mdsalApiManager,
141 final IdManagerService idManager,
142 final OdlInterfaceRpcService interfaceManager,
143 final ItmRpcService itmManager,
144 final IElanService elanService) {
145 this.dataBroker = dataBroker;
146 this.mdsalApiManager = mdsalApiManager;
147 this.idManager = idManager;
148 this.interfaceManager = interfaceManager;
149 this.itmManager = itmManager;
150 this.elanService = elanService;
151 waitTimeForSyncInstall = Long.getLong("wait.time.sync.install");
152 if (waitTimeForSyncInstall == null) {
153 waitTimeForSyncInstall = 1000L;
159 private void createIdPool() {
160 CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
161 .setPoolName(NEXTHOP_ID_POOL_NAME)
166 Future<RpcResult<Void>> result = idManager.createIdPool(createPool);
167 if ((result != null) && (result.get().isSuccessful())) {
168 LOG.info("Created IdPool for NextHopPointerPool");
170 } catch (InterruptedException | ExecutionException e) {
171 LOG.error("Failed to create idPool for NextHopPointerPool", e);
175 private BigInteger getDpnId(String ofPortId) {
176 String[] fields = ofPortId.split(":");
177 BigInteger dpn = new BigInteger(fields[1]);
178 LOG.debug("DpnId: {}", dpn);
182 private String getNextHopKey(long vpnId, String ipAddress) {
183 String nhKey = new String("nexthop." + vpnId + ipAddress);
187 private String getNextHopKey(String ifName, String ipAddress) {
188 String nhKey = new String("nexthop." + ifName + ipAddress);
192 protected long createNextHopPointer(String nexthopKey) {
193 AllocateIdInput getIdInput = new AllocateIdInputBuilder()
194 .setPoolName(NEXTHOP_ID_POOL_NAME).setIdKey(nexthopKey)
196 //TODO: Proper error handling once IdManager code is complete
198 Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
199 RpcResult<AllocateIdOutput> rpcResult = result.get();
200 return rpcResult.getResult().getIdValue();
201 } catch (NullPointerException | InterruptedException | ExecutionException e) {
207 protected void removeNextHopPointer(String nexthopKey) {
208 ReleaseIdInput idInput = new ReleaseIdInputBuilder()
209 .setPoolName(NEXTHOP_ID_POOL_NAME)
210 .setIdKey(nexthopKey).build();
212 Future<RpcResult<Void>> result = idManager.releaseId(idInput);
213 RpcResult<Void> rpcResult = result.get();
214 if (!rpcResult.isSuccessful()) {
215 LOG.warn("RPC Call to Get Unique Id returned with Errors {}", rpcResult.getErrors());
217 } catch (InterruptedException | ExecutionException e) {
218 LOG.warn("Exception when getting Unique Id for key {}", nexthopKey, e);
222 protected List<ActionInfo> getEgressActionsForInterface(String ifName) {
223 List<ActionInfo> listActionInfo = new ArrayList<>();
225 Future<RpcResult<GetEgressActionsForInterfaceOutput>> result =
226 interfaceManager.getEgressActionsForInterface(
227 new GetEgressActionsForInterfaceInputBuilder().setIntfName(ifName).build());
228 RpcResult<GetEgressActionsForInterfaceOutput> rpcResult = result.get();
229 if (!rpcResult.isSuccessful()) {
230 LOG.warn("RPC Call to Get egress actions for interface {} returned with Errors {}",
231 ifName, rpcResult.getErrors());
233 List<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action> actions =
234 rpcResult.getResult().getAction();
235 for (Action action : actions) {
236 org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action
237 actionClass = action.getAction();
238 if (actionClass instanceof OutputActionCase) {
239 listActionInfo.add(new ActionOutput(
240 ((OutputActionCase) actionClass).getOutputAction().getOutputNodeConnector()));
241 } else if (actionClass instanceof PushVlanActionCase) {
242 listActionInfo.add(new ActionPushVlan());
243 } else if (actionClass instanceof SetFieldCase) {
244 if (((SetFieldCase) actionClass).getSetField().getVlanMatch() != null) {
245 int vlanVid = ((SetFieldCase) actionClass).getSetField().getVlanMatch()
246 .getVlanId().getVlanId().getValue();
247 listActionInfo.add(new ActionSetFieldVlanVid(vlanVid));
249 } else if (actionClass instanceof NxActionResubmitRpcAddGroupCase) {
250 Short tableId = ((NxActionResubmitRpcAddGroupCase) actionClass).getNxResubmit().getTable();
251 listActionInfo.add(new ActionNxResubmit(action.getKey().getOrder() + 1, tableId));
252 } else if (actionClass instanceof NxActionRegLoadNodesNodeTableFlowApplyActionsCase) {
253 NxRegLoad nxRegLoad =
254 ((NxActionRegLoadNodesNodeTableFlowApplyActionsCase) actionClass).getNxRegLoad();
255 listActionInfo.add(new ActionRegLoad(action.getKey().getOrder() + 1, NxmNxReg6.class,
256 nxRegLoad.getDst().getStart(), nxRegLoad.getDst().getEnd(),
257 nxRegLoad.getValue().longValue()));
261 } catch (InterruptedException | ExecutionException e) {
262 LOG.warn("Exception when egress actions for interface {}", ifName, e);
264 return listActionInfo;
267 protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
268 Class<? extends TunnelTypeBase> tunType = getReqTunType(getReqTransType().toUpperCase());
269 Future<RpcResult<GetTunnelInterfaceNameOutput>> result;
271 result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
272 .setSourceDpid(srcDpId)
273 .setDestinationDpid(dstDpId)
274 .setTunnelType(tunType)
276 RpcResult<GetTunnelInterfaceNameOutput> rpcResult = result.get();
277 if (!rpcResult.isSuccessful()) {
278 LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
280 return rpcResult.getResult().getInterfaceName();
282 } catch (InterruptedException | ExecutionException e) {
283 LOG.warn("Exception when getting tunnel interface Id for tunnel between {} and {}", srcDpId, dstDpId, e);
288 protected String getTunnelInterfaceName(BigInteger srcDpId, org.opendaylight.yang.gen.v1.urn.ietf.params
289 .xml.ns.yang.ietf.inet.types.rev130715.IpAddress dstIp) {
290 Class<? extends TunnelTypeBase> tunType = getReqTunType(getReqTransType().toUpperCase());
291 Future<RpcResult<GetInternalOrExternalInterfaceNameOutput>> result;
293 result = itmManager.getInternalOrExternalInterfaceName(new GetInternalOrExternalInterfaceNameInputBuilder()
294 .setSourceDpid(srcDpId)
295 .setDestinationIp(dstIp)
296 .setTunnelType(tunType)
298 RpcResult<GetInternalOrExternalInterfaceNameOutput> rpcResult = result.get();
299 if (!rpcResult.isSuccessful()) {
300 LOG.warn("RPC Call to getTunnelInterfaceName returned with Errors {}", rpcResult.getErrors());
302 return rpcResult.getResult().getInterfaceName();
304 } catch (InterruptedException | ExecutionException e) {
305 LOG.warn("Exception when getting tunnel interface Id for tunnel between {} and {}", srcDpId, dstIp, e);
310 public long createLocalNextHop(long vpnId, BigInteger dpnId,
311 String ifName, String ipNextHopAddress, String ipPrefixAddress) {
312 String macAddress = FibUtil.getMacAddressFromPrefix(dataBroker, ifName, ipPrefixAddress);
313 String ipAddress = (macAddress != null) ? ipPrefixAddress : ipNextHopAddress;
315 long groupId = createNextHopPointer(getNextHopKey(vpnId, ipAddress));
317 LOG.error("Unable to allocate groupId for vpnId {} , prefix {}", vpnId, ipAddress);
320 String nextHopLockStr = new String(vpnId + ipAddress);
321 synchronized (nextHopLockStr.intern()) {
322 VpnNexthop nexthop = getVpnNexthop(vpnId, ipAddress);
323 LOG.trace("nexthop: {} retrieved for vpnId {}, prefix {}, ifName {} on dpn {}", nexthop,
324 vpnId, ipAddress, ifName, dpnId);
325 if (nexthop == null) {
326 if (macAddress == null) {
327 macAddress = FibUtil.getMacAddressFromPrefix(dataBroker, ifName, ipAddress);
329 List<BucketInfo> listBucketInfo = new ArrayList<>();
330 List<ActionInfo> listActionInfo = new ArrayList<>();
332 if (macAddress != null) {
333 int actionKey = listActionInfo.size();
334 listActionInfo.add(new ActionSetFieldEthernetDestination(actionKey, new MacAddress(macAddress)));
335 //listActionInfo.add(0, new ActionPopMpls());
337 //FIXME: Log message here.
338 LOG.debug("mac address for new local nexthop is null");
340 listActionInfo.addAll(getEgressActionsForInterface(ifName));
341 BucketInfo bucket = new BucketInfo(listActionInfo);
343 listBucketInfo.add(bucket);
344 GroupEntity groupEntity = MDSALUtil.buildGroupEntity(
345 dpnId, groupId, ipAddress, GroupTypes.GroupAll, listBucketInfo);
346 LOG.trace("Install LNH Group: id {}, mac address {}, interface {} for prefix {}",
347 groupId, macAddress, ifName, ipAddress);
350 mdsalApiManager.syncInstallGroup(groupEntity, FIXED_DELAY_IN_MILLISECONDS);
352 LOG.info("Sleeping for {} to wait for the groups to get programmed.", waitTimeForSyncInstall);
353 Thread.sleep(waitTimeForSyncInstall);
354 } catch (InterruptedException error) {
355 LOG.warn("Error while waiting for group {} to install.", groupId);
356 LOG.debug("{}", error);
359 addVpnNexthopToDS(dpnId, vpnId, ipAddress, groupId);
362 //nexthop exists already; a new flow is going to point to it, increment the flowrefCount by 1
363 int flowrefCnt = nexthop.getFlowrefCount() + 1;
364 VpnNexthop nh = new VpnNexthopBuilder().setKey(new VpnNexthopKey(ipAddress))
365 .setFlowrefCount(flowrefCnt).build();
366 LOG.trace("Updating vpnnextHop {} for refCount {} to Operational DS", nh, flowrefCnt);
367 syncWrite(LogicalDatastoreType.OPERATIONAL, getVpnNextHopIdentifier(vpnId, ipAddress),
368 nh, DEFAULT_CALLBACK);
374 protected void addVpnNexthopToDS(BigInteger dpnId, long vpnId, String ipPrefix, long egressPointer) {
375 InstanceIdentifierBuilder<VpnNexthops> idBuilder = InstanceIdentifier.builder(L3nexthop.class)
376 .child(VpnNexthops.class, new VpnNexthopsKey(vpnId));
378 // Add nexthop to vpn node
379 VpnNexthop nh = new VpnNexthopBuilder()
380 .setKey(new VpnNexthopKey(ipPrefix))
382 .setIpAddress(ipPrefix)
384 .setEgressPointer(egressPointer).build();
386 InstanceIdentifier<VpnNexthop> id1 = idBuilder
387 .child(VpnNexthop.class, new VpnNexthopKey(ipPrefix)).build();
388 LOG.trace("Adding vpnnextHop {} to Operational DS", nh);
389 syncWrite(LogicalDatastoreType.OPERATIONAL, id1, nh, DEFAULT_CALLBACK);
393 protected InstanceIdentifier<VpnNexthop> getVpnNextHopIdentifier(long vpnId, String ipAddress) {
394 InstanceIdentifier<VpnNexthop> id = InstanceIdentifier.builder(L3nexthop.class)
395 .child(VpnNexthops.class, new VpnNexthopsKey(vpnId)).child(VpnNexthop.class,
396 new VpnNexthopKey(ipAddress)).build();
400 protected VpnNexthop getVpnNexthop(long vpnId, String ipAddress) {
402 // check if vpn node is there
403 InstanceIdentifierBuilder<VpnNexthops> idBuilder =
404 InstanceIdentifier.builder(L3nexthop.class).child(VpnNexthops.class,
405 new VpnNexthopsKey(vpnId));
406 InstanceIdentifier<VpnNexthops> id = idBuilder.build();
407 Optional<VpnNexthops> vpnNexthops = read(LogicalDatastoreType.OPERATIONAL, id);
408 if (vpnNexthops.isPresent()) {
409 // get nexthops list for vpn
410 List<VpnNexthop> nexthops = vpnNexthops.get().getVpnNexthop();
411 for (VpnNexthop nexthop : nexthops) {
412 if (nexthop.getIpAddress().equals(ipAddress)) {
414 LOG.trace("VpnNextHop : {}", nexthop);
418 // return null if not found
423 public AdjacencyResult getRemoteNextHopPointer(BigInteger remoteDpnId, long vpnId, String prefixIp,
425 String egressIfName = null;
426 LOG.trace("getRemoteNextHopPointer: input [remoteDpnId {}, vpnId {}, prefixIp {}, nextHopIp {} ]", remoteDpnId,
427 vpnId, prefixIp, nextHopIp);
429 Class<? extends InterfaceType> egressIfType;
430 ElanInstance elanInstance = getElanInstanceForPrefix(vpnId, prefixIp);
431 if (elanInstance != null) {
432 egressIfType = getInterfaceType(elanInstance);
434 LOG.warn("Failed to determine network type for prefixIp {} using tunnel", prefixIp);
435 egressIfType = Tunnel.class;
438 if (Tunnel.class.equals(egressIfType)) {
439 egressIfName = getTunnelRemoteNextHopPointer(remoteDpnId, nextHopIp);
441 egressIfName = getExtPortRemoteNextHopPointer(remoteDpnId, elanInstance);
444 LOG.trace("NextHop pointer for prefixIp {} vpnId {} dpnId {} is {}", prefixIp, vpnId, remoteDpnId,
446 return egressIfName != null ? new AdjacencyResult(egressIfName, egressIfType) : null;
449 public BigInteger getDpnForPrefix(long vpnId, String prefixIp) {
450 VpnNexthop vpnNexthop = getVpnNexthop(vpnId, prefixIp);
451 BigInteger localDpnId = (vpnNexthop == null) ? null : vpnNexthop.getDpnId();
455 private void removeVpnNexthopFromDS(long vpnId, String ipPrefix) {
457 InstanceIdentifierBuilder<VpnNexthop> idBuilder = InstanceIdentifier.builder(L3nexthop.class)
458 .child(VpnNexthops.class, new VpnNexthopsKey(vpnId))
459 .child(VpnNexthop.class, new VpnNexthopKey(ipPrefix));
460 InstanceIdentifier<VpnNexthop> id = idBuilder.build();
462 LOG.trace("Removing vpn next hop from datastore : {}", id);
463 syncDelete(LogicalDatastoreType.OPERATIONAL, id);
466 public void removeLocalNextHop(BigInteger dpnId, Long vpnId, String ipNextHopAddress, String ipPrefixAddress) {
467 String ipPrefixStr = new String(vpnId + ipPrefixAddress);
468 VpnNexthop prefixNh = null;
469 synchronized (ipPrefixStr.intern()) {
470 prefixNh = getVpnNexthop(vpnId, ipPrefixAddress);
472 String ipAddress = (prefixNh != null) ? ipPrefixAddress : ipNextHopAddress;
474 String nextHopLockStr = new String(vpnId + ipAddress);
475 synchronized (nextHopLockStr.intern()) {
476 VpnNexthop nh = getVpnNexthop(vpnId, ipAddress);
478 int newFlowrefCnt = nh.getFlowrefCount() - 1;
479 if (newFlowrefCnt == 0) { //remove the group only if there are no more flows using this group
480 GroupEntity groupEntity = MDSALUtil.buildGroupEntity(
481 dpnId, nh.getEgressPointer(), ipAddress, GroupTypes.GroupAll, null);
483 mdsalApiManager.removeGroup(groupEntity);
485 removeVpnNexthopFromDS(vpnId, ipAddress);
487 removeNextHopPointer(getNextHopKey(vpnId, ipAddress));
488 LOG.debug("Local Next hop {} for {} {} on dpn {} successfully deleted",
489 nh.getEgressPointer(), vpnId, ipAddress, dpnId);
491 //just update the flowrefCount of the vpnNexthop
492 VpnNexthop currNh = new VpnNexthopBuilder().setKey(new VpnNexthopKey(ipAddress))
493 .setFlowrefCount(newFlowrefCnt).build();
494 LOG.trace("Updating vpnnextHop {} for refCount {} to Operational DS", currNh, newFlowrefCnt);
495 syncWrite(LogicalDatastoreType.OPERATIONAL, getVpnNextHopIdentifier(vpnId, ipAddress), currNh,
500 LOG.error("Local Next hop for {} on dpn {} not deleted", ipAddress, dpnId);
506 // TODO Clean up the exception handling
507 @SuppressWarnings("checkstyle:IllegalCatch")
508 private <T extends DataObject> Optional<T> read(LogicalDatastoreType datastoreType,
509 InstanceIdentifier<T> path) {
511 ReadOnlyTransaction tx = dataBroker.newReadOnlyTransaction();
513 Optional<T> result = Optional.absent();
515 result = tx.read(datastoreType, path).get();
516 } catch (Exception e) {
517 throw new RuntimeException(e);
523 private <T extends DataObject> void asyncWrite(LogicalDatastoreType datastoreType,
524 InstanceIdentifier<T> path, T data,
525 FutureCallback<Void> callback) {
526 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
527 tx.merge(datastoreType, path, data, true);
528 Futures.addCallback(tx.submit(), callback);
531 private <T extends DataObject> void syncWrite(LogicalDatastoreType datastoreType,
532 InstanceIdentifier<T> path, T data,
533 FutureCallback<Void> callback) {
534 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
535 tx.merge(datastoreType, path, data, true);
536 CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
539 } catch (InterruptedException | ExecutionException e) {
540 LOG.error("Error writing to datastore (path, data) : ({}, {})", path, data, e);
541 throw new RuntimeException(e.getMessage());
545 private <T extends DataObject> void syncDelete(LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
546 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
547 tx.delete(datastoreType, path);
548 CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
551 } catch (InterruptedException | ExecutionException e) {
552 LOG.error("Error deleting from datastore (path) : ({})", path, e);
553 throw new RuntimeException(e.getMessage());
557 private InstanceIdentifier<Adjacency> getAdjacencyIdentifier(String vpnInterfaceName, String ipAddress) {
558 return InstanceIdentifier.builder(VpnInterfaces.class)
559 .child(VpnInterface.class, new VpnInterfaceKey(vpnInterfaceName)).augmentation(
560 Adjacencies.class).child(Adjacency.class, new AdjacencyKey(ipAddress)).build();
563 InstanceIdentifier<Adjacencies> getAdjListPath(String vpnInterfaceName) {
564 return InstanceIdentifier.builder(VpnInterfaces.class)
565 .child(VpnInterface.class, new VpnInterfaceKey(vpnInterfaceName)).augmentation(
566 Adjacencies.class).build();
569 // TODO Clean up the console output
570 @SuppressWarnings("checkstyle:RegexpSinglelineJava")
571 public void setConfTransType(String service, String transportType) {
573 if (!service.toUpperCase().equals("L3VPN")) {
574 System.out.println("Please provide a valid service name. Available value(s): L3VPN");
575 LOG.error("Incorrect service {} provided for setting the transport type.", service);
579 L3VPNTransportTypes transType = L3VPNTransportTypes.validateTransportType(transportType.toUpperCase());
581 if (transType != L3VPNTransportTypes.Invalid) {
582 configuredTransportTypeL3VPN = transType;
586 public void writeConfTransTypeConfigDS() {
587 FibUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, getConfTransportTypeIdentifier(),
588 createConfTransportType(configuredTransportTypeL3VPN.getTransportType()),
589 FibUtil.DEFAULT_CALLBACK);
592 public L3VPNTransportTypes getConfiguredTransportTypeL3VPN() {
593 return this.configuredTransportTypeL3VPN;
596 public String getReqTransType() {
597 if (configuredTransportTypeL3VPN == L3VPNTransportTypes.Invalid) {
599 * Restart scenario, Read from the ConfigDS.
600 * if the value is Unset, cache value as VxLAN.
602 LOG.trace("configureTransportType is not yet set.");
603 Optional<ConfTransportTypeL3vpn> configuredTransTypeFromConfig =
604 FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, getConfTransportTypeIdentifier());
606 if (configuredTransTypeFromConfig.isPresent()) {
607 if (configuredTransTypeFromConfig.get().getTransportType().equals(TunnelTypeGre.class)) {
608 configuredTransportTypeL3VPN.setL3VPNTransportTypes(ITMConstants.TUNNEL_TYPE_GRE);
610 configuredTransportTypeL3VPN.setL3VPNTransportTypes(ITMConstants.TUNNEL_TYPE_VXLAN);
612 LOG.trace("configuredTransportType set from config DS to {}",
613 getConfiguredTransportTypeL3VPN().getTransportType());
615 setConfTransType("L3VPN", L3VPNTransportTypes.VxLAN.getTransportType());
616 LOG.trace("configuredTransportType is not set in the Config DS. VxLAN as default will be used.");
619 LOG.trace("configuredTransportType is set as {}", getConfiguredTransportTypeL3VPN().getTransportType());
621 return getConfiguredTransportTypeL3VPN().getTransportType();
624 public InstanceIdentifier<ConfTransportTypeL3vpn> getConfTransportTypeIdentifier() {
625 return InstanceIdentifier.builder(ConfTransportTypeL3vpn.class).build();
628 private ConfTransportTypeL3vpn createConfTransportType(String type) {
629 ConfTransportTypeL3vpn confTransType;
630 if (type.equals(ITMConstants.TUNNEL_TYPE_GRE)) {
631 confTransType = new ConfTransportTypeL3vpnBuilder().setTransportType(TunnelTypeGre.class).build();
632 LOG.trace("Setting the confTransportType to GRE.");
633 } else if (type.equals(ITMConstants.TUNNEL_TYPE_VXLAN)) {
634 confTransType = new ConfTransportTypeL3vpnBuilder().setTransportType(TunnelTypeVxlan.class).build();
635 LOG.trace("Setting the confTransportType to VxLAN.");
637 LOG.trace("Invalid transport type {} passed to Config DS ", type);
638 confTransType = null;
640 return confTransType;
643 public Class<? extends TunnelTypeBase> getReqTunType(String transportType) {
644 if (transportType.equals("VXLAN")) {
645 return TunnelTypeVxlan.class;
646 } else if (transportType.equals("GRE")) {
647 return TunnelTypeGre.class;
649 return TunnelTypeMplsOverGre.class;
653 public String getTransportTypeStr(String tunType) {
654 if (tunType.equals(TunnelTypeVxlan.class.toString())) {
655 return ITMConstants.TUNNEL_TYPE_VXLAN;
656 } else if (tunType.equals(TunnelTypeGre.class.toString())) {
657 return ITMConstants.TUNNEL_TYPE_GRE;
658 } else if (tunType.equals(TunnelTypeMplsOverGre.class.toString())) {
659 return ITMConstants.TUNNEL_TYPE_MPLSoGRE;
661 return ITMConstants.TUNNEL_TYPE_INVALID;
666 public void close() throws Exception {
667 LOG.info("{} close", getClass().getSimpleName());
670 // TODO Clean up the exception handling
671 @SuppressWarnings("checkstyle:IllegalCatch")
672 private String getTunnelRemoteNextHopPointer(BigInteger remoteDpnId, String nextHopIp) {
673 if (nextHopIp != null && !nextHopIp.isEmpty()) {
675 // here use the config for tunnel type param
676 return getTunnelInterfaceName(remoteDpnId,
677 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressBuilder
678 .getDefaultInstance(nextHopIp));
679 } catch (Exception ex) {
680 LOG.error("Error while retrieving nexthop pointer for nexthop {} : ", nextHopIp, ex);
687 private String getExtPortRemoteNextHopPointer(BigInteger remoteDpnId, ElanInstance elanInstance) {
688 return elanService.getExternalElanInterface(elanInstance.getElanInstanceName(), remoteDpnId);
692 * Get the interface type associated with the type of ELAN used for routing
693 * traffic to/from remote compute nodes.
695 * @param elanInstance The elan instance
696 * @return L2vlan for flat/VLAN network type and Tunnel otherwise
698 private Class<? extends InterfaceType> getInterfaceType(ElanInstance elanInstance) {
699 Class<? extends SegmentTypeBase> segmentType = elanInstance.getSegmentType();
700 if (SegmentTypeFlat.class.equals(segmentType) || SegmentTypeVlan.class.equals(segmentType)) {
707 private ElanInstance getElanInstanceForPrefix(long vpnId, String prefixIp) {
708 Prefixes prefix = FibUtil.getPrefixToInterface(dataBroker, vpnId, prefixIp);
709 if (prefix == null) {
710 LOG.warn("No prefix info was found for VPN id {} prefix {}", vpnId, prefixIp);
714 String interfaceName = prefix.getVpnInterfaceName();
715 if (interfaceName == null) {
716 LOG.warn("No VPN interface found for VPN id {} prefix {}", vpnId, prefixIp);
720 ElanInterface elanInterface = elanService.getElanInterfaceByElanInterfaceName(interfaceName);
721 if (elanInterface == null) {
722 LOG.warn("No ELAN interface found for VPN interface {} on VPN id {}", interfaceName, vpnId);
726 return elanService.getElanInstance(elanInterface.getElanInstanceName());
729 static class AdjacencyResult {
730 private String interfaceName;
731 private Class<? extends InterfaceType> interfaceType;
733 AdjacencyResult(String interfaceName, Class<? extends InterfaceType> interfaceType) {
734 this.interfaceName = interfaceName;
735 this.interfaceType = interfaceType;
738 public String getInterfaceName() {
739 return interfaceName;
742 public Class<? extends InterfaceType> getInterfaceType() {
743 return interfaceType;
747 public int hashCode() {
748 final int prime = 31;
750 result = prime * result + ((interfaceName == null) ? 0 : interfaceName.hashCode());
755 public boolean equals(Object obj) {
756 boolean result = false;
757 if (getClass() != obj.getClass()) {
760 AdjacencyResult other = (AdjacencyResult) obj;
761 result = interfaceName.equals(other.interfaceName);