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