Multiple fixes in various modules
[netvirt.git] / vpnservice / vpnmanager / vpnmanager-impl / src / main / java / org / opendaylight / netvirt / vpnmanager / VpnManager.java
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.vpnmanager;
9
10 import java.util.ArrayList;
11 import java.util.List;
12 import java.util.concurrent.*;
13
14 import com.google.common.util.concurrent.*;
15
16 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
17 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
20 import org.opendaylight.controller.md.sal.binding.api.NotificationService;
21 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
22 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
23 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
24 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.vpntargets.VpnTarget;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIds;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
29
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op
31         .data.entry.VpnToDpnList;
32 import org.opendaylight.yangtools.concepts.ListenerRegistration;
33 import org.opendaylight.yangtools.yang.binding.DataObject;
34 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
35 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
36 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
37 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnAfConfig;
38 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
39 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
40 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstanceKey;
41 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
42 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
49 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52
53 import com.google.common.base.Optional;
54
55 public class VpnManager extends AbstractDataChangeListener<VpnInstance> implements AutoCloseable {
56     private static final Logger LOG = LoggerFactory.getLogger(VpnManager.class);
57     private ListenerRegistration<DataChangeListener> listenerRegistration, fibListenerRegistration;
58     private ConcurrentMap<String, Runnable> vpnOpMap = new ConcurrentHashMap<String, Runnable>();
59     private ExecutorService executorService = Executors.newSingleThreadExecutor();
60     private final DataBroker broker;
61     private final IBgpManager bgpManager;
62     private IdManagerService idManager;
63     private VpnInterfaceManager vpnInterfaceManager;
64     private final FibEntriesListener fibListener;
65     private NotificationService notificationService;
66
67     private static final FutureCallback<Void> DEFAULT_CALLBACK =
68             new FutureCallback<Void>() {
69                 @Override
70                 public void onSuccess(Void result) {
71                     LOG.debug("Success in Datastore operation");
72                 }
73
74                 @Override
75                 public void onFailure(Throwable error) {
76                     LOG.error("Error in Datastore operation", error);
77                 };
78             };
79
80     /**
81      * Listens for data change related to VPN Instance
82      * Informs the BGP about VRF information
83      *
84      * @param db dataBroker reference
85      * @param bgpManager Used to advertise routes to the BGP Router
86      */
87     public VpnManager(final DataBroker db, final IBgpManager bgpManager) {
88         super(VpnInstance.class);
89         broker = db;
90         this.bgpManager = bgpManager;
91         this.fibListener = new FibEntriesListener();
92         registerListener(db);
93     }
94
95     private void registerListener(final DataBroker db) {
96         try {
97             listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
98                     getWildCardPath(), VpnManager.this, DataChangeScope.SUBTREE);
99             fibListenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
100                     getFibEntryListenerPath(), fibListener, DataChangeScope.BASE);
101         } catch (final Exception e) {
102             LOG.error("VPN Service DataChange listener registration fail !", e);
103             throw new IllegalStateException("VPN Service registration Listener failed.", e);
104         }
105     }
106
107     public void setIdManager(IdManagerService idManager) {
108         this.idManager = idManager;
109     }
110
111     public void setVpnInterfaceManager(VpnInterfaceManager vpnInterfaceManager) {
112         this.vpnInterfaceManager = vpnInterfaceManager;
113     }
114
115     private void waitForOpRemoval(String rd, String vpnName) {
116         //wait till DCN for update on VPN Instance Op Data signals that vpn interfaces linked to this vpn instance is zero
117         //TODO(vpnteam): Entire code would need refactoring to listen only on the parent object - VPNInstance
118         VpnInstanceOpDataEntry vpnOpEntry = null;
119         Long intfCount = 0L;
120         Long currentIntfCount = 0L;
121         Integer retryCount = 1;
122         long timeout = VpnConstants.MIN_WAIT_TIME_IN_MILLISECONDS;
123         Optional<VpnInstanceOpDataEntry> vpnOpValue = null;
124         vpnOpValue = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
125                     VpnUtil.getVpnInstanceOpDataIdentifier(rd));
126
127         if ((vpnOpValue != null) && (vpnOpValue.isPresent())) {
128             vpnOpEntry = vpnOpValue.get();
129             List<VpnToDpnList> dpnToVpns = vpnOpEntry.getVpnToDpnList();
130             if (dpnToVpns != null) {
131                 for (VpnToDpnList dpn : dpnToVpns) {
132                     if (dpn.getVpnInterfaces() != null) {
133                         intfCount = intfCount + dpn.getVpnInterfaces().size();
134                     }
135                 }
136             }
137             //intfCount = vpnOpEntry.getVpnInterfaceCount();
138             while (true) {
139                 if (intfCount > 0) {
140                     // Minimum wait time of 5 seconds for one VPN Interface clearance (inclusive of full trace on)
141                     timeout = intfCount * VpnConstants.MIN_WAIT_TIME_IN_MILLISECONDS;
142                     // Maximum wait time of 90 seconds for all VPN Interfaces clearance (inclusive of full trace on)
143                     if (timeout > VpnConstants.MAX_WAIT_TIME_IN_MILLISECONDS) {
144                         timeout = VpnConstants.MAX_WAIT_TIME_IN_MILLISECONDS;
145                     }
146                     LOG.info("VPNInstance removal count of interface at {} for for rd {}, vpnname {}",
147                             intfCount, rd, vpnName);
148                 }
149                 LOG.info("VPNInstance removal thread waiting for {} seconds for rd {}, vpnname {}",
150                         (timeout / 1000), rd, vpnName);
151
152                 try {
153                     Thread.sleep(timeout);
154                 } catch (java.lang.InterruptedException e) {
155                 }
156
157                 // Check current interface count
158                 vpnOpValue = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
159                         VpnUtil.getVpnInstanceOpDataIdentifier(rd));
160                 if ((vpnOpValue != null) && (vpnOpValue.isPresent())) {
161                     vpnOpEntry = vpnOpValue.get();
162                     dpnToVpns = vpnOpEntry.getVpnToDpnList();
163                     currentIntfCount = 0L;
164                     if (dpnToVpns != null) {
165                         for (VpnToDpnList dpn : dpnToVpns) {
166                             if (dpn.getVpnInterfaces() != null) {
167                                 currentIntfCount = currentIntfCount + dpn.getVpnInterfaces().size();
168                             }
169                         }
170                     }
171                     //currentIntfCount = vpnOpEntry.getVpnInterfaceCount();
172                     if ((currentIntfCount == 0) || (currentIntfCount >= intfCount)) {
173                         // Either the FibManager completed its job to cleanup all vpnInterfaces in VPN
174                         // OR
175                         // There is no progress by FibManager in removing all the interfaces even after good time!
176                         // In either case, let us quit and take our chances.
177                         //TODO(vpnteam): L3VPN refactoring to take care of this case.
178                         if (retryCount > 0) {
179                             retryCount--;
180                             LOG.info("Retrying clearing vpn with vpnname {} rd {} since currentIntfCount {} ", vpnName, rd, currentIntfCount);
181                             if (currentIntfCount > 0L){
182                                 LOG.info("Current interface count for vpn {} and rd {} is not zero and so retrying ...", vpnName, rd);
183                                 intfCount = currentIntfCount;
184                             } else {
185                                 LOG.info("Current interface count is zero but instance Op for vpn {} and rd {} not cleared yet. Waiting for 5 more seconds.", vpnName, rd);
186                                 intfCount = 1L;
187                             }
188                         } else {
189                             LOG.info("VPNInstance bailing out of wait loop as currentIntfCount is {} and max retries exceeded for for rd {}, vpnname {}",
190                                     currentIntfCount, rd, vpnName);
191                             break;
192                         }
193                     } else {
194                         // There is some progress by FibManager, so let us give it some more time!
195                         intfCount = currentIntfCount;
196                         retryCount = 1;
197                         LOG.info("current interface count {} for vpn {} and rd {} showing progress, waiting for it to drive to 0.", currentIntfCount, vpnName, rd);
198                     }
199                 } else {
200                     // There is no VPNOPEntry.  Something else happened on the system !
201                     // So let us quit and take our chances.
202                     //TODO(vpnteam): L3VPN refactoring to take care of this case.
203                     break;
204                 }
205             }
206         }
207         LOG.info("Returned out of waiting for  Op Data removal for rd {}, vpnname {}", rd, vpnName);
208     }
209     @Override
210     protected void remove(InstanceIdentifier<VpnInstance> identifier, VpnInstance del) {
211         LOG.trace("Remove VPN event key: {}, value: {}", identifier, del);
212         final String vpnName = del.getVpnInstanceName();
213         final String rd = del.getIpv4Family().getRouteDistinguisher();
214         final long vpnId = VpnUtil.getVpnId(broker, vpnName);
215         Optional<VpnInstanceOpDataEntry> vpnOpValue = null;
216
217         //TODO(vpnteam): Entire code would need refactoring to listen only on the parent object - VPNInstance
218         try {
219             if ((rd != null) && (!rd.isEmpty())) {
220                 vpnOpValue = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
221                         VpnUtil.getVpnInstanceOpDataIdentifier(rd));
222             } else {
223                 vpnOpValue = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
224                         VpnUtil.getVpnInstanceOpDataIdentifier(vpnName));
225             }
226         } catch (Exception e) {
227             LOG.error("Exception when attempting to retrieve VpnInstanceOpDataEntry for VPN {}. ", vpnName, e);
228             return;
229         }
230
231         if (vpnOpValue == null || !vpnOpValue.isPresent()) {
232             LOG.error("Unable to retrieve VpnInstanceOpDataEntry for VPN {}. ", vpnName);
233             return;
234         }
235
236         DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
237         dataStoreCoordinator.enqueueJob("VPN-" + vpnName,
238                 new DeleteVpnInstanceWorker(idManager, broker, del));
239     }
240
241     private class DeleteVpnInstanceWorker implements Callable<List<ListenableFuture<Void>>> {
242         IdManagerService idManager;
243         DataBroker broker;
244         VpnInstance vpnInstance;
245
246         public DeleteVpnInstanceWorker(IdManagerService idManager,
247                                        DataBroker broker,
248                                        VpnInstance value) {
249             this.idManager = idManager;
250             this.broker = broker;
251             this.vpnInstance = value;
252         }
253
254         @Override
255         public List<ListenableFuture<Void>> call() throws Exception {
256             final String vpnName = vpnInstance.getVpnInstanceName();
257             final String rd = vpnInstance.getIpv4Family().getRouteDistinguisher();
258             final long vpnId = VpnUtil.getVpnId(broker, vpnName);
259             WriteTransaction writeTxn = broker.newWriteOnlyTransaction();
260             if ((rd != null) && (!rd.isEmpty())) {
261                 waitForOpRemoval(rd, vpnName);
262             } else {
263                 waitForOpRemoval(vpnName, vpnName);
264             }
265
266             // Clean up VpnInstanceToVpnId from Config DS
267             VpnUtil.removeVpnIdToVpnInstance(broker, vpnId, writeTxn);
268             VpnUtil.removeVpnInstanceToVpnId(broker, vpnName, writeTxn);
269
270             List<ListenableFuture<Void>> futures = new ArrayList<>();
271             futures.add(writeTxn.submit());
272             LOG.trace("Removed vpnIdentifier for  rd{} vpnname {}", rd, vpnName);
273             if (rd != null) {
274                 synchronized (rd.intern()) {
275                     try {
276                         bgpManager.deleteVrf(rd);
277                     } catch (Exception e) {
278                         LOG.error("Exception when removing VRF from BGP for RD {} in VPN {} exception " + e, rd, vpnName);
279                     }
280                 }
281
282                 // Clean up VPNExtraRoutes Operational DS
283                 VpnUtil.removeVpnExtraRouteForVpn(broker, rd, null);
284
285                 // Clean up VPNInstanceOpDataEntry
286                 VpnUtil.removeVpnOpInstance(broker, rd, null);
287             } else {
288                 // Clean up FIB Entries Config DS
289                 synchronized (vpnName.intern()) {
290                     VpnUtil.removeVrfTableForVpn(broker, vpnName, null);
291                 }
292                 // Clean up VPNExtraRoutes Operational DS
293                 VpnUtil.removeVpnExtraRouteForVpn(broker, vpnName, null);
294
295                 // Clean up VPNInstanceOpDataEntry
296                 VpnUtil.removeVpnOpInstance(broker, vpnName, null);
297             }
298             // Clean up PrefixToInterface Operational DS
299             VpnUtil.removePrefixToInterfaceForVpnId(broker, vpnId, null);
300
301             // Clean up L3NextHop Operational DS
302             VpnUtil.removeL3nexthopForVpnId(broker, vpnId, null);
303
304             // Release the ID used for this VPN back to IdManager
305             VpnUtil.releaseId(idManager, VpnConstants.VPN_IDPOOL_NAME, vpnName);
306
307             return futures;
308         }
309     }
310
311     @Override
312     protected void update(InstanceIdentifier<VpnInstance> identifier,
313                           VpnInstance original, VpnInstance update) {
314         LOG.trace("Update VPN event key: {}, value: {}", identifier, update);
315     }
316
317     @Override
318     protected void add(final InstanceIdentifier<VpnInstance> identifier, final VpnInstance value) {
319         LOG.trace("Add VPN event key: {}, value: {}", identifier, value);
320         final VpnAfConfig config = value.getIpv4Family();
321         final String rd = config.getRouteDistinguisher();
322         final String vpnName = value.getVpnInstanceName();
323
324         DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
325         dataStoreCoordinator.enqueueJob("VPN-" + vpnName,
326                 new AddVpnInstanceWorker(idManager, vpnInterfaceManager, broker, value));
327     }
328
329     private class AddVpnInstanceWorker implements Callable<List<ListenableFuture<Void>>> {
330         IdManagerService idManager;
331         VpnInterfaceManager vpnInterfaceManager;
332         VpnInstance vpnInstance;
333         DataBroker broker;
334
335         public AddVpnInstanceWorker(IdManagerService idManager,
336                                     VpnInterfaceManager vpnInterfaceManager,
337                                     DataBroker broker,
338                                     VpnInstance value) {
339             this.idManager = idManager;
340             this.vpnInterfaceManager = vpnInterfaceManager;
341             this.broker = broker;
342             this.vpnInstance = value;
343         }
344
345         @Override
346         public List<ListenableFuture<Void>> call() throws Exception {
347             // If another renderer(for eg : CSS) needs to be supported, check can be performed here
348             // to call the respective helpers.
349             final VpnAfConfig config = vpnInstance.getIpv4Family();
350             final String rd = config.getRouteDistinguisher();
351             WriteTransaction writeTxn = broker.newWriteOnlyTransaction();
352             addVpnInstance(vpnInstance, writeTxn);
353             List<ListenableFuture<Void>> futures = new ArrayList<>();
354             futures.add(writeTxn.submit());
355             ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
356             if (rd != null) {
357                 Futures.addCallback(listenableFuture,
358                         new AddBgpVrfWorker(config , vpnInstance.getVpnInstanceName()));
359             }
360             return futures;
361         }
362     }
363
364     private void addVpnInstance(VpnInstance value, WriteTransaction writeTxn) {
365         VpnAfConfig config = value.getIpv4Family();
366         String rd = config.getRouteDistinguisher();
367         String vpnInstanceName = value.getVpnInstanceName();
368
369         long vpnId = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME, vpnInstanceName);
370         LOG.trace("VPN instance to ID generated.");
371         org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance
372                 vpnInstanceToVpnId = VpnUtil.getVpnInstanceToVpnId(vpnInstanceName, vpnId, (rd != null) ? rd
373                 : vpnInstanceName);
374
375         if (writeTxn != null) {
376             writeTxn.put(LogicalDatastoreType.CONFIGURATION, VpnUtil.getVpnInstanceToVpnIdIdentifier(vpnInstanceName),
377                     vpnInstanceToVpnId, true);
378         } else {
379             syncWrite(LogicalDatastoreType.CONFIGURATION, VpnUtil.getVpnInstanceToVpnIdIdentifier(vpnInstanceName),
380                     vpnInstanceToVpnId, DEFAULT_CALLBACK);
381         }
382
383         org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIds
384                 vpnIdToVpnInstance = VpnUtil.getVpnIdToVpnInstance(vpnId, value.getVpnInstanceName(),
385                 (rd != null) ? rd : value.getVpnInstanceName(), (rd != null)/*isExternalVpn*/);
386
387         if (writeTxn != null) {
388             writeTxn.put(LogicalDatastoreType.CONFIGURATION,
389                     VpnUtil.getVpnIdToVpnInstanceIdentifier(vpnId),
390                     vpnIdToVpnInstance, true);
391         } else {
392             syncWrite(LogicalDatastoreType.CONFIGURATION,
393                     VpnUtil.getVpnIdToVpnInstanceIdentifier(vpnId),
394                     vpnIdToVpnInstance, DEFAULT_CALLBACK);
395         }
396
397         IFibManager fibManager = vpnInterfaceManager.getFibManager();
398         try {
399             String cachedTransType = fibManager.getConfTransType();
400             LOG.trace("Value for confTransportType is " + cachedTransType);
401             if (cachedTransType.equals("Invalid")) {
402                 try {
403                     fibManager.setConfTransType("L3VPN", "VXLAN");
404                 } catch (Exception e) {
405                     LOG.trace("Exception caught setting the cached value for transportType");
406                     LOG.error(e.getMessage());
407                 }
408             } else {
409                 LOG.trace(":cached val is neither unset/invalid. NO-op.");
410             }
411         } catch (Exception e) {
412             LOG.error(e.getMessage());
413         }
414
415         if (rd == null) {
416             VpnInstanceOpDataEntryBuilder builder =
417                     new VpnInstanceOpDataEntryBuilder().setVrfId(vpnInstanceName).setVpnId(vpnId)
418                             .setVpnInstanceName(vpnInstanceName)
419                             .setVpnInterfaceCount(0L).setActiveDpnCount(0L);
420             if (writeTxn != null) {
421                 writeTxn.merge(LogicalDatastoreType.OPERATIONAL, VpnUtil.getVpnInstanceOpDataIdentifier(vpnInstanceName),
422                         builder.build(), true);
423             } else {
424                 syncWrite(LogicalDatastoreType.OPERATIONAL, VpnUtil.getVpnInstanceOpDataIdentifier(vpnInstanceName),
425                         builder.build(), DEFAULT_CALLBACK);
426             }
427         } else {
428             VpnInstanceOpDataEntryBuilder builder =
429                     new VpnInstanceOpDataEntryBuilder().setVrfId(rd).setVpnId(vpnId).setVpnInstanceName(vpnInstanceName)
430                             .setVpnInterfaceCount(0L).setActiveDpnCount(0L);
431
432             if (writeTxn != null) {
433                 writeTxn.merge(LogicalDatastoreType.OPERATIONAL,
434                         VpnUtil.getVpnInstanceOpDataIdentifier(rd),
435                         builder.build(), true);
436             } else {
437                 syncWrite(LogicalDatastoreType.OPERATIONAL,
438                         VpnUtil.getVpnInstanceOpDataIdentifier(rd),
439                         builder.build(), DEFAULT_CALLBACK);
440             }
441         }
442     }
443
444
445     private class AddBgpVrfWorker implements FutureCallback<List<Void>> {
446         VpnAfConfig config;
447         String vpnName;
448
449         public AddBgpVrfWorker(VpnAfConfig config, String vpnName)  {
450             this.config = config;
451             this.vpnName = vpnName;
452         }
453
454         /**
455          * @param voids
456          * This implies that all the future instances have returned success. -- TODO: Confirm this
457          */
458         @Override
459         public void onSuccess(List<Void> voids) {
460             String rd = config.getRouteDistinguisher();
461             if (rd != null) {
462                 List<VpnTarget> vpnTargetList = config.getVpnTargets().getVpnTarget();
463
464                 List<String> ertList = new ArrayList<String>();
465                 List<String> irtList = new ArrayList<String>();
466
467                 for (VpnTarget vpnTarget : vpnTargetList) {
468                     if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ExportExtcommunity) {
469                         ertList.add(vpnTarget.getVrfRTValue());
470                     }
471                     if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ImportExtcommunity) {
472                         irtList.add(vpnTarget.getVrfRTValue());
473                     }
474                     if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.Both) {
475                         ertList.add(vpnTarget.getVrfRTValue());
476                         irtList.add(vpnTarget.getVrfRTValue());
477                     }
478                 }
479
480                 try {
481                     bgpManager.addVrf(rd, irtList, ertList);
482                 } catch (Exception e) {
483                     LOG.error("Exception when adding VRF to BGP", e);
484                     return;
485                 }
486                 vpnInterfaceManager.handleVpnsExportingRoutes(this.vpnName, rd);
487             }
488         }
489         /**
490          *
491          * @param throwable
492          * This method is used to handle failure callbacks.
493          * If more retry needed, the retrycount is decremented and mainworker is executed again.
494          * After retries completed, rollbackworker is executed.
495          * If rollbackworker fails, this is a double-fault. Double fault is logged and ignored.
496          */
497
498         @Override
499         public void onFailure(Throwable throwable) {
500             LOG.warn("Job: failed with exception: {}", throwable.getStackTrace());
501         }
502     }
503
504     public boolean isVPNConfigured() {
505
506         InstanceIdentifier<VpnInstances> vpnsIdentifier =
507                 InstanceIdentifier.builder(VpnInstances.class).build();
508         Optional<VpnInstances> optionalVpns = read( LogicalDatastoreType.CONFIGURATION,
509                 vpnsIdentifier);
510         if (!optionalVpns.isPresent() ||
511                 optionalVpns.get().getVpnInstance() == null ||
512                 optionalVpns.get().getVpnInstance().isEmpty()) {
513             LOG.trace("No VPNs configured.");
514             return false;
515         }
516         LOG.trace("VPNs are configured on the system.");
517         return true;
518     }
519
520     private InstanceIdentifier<?> getWildCardPath() {
521         return InstanceIdentifier.create(VpnInstances.class).child(VpnInstance.class);
522     }
523
524     private InstanceIdentifier<?> getFibEntryListenerPath() {
525         return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class)
526                 .child(VrfEntry.class);
527     }
528
529     private InstanceIdentifier<?> getVpnInstanceOpListenerPath() {
530         return InstanceIdentifier.create(VpnInstanceOpData.class).child(VpnInstanceOpDataEntry.class);
531     }
532
533     @Override
534     public void close() throws Exception {
535         if (listenerRegistration != null) {
536             try {
537                 listenerRegistration.close();
538             } catch (final Exception e) {
539                 LOG.error("Error when cleaning up Vpn DataChangeListener.", e);
540             }
541             listenerRegistration = null;
542         }
543         if (fibListenerRegistration != null) {
544             try {
545                 fibListenerRegistration.close();
546             } catch (final Exception e) {
547                 LOG.error("Error when cleaning up Fib entries DataChangeListener.", e);
548             }
549             fibListenerRegistration = null;
550         }
551         LOG.trace("VPN Manager Closed");
552     }
553
554     private <T extends DataObject> Optional<T> read(LogicalDatastoreType datastoreType,
555             InstanceIdentifier<T> path) {
556
557         ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
558
559         Optional<T> result = Optional.absent();
560         try {
561             result = tx.read(datastoreType, path).get();
562         } catch (Exception e) {
563             throw new RuntimeException(e);
564         }
565
566         return result;
567     }
568
569     private <T extends DataObject> void asyncWrite(LogicalDatastoreType datastoreType,
570             InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
571         WriteTransaction tx = broker.newWriteOnlyTransaction();
572         tx.put(datastoreType, path, data, true);
573         Futures.addCallback(tx.submit(), callback);
574     }
575
576     private <T extends DataObject> void syncWrite(LogicalDatastoreType datastoreType,
577                                                    InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
578         WriteTransaction tx = broker.newWriteOnlyTransaction();
579         tx.put(datastoreType, path, data, true);
580         CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
581         try {
582             futures.get();
583         } catch (InterruptedException | ExecutionException e) {
584             LOG.error("Error writing VPN instance to ID info to datastore (path, data) : ({}, {})", path, data);
585             throw new RuntimeException(e.getMessage());
586         }
587     }
588
589     protected VpnInstance getVpnInstance(String vpnInstanceName) {
590         return VpnUtil.getVpnInstance(broker, vpnInstanceName);
591     }
592
593     protected VpnInstanceOpDataEntry getVpnInstanceOpData(String rd) {
594         InstanceIdentifier<VpnInstanceOpDataEntry> id = VpnUtil.getVpnInstanceOpDataIdentifier(rd);
595         Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = read(LogicalDatastoreType.OPERATIONAL, id);
596         if(vpnInstanceOpData.isPresent()) {
597             return vpnInstanceOpData.get();
598         }
599         return null;
600     }
601
602     private class FibEntriesListener extends AbstractDataChangeListener<VrfEntry>  {
603
604         public FibEntriesListener() {
605             super(VrfEntry.class);
606         }
607
608         @Override
609         protected void remove(InstanceIdentifier<VrfEntry> identifier,
610                 VrfEntry del) {
611             LOG.trace("Remove Fib event - Key : {}, value : {} ", identifier, del);
612             final VrfTablesKey key = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class);
613             String rd = key.getRouteDistinguisher();
614             Long label = del.getLabel();
615             VpnInstanceOpDataEntry vpnInstanceOpData = getVpnInstanceOpData(rd);
616             if(vpnInstanceOpData != null) {
617                 List<Long> routeIds = vpnInstanceOpData.getRouteEntryId();
618                 if(routeIds == null) {
619                     LOG.debug("Fib Route entry is empty.");
620                     return;
621                 }
622                 LOG.debug("Removing label from vpn info - {}", label);
623                 routeIds.remove(label);
624                 asyncWrite(LogicalDatastoreType.OPERATIONAL, VpnUtil.getVpnInstanceOpDataIdentifier(rd),
625                            new VpnInstanceOpDataEntryBuilder(vpnInstanceOpData).setRouteEntryId(routeIds).build(), DEFAULT_CALLBACK);
626             } else {
627                 LOG.warn("No VPN Instance found for RD: {}", rd);
628             }
629         }
630
631         @Override
632         protected void update(InstanceIdentifier<VrfEntry> identifier,
633                 VrfEntry original, VrfEntry update) {
634             // TODO Auto-generated method stub
635
636         }
637
638         @Override
639         protected void add(InstanceIdentifier<VrfEntry> identifier,
640                            VrfEntry add) {
641             LOG.trace("Add Vrf Entry event - Key : {}, value : {}", identifier, add);
642             final VrfTablesKey key = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class);
643             String rd = key.getRouteDistinguisher();
644             Long label = add.getLabel();
645             VpnInstanceOpDataEntry vpn = getVpnInstanceOpData(rd);
646             if(vpn != null) {
647                 List<Long> routeIds = vpn.getRouteEntryId();
648                 if(routeIds == null) {
649                     routeIds = new ArrayList<>();
650                 }
651                 LOG.debug("Adding label to vpn info - {}", label);
652                 routeIds.add(label);
653                 asyncWrite(LogicalDatastoreType.OPERATIONAL, VpnUtil.getVpnInstanceOpDataIdentifier(rd),
654                            new VpnInstanceOpDataEntryBuilder(vpn).setRouteEntryId(routeIds).build(), DEFAULT_CALLBACK);
655             } else {
656                 LOG.warn("No VPN Instance found for RD: {}", rd);
657             }
658         }
659     }
660 }