030a6c3fc9223afa93e7e7e28af2d8a13f96b881
[netvirt.git] /
1 /*
2  * Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.netvirt.vpnmanager;
9
10 import com.google.common.base.Optional;
11 import com.google.common.util.concurrent.CheckedFuture;
12 import com.google.common.util.concurrent.FutureCallback;
13 import com.google.common.util.concurrent.Futures;
14 import com.google.common.util.concurrent.ListenableFuture;
15 import com.google.common.util.concurrent.ThreadFactoryBuilder;
16 import java.util.ArrayList;
17 import java.util.List;
18 import java.util.concurrent.Callable;
19 import java.util.concurrent.ConcurrentHashMap;
20 import java.util.concurrent.ConcurrentMap;
21 import java.util.concurrent.ExecutionException;
22 import java.util.concurrent.ExecutorService;
23 import java.util.concurrent.Executors;
24 import java.util.concurrent.ThreadFactory;
25 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
26 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
27 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
28 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
29 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
30 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
31 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
32 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
33 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
34 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnAfConfig;
35 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
36 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.VpnTargets;
37 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.vpntargets.VpnTarget;
38 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIds;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnTargetsBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
45
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpntargets.VpnTargetBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpntargets.VpnTargetKey;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.Vpn;
49 import org.opendaylight.yangtools.concepts.ListenerRegistration;
50 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53
54 public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInstance, VpnInstanceListener>
55         implements AutoCloseable {
56     private static final Logger LOG = LoggerFactory.getLogger(VpnInstanceListener.class);
57     private ListenerRegistration<DataChangeListener> listenerRegistration;
58     private final DataBroker dataBroker;
59     private final IBgpManager bgpManager;
60     private final IdManagerService idManager;
61     private final VpnInterfaceManager vpnInterfaceManager;
62     private final IFibManager fibManager;
63     private static final ThreadFactory threadFactory = new ThreadFactoryBuilder()
64             .setNameFormat("NV-VpnMgr-%d").build();
65     private ExecutorService executorService = Executors.newSingleThreadExecutor(threadFactory);
66     private ConcurrentMap<String, Runnable> vpnOpMap = new ConcurrentHashMap<String, Runnable>();
67
68     public VpnInstanceListener(final DataBroker dataBroker, final IBgpManager bgpManager,
69                                final IdManagerService idManager,
70                                final VpnInterfaceManager vpnInterfaceManager,
71                                final IFibManager fibManager) {
72         super(VpnInstance.class, VpnInstanceListener.class);
73         this.dataBroker = dataBroker;
74         this.bgpManager = bgpManager;
75         this.idManager = idManager;
76         this.vpnInterfaceManager = vpnInterfaceManager;
77         this.fibManager = fibManager;
78     }
79
80     public void start() {
81         LOG.info("{} start", getClass().getSimpleName());
82         registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
83     }
84
85     @Override
86     protected InstanceIdentifier<VpnInstance> getWildCardPath() {
87         return InstanceIdentifier.create(VpnInstances.class).child(VpnInstance.class);
88     }
89
90     @Override
91     protected VpnInstanceListener getDataTreeChangeListener() {
92         return VpnInstanceListener.this;
93     }
94
95     void notifyTaskIfRequired(String vpnName) {
96         Runnable notifyTask = vpnOpMap.remove(vpnName);
97         if (notifyTask == null) {
98             LOG.trace("VpnInstanceListener update: No Notify Task queued for vpnName {}", vpnName);
99             return;
100         }
101         executorService.execute(notifyTask);
102     }
103
104     private void waitForOpRemoval(String rd, String vpnName) {
105         //wait till DCN for update on VPN Instance Op Data signals that vpn interfaces linked to this vpn instance is zero
106         //TODO(vpnteam): Entire code would need refactoring to listen only on the parent object - VPNInstance
107         VpnInstanceOpDataEntry vpnOpEntry = null;
108         Long intfCount = 0L;
109         Long currentIntfCount = 0L;
110         Integer retryCount = 3;
111         long timeout = VpnConstants.MIN_WAIT_TIME_IN_MILLISECONDS;
112         Optional<VpnInstanceOpDataEntry> vpnOpValue = null;
113         vpnOpValue = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
114                 VpnUtil.getVpnInstanceOpDataIdentifier(rd));
115
116         if ((vpnOpValue != null) && (vpnOpValue.isPresent())) {
117             vpnOpEntry = vpnOpValue.get();
118             List<VpnToDpnList> dpnToVpns = vpnOpEntry.getVpnToDpnList();
119             if (dpnToVpns != null) {
120                 for (VpnToDpnList dpn : dpnToVpns) {
121                     if (dpn.getVpnInterfaces() != null) {
122                         intfCount = intfCount + dpn.getVpnInterfaces().size();
123                     }
124                 }
125             }
126             //intfCount = vpnOpEntry.getVpnInterfaceCount();
127             while (true) {
128                 if (intfCount > 0) {
129                     // Minimum wait time of 5 seconds for one VPN Interface clearance (inclusive of full trace on)
130                     timeout = intfCount * VpnConstants.MIN_WAIT_TIME_IN_MILLISECONDS;
131                     // Maximum wait time of 90 seconds for all VPN Interfaces clearance (inclusive of full trace on)
132                     if (timeout > VpnConstants.MAX_WAIT_TIME_IN_MILLISECONDS) {
133                         timeout = VpnConstants.MAX_WAIT_TIME_IN_MILLISECONDS;
134                     }
135                     LOG.info("VPNInstance removal count of interface at {} for for rd {}, vpnname {}",
136                             intfCount, rd, vpnName);
137                 }
138                 LOG.info("VPNInstance removal thread waiting for {} seconds for rd {}, vpnname {}",
139                         (timeout / 1000), rd, vpnName);
140
141                 try {
142                     Thread.sleep(timeout);
143                 } catch (InterruptedException e) {
144                 }
145
146                 // Check current interface count
147                 vpnOpValue = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
148                         VpnUtil.getVpnInstanceOpDataIdentifier(rd));
149                 if ((vpnOpValue != null) && (vpnOpValue.isPresent())) {
150                     vpnOpEntry = vpnOpValue.get();
151                     dpnToVpns = vpnOpEntry.getVpnToDpnList();
152                     currentIntfCount = 0L;
153                     if (dpnToVpns != null) {
154                         for (VpnToDpnList dpn : dpnToVpns) {
155                             if (dpn.getVpnInterfaces() != null) {
156                                 currentIntfCount = currentIntfCount + dpn.getVpnInterfaces().size();
157                             }
158                         }
159                     }
160                     if ((currentIntfCount == 0) || (currentIntfCount >= intfCount)) {
161                         // Either the FibManager completed its job to cleanup all vpnInterfaces in VPN
162                         // OR
163                         // There is no progress by FibManager in removing all the interfaces even after good time!
164                         // In either case, let us quit and take our chances.
165                         //TODO(vpnteam): L3VPN refactoring to take care of this case.
166                         if ((dpnToVpns == null) || dpnToVpns.size() <= 0) {
167                             LOG.info("VPN Instance vpn {} rd {} ready for removal, exiting wait loop", vpnName, rd);
168                             break;
169                         } else {
170                             if (retryCount > 0) {
171                                 retryCount--;
172                                 LOG.info("Retrying clearing vpn with vpnname {} rd {} since current interface count {} ", vpnName, rd, currentIntfCount);
173                                 if (currentIntfCount > 0) {
174                                     intfCount = currentIntfCount;
175                                 } else {
176                                     LOG.info("Current interface count is zero, but instance Op for vpn {} and rd {} not cleared yet. Waiting for 5 more seconds.", vpnName, rd);
177                                     intfCount = 1L;
178                                 }
179                             } else {
180                                 LOG.info("VPNInstance bailing out of wait loop as current interface count is {} and max retries exceeded for for vpnName {}, rd {}",
181                                         currentIntfCount, vpnName, rd);
182                                 break;
183                             }
184                         }
185                     }
186                 } else {
187                     // There is no VPNOPEntry.  Something else happened on the system !
188                     // So let us quit and take our chances.
189                     //TODO(vpnteam): L3VPN refactoring to take care of this case.
190                     break;
191                 }
192             }
193         }
194         LOG.info("Returned out of waiting for  Op Data removal for rd {}, vpnname {}", rd, vpnName);
195     }
196     @Override
197     protected void remove(InstanceIdentifier<VpnInstance> identifier, VpnInstance del) {
198         LOG.trace("Remove VPN event key: {}, value: {}", identifier, del);
199         final String vpnName = del.getVpnInstanceName();
200         final String rd = del.getIpv4Family().getRouteDistinguisher();
201         final long vpnId = VpnUtil.getVpnId(dataBroker, vpnName);
202         Optional<VpnInstanceOpDataEntry> vpnOpValue = null;
203
204         //TODO(vpnteam): Entire code would need refactoring to listen only on the parent object - VPNInstance
205         try {
206             if ((rd != null) && (!rd.isEmpty())) {
207                 vpnOpValue = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
208                         VpnUtil.getVpnInstanceOpDataIdentifier(rd));
209             } else {
210                 vpnOpValue = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
211                         VpnUtil.getVpnInstanceOpDataIdentifier(vpnName));
212             }
213         } catch (Exception e) {
214             LOG.error("Exception when attempting to retrieve VpnInstanceOpDataEntry for VPN {}. ", vpnName, e);
215             return;
216         }
217
218         if (vpnOpValue == null || !vpnOpValue.isPresent()) {
219             LOG.error("Unable to retrieve VpnInstanceOpDataEntry for VPN {}. ", vpnName);
220             return;
221         }
222
223         DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
224         dataStoreCoordinator.enqueueJob("VPN-" + vpnName,
225                 new DeleteVpnInstanceWorker(idManager, dataBroker, del));
226     }
227
228     private class DeleteVpnInstanceWorker implements Callable<List<ListenableFuture<Void>>> {
229         IdManagerService idManager;
230         DataBroker broker;
231         VpnInstance vpnInstance;
232
233         public DeleteVpnInstanceWorker(IdManagerService idManager,
234                                        DataBroker broker,
235                                        VpnInstance value) {
236             this.idManager = idManager;
237             this.broker = broker;
238             this.vpnInstance = value;
239         }
240
241         @Override
242         public List<ListenableFuture<Void>> call() throws Exception {
243             final String vpnName = vpnInstance.getVpnInstanceName();
244             final String rd = vpnInstance.getIpv4Family().getRouteDistinguisher();
245             final long vpnId = VpnUtil.getVpnId(broker, vpnName);
246             WriteTransaction writeTxn = broker.newWriteOnlyTransaction();
247             if ((rd != null) && (!rd.isEmpty())) {
248                 waitForOpRemoval(rd, vpnName);
249             } else {
250                 waitForOpRemoval(vpnName, vpnName);
251             }
252
253             // Clean up VpnInstanceToVpnId from Config DS
254             VpnUtil.removeVpnIdToVpnInstance(broker, vpnId, writeTxn);
255             VpnUtil.removeVpnInstanceToVpnId(broker, vpnName, writeTxn);
256             LOG.trace("Removed vpnIdentifier for  rd{} vpnname {}", rd, vpnName);
257             if (rd != null) {
258                 synchronized (vpnName.intern()) {
259                     fibManager.removeVrfTable(broker, rd, null);
260                 }
261                 try {
262                     bgpManager.deleteVrf(rd, false);
263                 } catch (Exception e) {
264                     LOG.error("Exception when removing VRF from BGP for RD {} in VPN {} exception " + e, rd, vpnName);
265                 }
266
267                 // Clean up VPNExtraRoutes Operational DS
268                 InstanceIdentifier<Vpn> vpnToExtraroute = VpnUtil.getVpnToExtrarouteIdentifier(rd);
269                 Optional<Vpn> optVpnToExtraroute = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, vpnToExtraroute);
270                 if (optVpnToExtraroute.isPresent()) {
271                     VpnUtil.removeVpnExtraRouteForVpn(broker, rd, writeTxn);
272                 }
273
274                 // Clean up VPNInstanceOpDataEntry
275                 VpnUtil.removeVpnOpInstance(broker, rd, writeTxn);
276             } else {
277                 // Clean up FIB Entries Config DS
278                 synchronized (vpnName.intern()) {
279                     fibManager.removeVrfTable(broker, vpnName, null);
280                 }
281                 // Clean up VPNExtraRoutes Operational DS
282                 InstanceIdentifier<Vpn> vpnToExtraroute = VpnUtil.getVpnToExtrarouteIdentifier(vpnName);
283                 Optional<Vpn> optVpnToExtraroute = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, vpnToExtraroute);
284                 if (optVpnToExtraroute.isPresent()) {
285                     VpnUtil.removeVpnExtraRouteForVpn(broker, vpnName, writeTxn);
286                 }
287
288                 // Clean up VPNInstanceOpDataEntry
289                 VpnUtil.removeVpnOpInstance(broker, vpnName, writeTxn);
290             }
291             // Clean up PrefixToInterface Operational DS
292             VpnUtil.removePrefixToInterfaceForVpnId(broker, vpnId, writeTxn);
293
294             // Clean up L3NextHop Operational DS
295             VpnUtil.removeL3nexthopForVpnId(broker, vpnId, writeTxn);
296
297             // Release the ID used for this VPN back to IdManager
298             VpnUtil.releaseId(idManager, VpnConstants.VPN_IDPOOL_NAME, vpnName);
299
300             List<ListenableFuture<Void>> futures = new ArrayList<>();
301             futures.add(writeTxn.submit());
302             return futures;
303         }
304     }
305
306     @Override
307     protected void update(InstanceIdentifier<VpnInstance> identifier,
308                           VpnInstance original, VpnInstance update) {
309         LOG.trace("Update VPN event key: {}, value: {}", identifier, update);
310     }
311
312     @Override
313     protected void add(final InstanceIdentifier<VpnInstance> identifier, final VpnInstance value) {
314         LOG.trace("Add VPN event key: {}, value: {}", identifier, value);
315         final VpnAfConfig config = value.getIpv4Family();
316         final String rd = config.getRouteDistinguisher();
317         final String vpnName = value.getVpnInstanceName();
318
319         DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
320         dataStoreCoordinator.enqueueJob("VPN-" + vpnName,
321                 new AddVpnInstanceWorker(idManager, vpnInterfaceManager, dataBroker, value));
322     }
323
324     private class AddVpnInstanceWorker implements Callable<List<ListenableFuture<Void>>> {
325         IdManagerService idManager;
326         VpnInterfaceManager vpnInterfaceManager;
327         VpnInstance vpnInstance;
328         DataBroker broker;
329
330         public AddVpnInstanceWorker(IdManagerService idManager,
331                                     VpnInterfaceManager vpnInterfaceManager,
332                                     DataBroker broker,
333                                     VpnInstance value) {
334             this.idManager = idManager;
335             this.vpnInterfaceManager = vpnInterfaceManager;
336             this.broker = broker;
337             this.vpnInstance = value;
338         }
339
340         @Override
341         public List<ListenableFuture<Void>> call() throws Exception {
342             // If another renderer(for eg : CSS) needs to be supported, check can be performed here
343             // to call the respective helpers.
344             final VpnAfConfig config = vpnInstance.getIpv4Family();
345             final String rd = config.getRouteDistinguisher();
346             WriteTransaction writeConfigTxn = broker.newWriteOnlyTransaction();
347             WriteTransaction writeOperTxn = broker.newWriteOnlyTransaction();
348             addVpnInstance(vpnInstance, writeConfigTxn, writeOperTxn);
349             CheckedFuture<Void, TransactionCommitFailedException> checkFutures = writeOperTxn.submit();
350             try {
351                 checkFutures.get();
352             } catch (InterruptedException | ExecutionException e) {
353                 LOG.error("Error creating vpn {} ", vpnInstance.getVpnInstanceName());
354                 throw new RuntimeException(e.getMessage());
355             }
356             List<ListenableFuture<Void>> futures = new ArrayList<>();
357             futures.add(writeConfigTxn.submit());
358             ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
359             if (rd != null) {
360                 Futures.addCallback(listenableFuture,
361                         new AddBgpVrfWorker(config , vpnInstance.getVpnInstanceName()));
362             }
363             return futures;
364         }
365     }
366
367     private void addVpnInstance(VpnInstance value, WriteTransaction writeConfigTxn,
368                                 WriteTransaction writeOperTxn) {
369         VpnAfConfig config = value.getIpv4Family();
370         String rd = config.getRouteDistinguisher();
371         String vpnInstanceName = value.getVpnInstanceName();
372
373         long vpnId = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME, vpnInstanceName);
374         if (vpnId == 0) {
375             LOG.error("Unable to fetch label from Id Manager. Bailing out of adding operational data for Vpn Instance {}", value.getVpnInstanceName());
376             return;
377         }
378         LOG.trace("VPN instance to ID generated.");
379         org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance
380                 vpnInstanceToVpnId = VpnUtil.getVpnInstanceToVpnId(vpnInstanceName, vpnId, (rd != null) ? rd
381                 : vpnInstanceName);
382
383         if (writeConfigTxn != null) {
384             writeConfigTxn.put(LogicalDatastoreType.CONFIGURATION,
385                     VpnUtil.getVpnInstanceToVpnIdIdentifier(vpnInstanceName),
386                     vpnInstanceToVpnId, true);
387         } else {
388              TransactionUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
389                      VpnUtil.getVpnInstanceToVpnIdIdentifier(vpnInstanceName),
390                      vpnInstanceToVpnId, TransactionUtil.DEFAULT_CALLBACK);
391         }
392
393         VpnIds vpnIdToVpnInstance = VpnUtil.getVpnIdToVpnInstance(vpnId, value.getVpnInstanceName(),
394                 (rd != null) ? rd : value.getVpnInstanceName(), (rd != null)/*isExternalVpn*/);
395
396         if (writeConfigTxn != null) {
397             writeConfigTxn.put(LogicalDatastoreType.CONFIGURATION,
398                     VpnUtil.getVpnIdToVpnInstanceIdentifier(vpnId),
399                     vpnIdToVpnInstance, true);
400         } else {
401              TransactionUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
402                      VpnUtil.getVpnIdToVpnInstanceIdentifier(vpnId),
403                      vpnIdToVpnInstance, TransactionUtil.DEFAULT_CALLBACK);
404         }
405
406         try {
407             String cachedTransType = fibManager.getConfTransType();
408             LOG.trace("Value for confTransportType is " + cachedTransType);
409             if (cachedTransType.equals("Invalid")) {
410                 try {
411                     fibManager.setConfTransType("L3VPN", "VXLAN");
412                 } catch (Exception e) {
413                     LOG.trace("Exception caught setting the cached value for transportType");
414                     LOG.error(e.getMessage());
415                 }
416             } else {
417                 LOG.trace(":cached val is neither unset/invalid. NO-op.");
418             }
419         } catch (Exception e) {
420             LOG.error(e.getMessage());
421         }
422
423         if (rd == null) {
424             VpnInstanceOpDataEntryBuilder builder =
425                     new VpnInstanceOpDataEntryBuilder().setVrfId(vpnInstanceName).setVpnId(vpnId)
426                             .setVpnInstanceName(vpnInstanceName);
427             if (writeOperTxn != null) {
428                 writeOperTxn.merge(LogicalDatastoreType.OPERATIONAL,
429                         VpnUtil.getVpnInstanceOpDataIdentifier(vpnInstanceName),
430                         builder.build(), true);
431             } else {
432                  TransactionUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
433                          VpnUtil.getVpnInstanceOpDataIdentifier(vpnInstanceName),
434                          builder.build(), TransactionUtil.DEFAULT_CALLBACK);
435             }
436         } else {
437             VpnInstanceOpDataEntryBuilder builder = new VpnInstanceOpDataEntryBuilder()
438                     .setVrfId(rd).setVpnId(vpnId).setVpnInstanceName(vpnInstanceName);
439
440             List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpntargets.VpnTarget> opVpnTargetList = new ArrayList<>();
441             VpnTargets vpnTargets = config.getVpnTargets();
442             if (vpnTargets != null) {
443                 List<VpnTarget> vpnTargetList = vpnTargets.getVpnTarget();
444                 if (vpnTargetList != null) {
445                     for (VpnTarget vpnTarget : vpnTargetList) {
446                         VpnTargetBuilder vpnTargetBuilder = new VpnTargetBuilder().setKey(new VpnTargetKey(vpnTarget.getKey().getVrfRTValue()))
447                                         .setVrfRTType(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
448                                                 .instance.op.data.vpn.instance.op.data.entry.vpntargets.VpnTarget.VrfRTType
449                                                 .forValue(vpnTarget.getVrfRTType().getIntValue())).setVrfRTValue(vpnTarget.getVrfRTValue());
450                         opVpnTargetList.add(vpnTargetBuilder.build());
451                     }
452                 }
453             }
454             VpnTargetsBuilder vpnTargetsBuilder = new VpnTargetsBuilder().setVpnTarget(opVpnTargetList);
455             builder.setVpnTargets(vpnTargetsBuilder.build());
456
457             if (writeOperTxn != null) {
458                 writeOperTxn.merge(LogicalDatastoreType.OPERATIONAL,
459                         VpnUtil.getVpnInstanceOpDataIdentifier(rd),
460                         builder.build(), true);
461             } else {
462                  TransactionUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
463                         VpnUtil.getVpnInstanceOpDataIdentifier(rd),
464                         builder.build(), TransactionUtil.DEFAULT_CALLBACK);
465             }
466         }
467     }
468
469
470     private class AddBgpVrfWorker implements FutureCallback<List<Void>> {
471         VpnAfConfig config;
472         String vpnName;
473
474         public AddBgpVrfWorker(VpnAfConfig config, String vpnName)  {
475             this.config = config;
476             this.vpnName = vpnName;
477         }
478
479         /**
480          * @param voids
481          * This implies that all the future instances have returned success. -- TODO: Confirm this
482          */
483         @Override
484         public void onSuccess(List<Void> voids) {
485             String rd = config.getRouteDistinguisher();
486             if (rd != null) {
487                 List<VpnTarget> vpnTargetList = config.getVpnTargets().getVpnTarget();
488
489                 List<String> ertList = new ArrayList<String>();
490                 List<String> irtList = new ArrayList<String>();
491
492                 for (VpnTarget vpnTarget : vpnTargetList) {
493                     if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ExportExtcommunity) {
494                         ertList.add(vpnTarget.getVrfRTValue());
495                     }
496                     if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ImportExtcommunity) {
497                         irtList.add(vpnTarget.getVrfRTValue());
498                     }
499                     if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.Both) {
500                         ertList.add(vpnTarget.getVrfRTValue());
501                         irtList.add(vpnTarget.getVrfRTValue());
502                     }
503                 }
504
505                 try {
506                     bgpManager.addVrf(rd, irtList, ertList);
507                 } catch (Exception e) {
508                     LOG.error("Exception when adding VRF to BGP", e);
509                     return;
510                 }
511                 vpnInterfaceManager.handleVpnsExportingRoutes(this.vpnName, rd);
512             }
513         }
514         /**
515          *
516          * @param throwable
517          * This method is used to handle failure callbacks.
518          * If more retry needed, the retrycount is decremented and mainworker is executed again.
519          * After retries completed, rollbackworker is executed.
520          * If rollbackworker fails, this is a double-fault. Double fault is logged and ignored.
521          */
522
523         @Override
524         public void onFailure(Throwable throwable) {
525             LOG.warn("Job: failed with exception: ", throwable);
526         }
527     }
528
529     public boolean isVPNConfigured() {
530
531         InstanceIdentifier<VpnInstances> vpnsIdentifier =
532                 InstanceIdentifier.builder(VpnInstances.class).build();
533         Optional<VpnInstances> optionalVpns = TransactionUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
534                 vpnsIdentifier);
535         if (!optionalVpns.isPresent() ||
536                 optionalVpns.get().getVpnInstance() == null ||
537                 optionalVpns.get().getVpnInstance().isEmpty()) {
538             LOG.trace("No VPNs configured.");
539             return false;
540         }
541         LOG.trace("VPNs are configured on the system.");
542         return true;
543     }
544
545     protected VpnInstanceOpDataEntry getVpnInstanceOpData(String rd) {
546         InstanceIdentifier<VpnInstanceOpDataEntry> id = VpnUtil.getVpnInstanceOpDataIdentifier(rd);
547         Optional<VpnInstanceOpDataEntry> vpnInstanceOpData =
548                 TransactionUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
549         if(vpnInstanceOpData.isPresent()) {
550             return vpnInstanceOpData.get();
551         }
552         return null;
553     }
554 }