2 * Copyright (c) 2015 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.vpnservice.nexthopmgr;
11 import java.math.BigInteger;
12 import java.util.ArrayList;
13 import java.util.List;
14 import java.util.concurrent.Future;
16 import com.google.common.base.Optional;
17 import com.google.common.util.concurrent.Futures;
18 import com.google.common.util.concurrent.FutureCallback;
20 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
21 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
22 import org.opendaylight.yangtools.yang.binding.DataObject;
23 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
24 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
25 import org.opendaylight.yangtools.yang.common.RpcResult;
26 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
27 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
28 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
29 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
30 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
31 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstanceKey;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstance1;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.CreateIdPoolInput;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.CreateIdPoolInputBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.GetUniqueIdOutput;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.GetUniqueIdInputBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.GetUniqueIdInput;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.*;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.l3nexthop.*;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.l3nexthop.tunnelnexthops.*;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.l3nexthop.vpnnexthops.*;
43 import org.opendaylight.vpnservice.interfacemgr.interfaces.IInterfaceManager;
44 import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
45 import org.opendaylight.vpnservice.mdsalutil.ActionType;
46 import org.opendaylight.vpnservice.mdsalutil.BucketInfo;
47 import org.opendaylight.vpnservice.mdsalutil.GroupEntity;
48 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
49 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
50 import org.opendaylight.idmanager.IdManager;
52 import java.util.concurrent.ExecutionException;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
57 public class NexthopManager implements L3nexthopService, AutoCloseable {
58 private static final Logger LOG = LoggerFactory.getLogger(NexthopManager.class);
59 private final DataBroker broker;
60 private IMdsalApiManager mdsalManager;
61 private IInterfaceManager interfaceManager;
62 private IdManager idManager;
64 private static final FutureCallback<Void> DEFAULT_CALLBACK =
65 new FutureCallback<Void>() {
66 public void onSuccess(Void result) {
67 LOG.debug("Success in Datastore write operation");
69 public void onFailure(Throwable error) {
70 LOG.error("Error in Datastore write operation", error);
75 * Provides nexthop functions
76 * Creates group ID pool
78 * @param db - dataBroker reference
80 public NexthopManager(final DataBroker db) {
85 public void close() throws Exception {
86 LOG.info("NextHop Manager Closed");
89 public void setInterfaceManager(IInterfaceManager ifManager) {
90 this.interfaceManager = ifManager;
93 public void setMdsalManager(IMdsalApiManager mdsalManager) {
94 this.mdsalManager = mdsalManager;
97 public void setIdManager(IdManager idManager) {
98 this.idManager = idManager;
101 protected void createNexthopPointerPool() {
102 CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
103 .setPoolName("nextHopPointerPool")
105 .setPoolSize(new BigInteger("65535"))
107 //TODO: Error handling
108 Future<RpcResult<Void>> result = idManager.createIdPool(createPool);
109 LOG.trace("NextHopPointerPool result : {}", result);
111 // LOG.info("Result2: {}",result.get());
112 // } catch (InterruptedException | ExecutionException e) {
113 // // TODO Auto-generated catch block
114 // LOG.error("Error in result.get");
120 private long getVpnId(String vpnName) {
121 InstanceIdentifierBuilder<VpnInstance> idBuilder = InstanceIdentifier.builder(VpnInstances.class)
122 .child(VpnInstance.class, new VpnInstanceKey(vpnName));
124 InstanceIdentifier<VpnInstance> id = idBuilder.build();
125 InstanceIdentifier<VpnInstance1> idx = id.augmentation(VpnInstance1.class);
126 Optional<VpnInstance1> vpn = read(LogicalDatastoreType.OPERATIONAL, idx);
128 if (vpn.isPresent()) {
129 LOG.debug("VPN id returned: {}", vpn.get().getVpnId());
130 return vpn.get().getVpnId();
136 private long getDpnId(String ifName) {
137 String[] fields = ifName.split(":");
138 long dpn = Integer.parseInt(fields[1]);
139 LOG.debug("DpnId: {}", dpn);
143 private int createNextHopPointer(String nexthopKey) {
144 GetUniqueIdInput getIdInput = new GetUniqueIdInputBuilder()
145 .setPoolName("nextHopPointerPool").setIdKey(nexthopKey)
147 //TODO: Proper error handling once IdManager code is complete
149 Future<RpcResult<GetUniqueIdOutput>> result = idManager.getUniqueId(getIdInput);
150 RpcResult<GetUniqueIdOutput> rpcResult = result.get();
151 return rpcResult.getResult().getIdValue().intValue();
152 } catch (NullPointerException | InterruptedException | ExecutionException e) {
158 public void createLocalNextHop(String ifName, String vpnName, String ipAddress, String macAddress) {
159 String nhKey = new String("nexthop." + vpnName + ipAddress);
160 int groupId = createNextHopPointer(nhKey);
162 long vpnId = getVpnId(vpnName);
163 long dpnId = interfaceManager.getDpnForInterface(ifName);
164 VpnNexthop nexthop = getVpnNexthop(vpnId, ipAddress);
165 LOG.trace("nexthop: {}", nexthop);
166 if (nexthop == null) {
167 List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
168 List<ActionInfo> listActionInfo = interfaceManager.getInterfaceEgressActions(ifName);
169 BucketInfo bucket = new BucketInfo(listActionInfo);
171 if (macAddress != null) {
172 listActionInfo.add(0, new ActionInfo(ActionType.set_field_eth_dest, new String[]{macAddress}));
173 listActionInfo.add(0, new ActionInfo(ActionType.pop_mpls, new String[]{}));
175 //FIXME: Log message here.
176 LOG.debug("mac address for new local nexthop is null");
178 listBucketInfo.add(bucket);
179 GroupEntity groupEntity = MDSALUtil.buildGroupEntity(
180 dpnId, groupId, ipAddress, GroupTypes.GroupIndirect, listBucketInfo);
183 mdsalManager.installGroup(groupEntity);
186 addVpnNexthopToDS(vpnId, ipAddress, groupId);
192 public void createRemoteNextHop(String ifName, String ofPortId, String ipAddress) {
193 String nhKey = new String("nexthop." + ifName + ipAddress);
194 int groupId = createNextHopPointer(nhKey);
196 long dpnId = getDpnId(ofPortId);
197 TunnelNexthop nexthop = getTunnelNexthop(dpnId, ipAddress);
198 if (nexthop == null) {
200 List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
201 List<ActionInfo> listActionInfo = interfaceManager.getInterfaceEgressActions(ifName);
202 BucketInfo bucket = new BucketInfo(listActionInfo);
204 listBucketInfo.add(bucket);
205 GroupEntity groupEntity = MDSALUtil.buildGroupEntity(
206 dpnId, groupId, ipAddress, GroupTypes.GroupIndirect, listBucketInfo);
207 mdsalManager.installGroup(groupEntity);
210 addTunnelNexthopToDS(dpnId, ipAddress, groupId);
216 private void addVpnNexthopToDS(long vpnId, String ipPrefix, long egressPointer) {
218 InstanceIdentifierBuilder<VpnNexthops> idBuilder = InstanceIdentifier.builder(L3nexthop.class)
219 .child(VpnNexthops.class, new VpnNexthopsKey(vpnId));
221 // check if vpn node is there or to be created
222 InstanceIdentifier<VpnNexthops> id = idBuilder.build();
223 Optional<VpnNexthops> nexthops = read(LogicalDatastoreType.OPERATIONAL, id);
224 if (!nexthops.isPresent()) {
226 VpnNexthops node = new VpnNexthopsBuilder().setKey(new VpnNexthopsKey(vpnId)).setVpnId(vpnId).build();
227 asyncWrite(LogicalDatastoreType.OPERATIONAL, id, node, DEFAULT_CALLBACK);
230 // Add nexthop to vpn node
231 VpnNexthop nh = new VpnNexthopBuilder().
232 setKey(new VpnNexthopKey(ipPrefix)).
233 setIpAddress(ipPrefix).
234 setEgressPointer(egressPointer).build();
236 InstanceIdentifier<VpnNexthop> id1 = idBuilder
237 .child(VpnNexthop.class, new VpnNexthopKey(ipPrefix)).build();
238 LOG.trace("Adding vpnnextHop {} to Operational DS", nh);
239 asyncWrite(LogicalDatastoreType.OPERATIONAL, id1, nh, DEFAULT_CALLBACK);
243 private void addTunnelNexthopToDS(long dpnId, String ipPrefix, long egressPointer) {
244 InstanceIdentifierBuilder<TunnelNexthops> idBuilder = InstanceIdentifier.builder(L3nexthop.class)
245 .child(TunnelNexthops.class, new TunnelNexthopsKey(dpnId));
247 // check if dpn node is there or to be created
248 InstanceIdentifier<TunnelNexthops> id = idBuilder.build();
249 Optional<TunnelNexthops> nexthops = read(LogicalDatastoreType.OPERATIONAL, id);
250 if (!nexthops.isPresent()) {
252 TunnelNexthops node = new TunnelNexthopsBuilder()
253 .setKey(new TunnelNexthopsKey(dpnId))
256 LOG.trace("Adding tunnelnextHop {} to Operational DS for a new node", node);
257 asyncWrite(LogicalDatastoreType.OPERATIONAL, id, node, DEFAULT_CALLBACK);
260 // Add nexthop to dpn node
261 TunnelNexthop nh = new TunnelNexthopBuilder().
262 setKey(new TunnelNexthopKey(ipPrefix)).
263 setIpAddress(ipPrefix).
264 setEgressPointer(egressPointer).build();
266 InstanceIdentifier<TunnelNexthop> id1 = idBuilder
267 .child(TunnelNexthop.class, new TunnelNexthopKey(ipPrefix)).build();
268 LOG.trace("Adding tunnelnextHop {} to Operational DS for a dpn node", nh);
269 asyncWrite(LogicalDatastoreType.OPERATIONAL, id1, nh, DEFAULT_CALLBACK);
273 private VpnNexthop getVpnNexthop(long vpnId, String ipAddress) {
275 // check if vpn node is there
276 InstanceIdentifierBuilder<VpnNexthops> idBuilder = InstanceIdentifier.builder(L3nexthop.class)
277 .child(VpnNexthops.class, new VpnNexthopsKey(vpnId));
278 InstanceIdentifier<VpnNexthops> id = idBuilder.build();
279 Optional<VpnNexthops> vpnNexthops = read(LogicalDatastoreType.OPERATIONAL, id);
280 if (vpnNexthops.isPresent()) {
282 // get nexthops list for vpn
283 List<VpnNexthop> nexthops = vpnNexthops.get().getVpnNexthop();
284 for (VpnNexthop nexthop : nexthops) {
285 if (nexthop.getIpAddress().equals(ipAddress)) {
287 LOG.trace("VpnNextHop : {}",nexthop);
292 //return null if not found
296 private TunnelNexthop getTunnelNexthop(long dpnId, String ipAddress) {
298 InstanceIdentifierBuilder<TunnelNexthops> idBuilder = InstanceIdentifier.builder(L3nexthop.class)
299 .child(TunnelNexthops.class, new TunnelNexthopsKey(dpnId));
301 // check if vpn node is there
302 InstanceIdentifier<TunnelNexthops> id = idBuilder.build();
303 Optional<TunnelNexthops> dpnNexthops = read(LogicalDatastoreType.OPERATIONAL, id);
304 if (dpnNexthops.isPresent()) {
305 List<TunnelNexthop> nexthops = dpnNexthops.get().getTunnelNexthop();
306 for (TunnelNexthop nexthop : nexthops) {
307 if (nexthop.getIpAddress().equals(ipAddress)) {
308 LOG.trace("TunnelNextHop : {}",nexthop);
316 public long getNextHopPointer(long dpnId, long vpnId, String prefixIp, String nextHopIp) {
317 String endpointIp = interfaceManager.getEndpointIpForDpn(dpnId);
318 if (nextHopIp.equals(endpointIp)) {
319 VpnNexthop vpnNextHop = getVpnNexthop(vpnId, prefixIp);
320 return vpnNextHop.getEgressPointer();
322 TunnelNexthop tunnelNextHop = getTunnelNexthop(dpnId, nextHopIp);
323 LOG.trace("NExtHopPointer : {}", tunnelNextHop.getEgressPointer());
324 return tunnelNextHop.getEgressPointer();
328 private void removeTunnelNexthopFromDS(long dpnId, String ipPrefix) {
330 InstanceIdentifierBuilder<TunnelNexthop> idBuilder = InstanceIdentifier.builder(L3nexthop.class)
331 .child(TunnelNexthops.class, new TunnelNexthopsKey(dpnId))
332 .child(TunnelNexthop.class, new TunnelNexthopKey(ipPrefix));
333 InstanceIdentifier<TunnelNexthop> id = idBuilder.build();
335 LOG.trace("Removing tunnel next hop from datastore : {}", id);
336 delete(LogicalDatastoreType.OPERATIONAL, id);
339 private void removeVpnNexthopFromDS(long vpnId, String ipPrefix) {
341 InstanceIdentifierBuilder<VpnNexthop> idBuilder = InstanceIdentifier.builder(L3nexthop.class)
342 .child(VpnNexthops.class, new VpnNexthopsKey(vpnId))
343 .child(VpnNexthop.class, new VpnNexthopKey(ipPrefix));
344 InstanceIdentifier<VpnNexthop> id = idBuilder.build();
346 LOG.trace("Removing vpn next hop from datastore : {}", id);
347 delete(LogicalDatastoreType.OPERATIONAL, id);
351 public void removeLocalNextHop(Long dpId, Long vpnId, String ipAddress) {
353 VpnNexthop nh = getVpnNexthop(vpnId, ipAddress);
355 // how to inform and remove dependent FIB entries??
356 // we need to do it before the group is removed
357 GroupEntity groupEntity = MDSALUtil.buildGroupEntity(
358 dpId, nh.getEgressPointer(), ipAddress, GroupTypes.GroupIndirect, null);
360 mdsalManager.removeGroup(groupEntity);
362 removeVpnNexthopFromDS(vpnId, ipAddress);
365 LOG.error("removal of local next hop failed");
370 public void removeRemoteNextHop(long dpnId, String ipAddress) {
372 TunnelNexthop nh = getTunnelNexthop(dpnId, ipAddress);
374 // how to inform and remove dependent FIB entries??
375 // we need to do it before the group is removed
378 GroupEntity groupEntity = MDSALUtil.buildGroupEntity(
379 dpnId, nh.getEgressPointer(), ipAddress, GroupTypes.GroupIndirect, null);
381 mdsalManager.removeGroup(groupEntity);
383 removeTunnelNexthopFromDS(dpnId, ipAddress);
386 LOG.error("removal of remote next hop failed : dpnid : {}, ipaddress : {}", dpnId, ipAddress);
392 public Future<RpcResult<GetEgressPointerOutput>> getEgressPointer(
393 GetEgressPointerInput input) {
395 GetEgressPointerOutputBuilder output = new GetEgressPointerOutputBuilder();
397 String endpointIp = interfaceManager.getEndpointIpForDpn(input.getDpnId());
398 LOG.trace("getEgressPointer: input {}, endpointIp {}", input, endpointIp);
399 if (input.getNexthopIp().equals(endpointIp)) {
400 VpnNexthop vpnNextHop = getVpnNexthop(input.getVpnId(), input.getIpPrefix());
401 output.setEgressPointer(vpnNextHop.getEgressPointer());
402 output.setLocalDestination(true);
404 TunnelNexthop tunnelNextHop = getTunnelNexthop(input.getDpnId(), input.getNexthopIp());
405 output.setEgressPointer(tunnelNextHop.getEgressPointer());
406 output.setLocalDestination(false);
409 RpcResultBuilder<GetEgressPointerOutput> rpcResultBuilder = RpcResultBuilder.success();
410 rpcResultBuilder.withResult(output.build());
412 return Futures.immediateFuture(rpcResultBuilder.build());
416 private <T extends DataObject> Optional<T> read(LogicalDatastoreType datastoreType,
417 InstanceIdentifier<T> path) {
419 ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
421 Optional<T> result = Optional.absent();
423 result = tx.read(datastoreType, path).get();
424 } catch (Exception e) {
425 throw new RuntimeException(e);
431 private <T extends DataObject> void asyncWrite(LogicalDatastoreType datastoreType,
432 InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
433 WriteTransaction tx = broker.newWriteOnlyTransaction();
434 tx.put(datastoreType, path, data, true);
435 Futures.addCallback(tx.submit(), callback);
439 private <T extends DataObject> void delete(LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
440 WriteTransaction tx = broker.newWriteOnlyTransaction();
441 tx.delete(datastoreType, path);
442 Futures.addCallback(tx.submit(), DEFAULT_CALLBACK);
446 public Future<RpcResult<Void>> removeLocalNextHop(RemoveLocalNextHopInput input) {
447 VpnNexthop vpnNextHop = getVpnNexthop(input.getVpnId(), input.getIpPrefix());
448 RpcResultBuilder<Void> rpcResultBuilder;
449 LOG.debug("vpnnexthop is: {}", vpnNextHop);
451 removeLocalNextHop(input.getDpnId(),input.getVpnId(), input.getIpPrefix());
452 rpcResultBuilder = RpcResultBuilder.success();
455 LOG.error("Removal of local next hop for vpnNextHop {} failed {}" ,vpnNextHop, e);
456 rpcResultBuilder = RpcResultBuilder.failed();
458 return Futures.immediateFuture(rpcResultBuilder.build());