8e1a4fc2e37d7cdf0d1eeec7af8d750baa389570
[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
11 import java.math.BigInteger;
12 import java.util.ArrayList;
13 import java.util.List;
14 import java.util.concurrent.Future;
15
16 import com.google.common.base.Optional;
17 import com.google.common.util.concurrent.Futures;
18 import com.google.common.util.concurrent.FutureCallback;
19
20 //import org.opendaylight.controller.netconf.confignetconfconnector.mapping.rpc.Rpcs;
21 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
22 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
23 import org.opendaylight.yangtools.yang.binding.DataObject;
24 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
25 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
26 import org.opendaylight.yangtools.yang.common.RpcResult;
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;
51
52 import java.util.concurrent.ExecutionException;
53
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
56
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;
63
64     private static final FutureCallback<Void> DEFAULT_CALLBACK =
65         new FutureCallback<Void>() {
66             public void onSuccess(Void result) {
67                 LOG.info("Success in Datastore write operation");
68             }
69             public void onFailure(Throwable error) {
70                 LOG.error("Error in Datastore write operation", error);
71             };
72         };
73
74     /**
75     * Provides nexthop functions
76     * Creates group ID pool
77     *
78     * @param db - dataBroker reference
79     */
80     public NexthopManager(final DataBroker db) {
81         broker = db;
82         createNexthopPointerPool();
83     }
84
85     @Override
86     public void close() throws Exception {
87         LOG.info("NextHop Manager Closed");
88     }
89
90     public void setInterfaceManager(IInterfaceManager ifManager) {
91         this.interfaceManager = ifManager;
92     }
93
94     public void setMdsalManager(IMdsalApiManager mdsalManager) {
95         this.mdsalManager = mdsalManager;
96     }
97
98     public void setIdManager(IdManager idManager) {
99         this.idManager = idManager;
100     }
101
102     private void createNexthopPointerPool() {
103         CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
104             .setPoolName("nextHopPointerPool")
105             .setIdStart(1L)
106             .setPoolSize(new BigInteger("65535"))
107             .build();
108         //TODO: Error handling
109         Future<RpcResult<Void>> result = idManager.createIdPool(createPool);
110 //            try {
111 //                LOG.info("Result2: {}",result.get());
112 //            } catch (InterruptedException | ExecutionException e) {
113 //                // TODO Auto-generated catch block
114 //                LOG.error("Error in result.get");
115 //            }
116
117     }
118
119
120     private long getVpnId(String vpnName) {
121         InstanceIdentifierBuilder<VpnInstance> idBuilder = InstanceIdentifier.builder(VpnInstances.class)
122                 .child(VpnInstance.class, new VpnInstanceKey(vpnName));
123
124         InstanceIdentifier<VpnInstance> id = idBuilder.build();
125         InstanceIdentifier<VpnInstance1> idx = id.augmentation(VpnInstance1.class);
126         Optional<VpnInstance1> vpn = read(LogicalDatastoreType.CONFIGURATION, idx);
127
128         if (vpn.isPresent()) {
129             return vpn.get().getVpnId();
130         } else {
131             return 0;
132         }
133     }
134
135     private long getDpnId(String ifName) {
136         String[] fields = ifName.split(":");
137         long dpn = Integer.parseInt(fields[1]);
138         return dpn;
139     }
140
141     private int createNextHopPointer(String nexthopKey) {
142         GetUniqueIdInput getIdInput = new GetUniqueIdInputBuilder()
143             .setPoolName("nextHopPointerPool").setIdKey(nexthopKey)
144             .build();
145         //TODO: Proper error handling once IdManager code is complete
146         try {
147             Future<RpcResult<GetUniqueIdOutput>> result = idManager.getUniqueId(getIdInput);
148             RpcResult<GetUniqueIdOutput> rpcResult = result.get();
149             return rpcResult.getResult().getIdValue().intValue();
150         } catch (NullPointerException | InterruptedException | ExecutionException e) {
151             LOG.trace("",e);
152         }
153         return 0;
154     }
155
156     public void createLocalNextHop(String ifName, String vpnName, String ipAddress, String macAddress) {
157         String nhKey = new String("nexthop." + vpnName + ipAddress);
158         int groupId = createNextHopPointer(nhKey);
159
160         long vpnId = getVpnId(vpnName);
161         long dpnId = interfaceManager.getDpnForInterface(ifName);
162         VpnNexthop nexthop = getVpnNexthop(vpnId, ipAddress);
163         if (nexthop == null) {
164             List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
165             List<ActionInfo> listActionInfo = interfaceManager.getInterfaceEgressActions(ifName);
166             BucketInfo bucket = new BucketInfo(listActionInfo);
167             // MAC re-write
168             if (macAddress != null) {
169                 listActionInfo.add(new ActionInfo(ActionType.set_field_eth_dest, new String[]{macAddress}));
170             } else {
171                 //FIXME: Log message here.
172             }
173             listBucketInfo.add(bucket);
174             GroupEntity groupEntity = MDSALUtil.buildGroupEntity(
175                 dpnId, groupId, ipAddress, GroupTypes.GroupIndirect, listBucketInfo);
176
177             // install Group
178             mdsalManager.installGroup(groupEntity);
179
180             //update MD-SAL DS
181             addVpnNexthopToDS(vpnId, ipAddress, groupId);
182         } else {
183             //check update
184         }
185     }
186
187     public void createRemoteNextHop(String ifName, String ofPortId, String ipAddress) {
188         String nhKey = new String("nexthop." + ifName + ipAddress);
189         int groupId = createNextHopPointer(nhKey);
190
191         long dpnId = getDpnId(ofPortId);
192         TunnelNexthop nexthop = getTunnelNexthop(dpnId, ipAddress);
193         if (nexthop == null) {
194
195             List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
196             List<ActionInfo> listActionInfo = interfaceManager.getInterfaceEgressActions(ifName);
197             BucketInfo bucket = new BucketInfo(listActionInfo);
198             // MAC re-write??           
199             listBucketInfo.add(bucket);
200             GroupEntity groupEntity = MDSALUtil.buildGroupEntity(
201                 dpnId, groupId, ipAddress, GroupTypes.GroupIndirect, listBucketInfo);
202             mdsalManager.installGroup(groupEntity);
203
204             //update MD-SAL DS
205             addTunnelNexthopToDS(dpnId, ipAddress, groupId);
206         } else {
207             //check update
208         }
209     }
210
211     private void addVpnNexthopToDS(long vpnId, String ipPrefix, long egressPointer) {
212
213         InstanceIdentifierBuilder<VpnNexthops> idBuilder = InstanceIdentifier.builder(L3nexthop.class)
214                 .child(VpnNexthops.class, new VpnNexthopsKey(vpnId));
215
216         // check if vpn node is there or to be created
217         InstanceIdentifier<VpnNexthops> id = idBuilder.build();
218         Optional<VpnNexthops> nexthops = read(LogicalDatastoreType.CONFIGURATION, id);
219         if (!nexthops.isPresent()) {
220             // create a new node
221             VpnNexthops node = new VpnNexthopsBuilder().setKey(new VpnNexthopsKey(vpnId)).setVpnId(vpnId).build();
222             asyncWrite(LogicalDatastoreType.OPERATIONAL, id, node, DEFAULT_CALLBACK);
223         }
224
225         // Add nexthop to vpn node
226         VpnNexthop nh = new VpnNexthopBuilder().
227                 setKey(new VpnNexthopKey(ipPrefix)).
228                 setIpAddress(ipPrefix).
229                 setEgressPointer(egressPointer).build();
230
231         InstanceIdentifier<VpnNexthop> id1 = idBuilder
232                 .child(VpnNexthop.class, new VpnNexthopKey(ipPrefix)).build();
233
234         asyncWrite(LogicalDatastoreType.OPERATIONAL, id1, nh, DEFAULT_CALLBACK);
235
236     }
237
238     private void addTunnelNexthopToDS(long dpnId, String ipPrefix, long egressPointer) {
239         InstanceIdentifierBuilder<TunnelNexthops> idBuilder = InstanceIdentifier.builder(L3nexthop.class)
240                 .child(TunnelNexthops.class, new TunnelNexthopsKey(dpnId));
241
242         // check if dpn node is there or to be created
243         InstanceIdentifier<TunnelNexthops> id = idBuilder.build();
244         Optional<TunnelNexthops> nexthops = read(LogicalDatastoreType.CONFIGURATION, id);
245         if (!nexthops.isPresent()) {
246             // create a new node
247             TunnelNexthops node = new TunnelNexthopsBuilder()
248                 .setKey(new TunnelNexthopsKey(dpnId))
249                 .setDpnId(dpnId)
250                 .build();
251             asyncWrite(LogicalDatastoreType.OPERATIONAL, id, node, DEFAULT_CALLBACK);
252         }
253
254         // Add nexthop to dpn node
255         TunnelNexthop nh = new TunnelNexthopBuilder().
256                 setKey(new TunnelNexthopKey(ipPrefix)).
257                 setIpAddress(ipPrefix).
258                 setEgressPointer(egressPointer).build();
259
260         InstanceIdentifier<TunnelNexthop> id1 = idBuilder
261                 .child(TunnelNexthop.class, new TunnelNexthopKey(ipPrefix)).build();
262
263         asyncWrite(LogicalDatastoreType.OPERATIONAL, id1, nh, DEFAULT_CALLBACK);
264
265     }
266
267     private VpnNexthop getVpnNexthop(long vpnId, String ipAddress) {
268
269         // check if vpn node is there 
270         InstanceIdentifierBuilder<VpnNexthops> idBuilder = InstanceIdentifier.builder(L3nexthop.class)
271                 .child(VpnNexthops.class, new VpnNexthopsKey(vpnId));
272         InstanceIdentifier<VpnNexthops> id = idBuilder.build();
273         Optional<VpnNexthops> vpnNexthops = read(LogicalDatastoreType.CONFIGURATION, id);
274         if (!vpnNexthops.isPresent()) {
275
276             // get nexthops list for vpn
277             List<VpnNexthop> nexthops = vpnNexthops.get().getVpnNexthop();
278             for (VpnNexthop nexthop : nexthops) {
279                 if (nexthop.getIpAddress().equals(ipAddress)) {
280                     // return nexthop 
281                     return nexthop;
282                 }
283             }
284         }
285         //return null if not found
286         return null;
287     }
288
289     private TunnelNexthop getTunnelNexthop(long dpnId, String ipAddress) {
290         
291         InstanceIdentifierBuilder<TunnelNexthops> idBuilder = InstanceIdentifier.builder(L3nexthop.class)
292                 .child(TunnelNexthops.class, new TunnelNexthopsKey(dpnId));
293
294         // check if vpn node is there 
295         InstanceIdentifier<TunnelNexthops> id = idBuilder.build();
296         Optional<TunnelNexthops> dpnNexthops = read(LogicalDatastoreType.CONFIGURATION, id);
297         if (!dpnNexthops.isPresent()) {
298             List<TunnelNexthop> nexthops = dpnNexthops.get().getTunnelNexthop();
299             for (TunnelNexthop nexthop : nexthops) {
300                 if (nexthop.getIpAddress().equals(ipAddress)) {
301                     return nexthop;
302                 }
303             }
304         }
305         return null;
306     }
307
308     public long getNextHopPointer(long dpnId, long vpnId, String prefixIp, String nextHopIp) {
309         String endpointIp = interfaceManager.getEndpointIpForDpn(dpnId);
310         if (nextHopIp.equals(endpointIp)) {
311             VpnNexthop vpnNextHop = getVpnNexthop(vpnId, prefixIp);
312             return vpnNextHop.getEgressPointer();
313         } else {
314             TunnelNexthop tunnelNextHop = getTunnelNexthop(dpnId, nextHopIp);
315             return tunnelNextHop.getEgressPointer();
316         }
317     }
318
319     private void removeTunnelNexthopFromDS(long dpnId, String ipPrefix) {
320
321         InstanceIdentifierBuilder<TunnelNexthop> idBuilder = InstanceIdentifier.builder(L3nexthop.class)
322                 .child(TunnelNexthops.class, new TunnelNexthopsKey(dpnId))
323                 .child(TunnelNexthop.class, new TunnelNexthopKey(ipPrefix));
324         InstanceIdentifier<TunnelNexthop> id = idBuilder.build();
325         // remove from DS     
326         delete(LogicalDatastoreType.OPERATIONAL, id);
327     }
328
329     private void removeVpnNexthopFromDS(long vpnId, String ipPrefix) {
330
331         InstanceIdentifierBuilder<VpnNexthop> idBuilder = InstanceIdentifier.builder(L3nexthop.class)
332                 .child(VpnNexthops.class, new VpnNexthopsKey(vpnId))
333                 .child(VpnNexthop.class, new VpnNexthopKey(ipPrefix));
334         InstanceIdentifier<VpnNexthop> id = idBuilder.build();
335         // remove from DS
336         delete(LogicalDatastoreType.OPERATIONAL, id);
337     }
338
339  
340     public void removeLocalNextHop(String vpnName, String ipAddress) {
341
342         long vpnId = getVpnId(vpnName);
343
344         VpnNexthop nh = getVpnNexthop(vpnId, ipAddress);
345         if (nh != null) {
346             // how to inform and remove dependent FIB entries??
347             // we need to do it before the group is removed
348             
349             // remove Group ...
350             
351             //update MD-SAL DS
352             removeVpnNexthopFromDS(vpnId, ipAddress);
353         } else {
354             //throw error
355         }
356
357     }
358
359     public void removeRemoteNextHop(long dpnId, String ipAddress) {
360
361         TunnelNexthop nh = getTunnelNexthop(dpnId, ipAddress);
362         if (nh != null) {
363             // how to inform and remove dependent FIB entries??
364             // we need to do it before the group is removed
365
366             // remove Group ...
367             //update MD-SAL DS
368             removeTunnelNexthopFromDS(dpnId, ipAddress);
369         } else {
370             //throw error
371         }
372
373     }
374
375     @Override
376     public Future<RpcResult<GetEgressPointerOutput>> getEgressPointer(
377             GetEgressPointerInput input) {
378         long egressGroupId =
379                 getNextHopPointer(input.getDpnId(), input.getVpnId(), input.getIpPrefix(), input.getNexthopIp());
380
381         GetEgressPointerOutputBuilder output = new GetEgressPointerOutputBuilder();
382         output.setEgressPointer(egressGroupId);
383
384         RpcResult<GetEgressPointerOutput> result = null;
385         //Rpcs.<GetEgressPointerOutput> getRpcResult(false, output.build());
386         return Futures.immediateFuture(result); 
387     }
388
389     private <T extends DataObject> Optional<T> read(LogicalDatastoreType datastoreType,
390             InstanceIdentifier<T> path) {
391
392         ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
393
394         Optional<T> result = Optional.absent();
395         try {
396             result = tx.read(datastoreType, path).get();
397         } catch (Exception e) {
398             throw new RuntimeException(e);
399         }
400
401         return result;
402     }
403
404     private <T extends DataObject> void asyncWrite(LogicalDatastoreType datastoreType,
405             InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
406         WriteTransaction tx = broker.newWriteOnlyTransaction();
407         tx.put(datastoreType, path, data, true);
408         Futures.addCallback(tx.submit(), callback);
409     }
410
411
412     private <T extends DataObject> void delete(LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
413         WriteTransaction tx = broker.newWriteOnlyTransaction();
414         tx.delete(datastoreType, path);
415         Futures.addCallback(tx.submit(), DEFAULT_CALLBACK);
416     }
417
418 }