Add missing license headers
[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.CheckedFuture;
15
16 import com.google.common.util.concurrent.ThreadFactoryBuilder;
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 import com.google.common.util.concurrent.FutureCallback;
55 import com.google.common.util.concurrent.Futures;
56
57 public class VpnManager extends AbstractDataChangeListener<VpnInstance> implements AutoCloseable {
58     private static final Logger LOG = LoggerFactory.getLogger(VpnManager.class);
59     private ListenerRegistration<DataChangeListener> listenerRegistration, fibListenerRegistration;
60     private ConcurrentMap<String, Runnable> vpnOpMap = new ConcurrentHashMap<String, Runnable>();
61     private ExecutorService executorService = Executors.newSingleThreadExecutor();
62     private final DataBroker broker;
63     private final IBgpManager bgpManager;
64     private IdManagerService idManager;
65     private VpnInterfaceManager vpnInterfaceManager;
66     private final FibEntriesListener fibListener;
67     private NotificationService notificationService;
68
69     private static final FutureCallback<Void> DEFAULT_CALLBACK =
70             new FutureCallback<Void>() {
71                 @Override
72                 public void onSuccess(Void result) {
73                     LOG.debug("Success in Datastore operation");
74                 }
75
76                 @Override
77                 public void onFailure(Throwable error) {
78                     LOG.error("Error in Datastore operation", error);
79                 };
80             };
81
82     /**
83      * Listens for data change related to VPN Instance
84      * Informs the BGP about VRF information
85      *
86      * @param db dataBroker reference
87      * @param bgpManager Used to advertise routes to the BGP Router
88      */
89     public VpnManager(final DataBroker db, final IBgpManager bgpManager) {
90         super(VpnInstance.class);
91         broker = db;
92         this.bgpManager = bgpManager;
93         this.fibListener = new FibEntriesListener();
94         registerListener(db);
95     }
96
97     private void registerListener(final DataBroker db) {
98         try {
99             listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
100                     getWildCardPath(), VpnManager.this, DataChangeScope.SUBTREE);
101             fibListenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
102                     getFibEntryListenerPath(), fibListener, DataChangeScope.BASE);
103         } catch (final Exception e) {
104             LOG.error("VPN Service DataChange listener registration fail !", e);
105             throw new IllegalStateException("VPN Service registration Listener failed.", e);
106         }
107     }
108
109     public void setIdManager(IdManagerService idManager) {
110         this.idManager = idManager;
111     }
112
113     public void setVpnInterfaceManager(VpnInterfaceManager vpnInterfaceManager) {
114         this.vpnInterfaceManager = vpnInterfaceManager;
115     }
116
117     private void waitForOpRemoval(String rd, String vpnName) {
118         //wait till DCN for update on VPN Instance Op Data signals that vpn interfaces linked to this vpn instance is zero
119         //TODO(vpnteam): Entire code would need refactoring to listen only on the parent object - VPNInstance
120         VpnInstanceOpDataEntry vpnOpEntry = null;
121         Long intfCount = 0L;
122         Long currentIntfCount = 0L;
123         Integer retryCount = 1;
124         long timeout = VpnConstants.MIN_WAIT_TIME_IN_MILLISECONDS;
125         Optional<VpnInstanceOpDataEntry> vpnOpValue = null;
126         vpnOpValue = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
127                     VpnUtil.getVpnInstanceOpDataIdentifier(rd));
128
129         if ((vpnOpValue != null) && (vpnOpValue.isPresent())) {
130             vpnOpEntry = vpnOpValue.get();
131             List<VpnToDpnList> dpnToVpns = vpnOpEntry.getVpnToDpnList();
132             if (dpnToVpns != null) {
133                 for (VpnToDpnList dpn : dpnToVpns) {
134                     if (dpn.getVpnInterfaces() != null) {
135                         intfCount = intfCount + dpn.getVpnInterfaces().size();
136                     }
137                 }
138             }
139             //intfCount = vpnOpEntry.getVpnInterfaceCount();
140             while (true) {
141                 if (intfCount > 0) {
142                     // Minimum wait time of 5 seconds for one VPN Interface clearance (inclusive of full trace on)
143                     timeout = intfCount * VpnConstants.MIN_WAIT_TIME_IN_MILLISECONDS;
144                     // Maximum wait time of 90 seconds for all VPN Interfaces clearance (inclusive of full trace on)
145                     if (timeout > VpnConstants.MAX_WAIT_TIME_IN_MILLISECONDS) {
146                         timeout = VpnConstants.MAX_WAIT_TIME_IN_MILLISECONDS;
147                     }
148                     LOG.info("VPNInstance removal count of interface at {} for for rd {}, vpnname {}",
149                             intfCount, rd, vpnName);
150                 }
151                 LOG.info("VPNInstance removal thread waiting for {} seconds for rd {}, vpnname {}",
152                         (timeout / 1000), rd, vpnName);
153
154                 try {
155                     Thread.sleep(timeout);
156                 } catch (java.lang.InterruptedException e) {
157                 }
158 //                Runnable notifyTask = new VpnNotifyTask();
159 //                synchronized (rd.intern()) {
160 //                    try {
161 //                        vpnOpMap.put(rd, notifyTask);
162 //                        synchronized (notifyTask) {
163 //                            try {
164 //                                notifyTask.wait(timeout);
165 //                            } catch (InterruptedException e) {
166 //                            }
167 //                        }
168 //                    } finally {
169 //                        vpnOpMap.remove(rd);
170 //                    }
171 //                }
172
173                 // Check current interface count
174                 vpnOpValue = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
175                         VpnUtil.getVpnInstanceOpDataIdentifier(rd));
176                 if ((vpnOpValue != null) && (vpnOpValue.isPresent())) {
177                     vpnOpEntry = vpnOpValue.get();
178                     dpnToVpns = vpnOpEntry.getVpnToDpnList();
179                     currentIntfCount = 0L;
180                     if (dpnToVpns != null) {
181                         for (VpnToDpnList dpn : dpnToVpns) {
182                             if (dpn.getVpnInterfaces() != null) {
183                                 currentIntfCount = currentIntfCount + dpn.getVpnInterfaces().size();
184                             }
185                         }
186                     }
187                     //currentIntfCount = vpnOpEntry.getVpnInterfaceCount();
188                     if ((currentIntfCount == 0) || (currentIntfCount >= intfCount)) {
189                         // Either the FibManager completed its job to cleanup all vpnInterfaces in VPN
190                         // OR
191                         // There is no progress by FibManager in removing all the interfaces even after good time!
192                         // In either case, let us quit and take our chances.
193                         //TODO(vpnteam): L3VPN refactoring to take care of this case.
194                         if (retryCount > 0) {
195                             retryCount--;
196                             LOG.info("Retrying clearing vpn with vpnname {} rd {} since currentIntfCount {} ", vpnName, rd, currentIntfCount);
197                             if (currentIntfCount > 0L){
198                                 LOG.info("Current interface count for vpn {} and rd {} is not zero and so retrying ...", vpnName, rd);
199                                 intfCount = currentIntfCount;
200                             } else {
201                                 LOG.info("Current interface count is zero but instance Op for vpn {} and rd {} not cleared yet. Waiting for 5 more seconds.", vpnName, rd);
202                                 intfCount = 1L;
203                             }
204                         } else {
205                             LOG.info("VPNInstance bailing out of wait loop as currentIntfCount is {} and max retries exceeded for for rd {}, vpnname {}",
206                                     currentIntfCount, rd, vpnName);
207                             break;
208                         }
209                     } else {
210                         // There is some progress by FibManager, so let us give it some more time!
211                         intfCount = currentIntfCount;
212                         retryCount = 1;
213                         LOG.info("current interface count {} for vpn {} and rd {} showing progress, waiting for it to drive to 0.", currentIntfCount, vpnName, rd);
214                     }
215                 } else {
216                     // There is no VPNOPEntry.  Something else happened on the system !
217                     // So let us quit and take our chances.
218                     //TODO(vpnteam): L3VPN refactoring to take care of this case.
219                     break;
220                 }
221             }
222         }
223         LOG.info("Returned out of waiting for  Op Data removal for rd {}, vpnname {}", rd, vpnName);
224     }
225
226
227     @Override
228     protected void remove(InstanceIdentifier<VpnInstance> identifier, VpnInstance del) {
229         LOG.trace("Remove VPN event key: {}, value: {}", identifier, del);
230         String vpnName = del.getVpnInstanceName();
231         String rd = del.getIpv4Family().getRouteDistinguisher();
232         long vpnId = VpnUtil.getVpnId(broker, vpnName);
233
234         //TODO(vpnteam): Entire code would need refactoring to listen only on the parent object - VPNInstance
235         Optional<VpnInstanceOpDataEntry> vpnOpValue = null;
236         if ((rd != null) && (!rd.isEmpty())) {
237             vpnOpValue = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
238                     VpnUtil.getVpnInstanceOpDataIdentifier(rd));
239         } else {
240             vpnOpValue = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
241                     VpnUtil.getVpnInstanceOpDataIdentifier(vpnName));
242         }
243
244         if ((rd != null)  && (!rd.isEmpty())) {
245             waitForOpRemoval(rd, vpnName);
246         } else {
247             waitForOpRemoval(vpnName, vpnName);
248         }
249
250         // Clean up VpnInstanceToVpnId from Config DS
251         VpnUtil.removeVpnIdToVpnInstance(broker, vpnId);
252         VpnUtil.removeVpnInstanceToVpnId(broker, vpnName);
253         LOG.trace("Removed vpnIdentifier for  rd{} vpnname {}", rd, vpnName);
254         if (rd != null) {
255             synchronized (rd.intern()) {
256                 try {
257                     bgpManager.deleteVrf(rd);
258                 } catch (Exception e) {
259                     LOG.error("Exception when removing VRF from BGP for RD {} in VPN {} exception " + e, rd, vpnName);
260                 }
261             }
262
263             // Clean up VPNExtraRoutes Operational DS
264             VpnUtil.removeVpnExtraRouteForVpn(broker, rd);
265
266             // Clean up VPNInstanceOpDataEntry
267             VpnUtil.removeVpnOpInstance(broker, rd);
268         } else {
269             // Clean up FIB Entries Config DS
270             synchronized (vpnName.intern()) {
271                 VpnUtil.removeVrfTableForVpn(broker, vpnName);
272             }
273
274             // Clean up VPNExtraRoutes Operational DS
275             VpnUtil.removeVpnExtraRouteForVpn(broker, vpnName);
276
277             // Clean up VPNInstanceOpDataEntry
278             VpnUtil.removeVpnOpInstance(broker, vpnName);
279         }
280
281         // Clean up PrefixToInterface Operational DS
282         VpnUtil.removePrefixToInterfaceForVpnId(broker, vpnId);
283
284         // Clean up L3NextHop Operational DS
285         VpnUtil.removeL3nexthopForVpnId(broker, vpnId);
286
287         // Release the ID used for this VPN back to IdManager
288         VpnUtil.releaseId(idManager, VpnConstants.VPN_IDPOOL_NAME, vpnName);
289     }
290
291     @Override
292     protected void update(InstanceIdentifier<VpnInstance> identifier,
293             VpnInstance original, VpnInstance update) {
294         LOG.trace("Update VPN event key: {}, value: {}", identifier, update);
295     }
296
297     @Override
298     protected void add(InstanceIdentifier<VpnInstance> identifier, VpnInstance value) {
299         LOG.trace("Add VPN event key: {}, value: {}", identifier, value);
300         VpnAfConfig config = value.getIpv4Family();
301         String rd = config.getRouteDistinguisher();
302         String vpnInstanceName = value.getVpnInstanceName();
303
304         long vpnId = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME, vpnInstanceName);
305         LOG.trace("VPN instance to ID generated.");
306         org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance
307             vpnInstanceToVpnId = VpnUtil.getVpnInstanceToVpnId(vpnInstanceName, vpnId, (rd != null) ? rd
308                                                                                                     : vpnInstanceName);
309
310         syncWrite(LogicalDatastoreType.CONFIGURATION, VpnUtil.getVpnInstanceToVpnIdIdentifier(vpnInstanceName),
311                   vpnInstanceToVpnId, DEFAULT_CALLBACK);
312
313         VpnIds
314                 vpnIdToVpnInstance = VpnUtil.getVpnIdToVpnInstance(vpnId, value.getVpnInstanceName(),
315                 (rd != null) ? rd : value.getVpnInstanceName(), (rd != null)/*isExternalVpn*/) ;
316
317         syncWrite(LogicalDatastoreType.CONFIGURATION,
318                 VpnUtil.getVpnIdToVpnInstanceIdentifier(vpnId),
319                 vpnIdToVpnInstance, DEFAULT_CALLBACK);
320
321         IFibManager fibManager = vpnInterfaceManager.getFibManager();
322         try {
323             String cachedTransType = fibManager.getConfTransType();
324             LOG.trace("Value for confTransportType is " + cachedTransType);
325             if (cachedTransType.equals("Invalid")) {
326                 try {
327                     fibManager.setConfTransType("L3VPN", "VXLAN");
328                 } catch (Exception e) {
329                     LOG.trace("Exception caught setting the cached value for transportType");
330                     LOG.error(e.getMessage());
331                 }
332             } else {
333                 LOG.trace(":cached val is neither unset/invalid. NO-op.");
334             }
335         } catch (Exception e) {
336             LOG.error(e.getMessage());
337         }
338
339         if(rd == null) {
340             VpnInstanceOpDataEntryBuilder builder =
341                 new VpnInstanceOpDataEntryBuilder().setVrfId(vpnInstanceName).setVpnId(vpnId)
342                                                    .setVpnInstanceName(vpnInstanceName)
343                                                    .setVpnInterfaceCount(0L);
344             syncWrite(LogicalDatastoreType.OPERATIONAL, VpnUtil.getVpnInstanceOpDataIdentifier(vpnInstanceName),
345                       builder.build(), DEFAULT_CALLBACK);
346
347         } else {
348             VpnInstanceOpDataEntryBuilder builder =
349                 new VpnInstanceOpDataEntryBuilder().setVrfId(rd).setVpnId(vpnId).setVpnInstanceName(vpnInstanceName)
350                                                    .setVpnInterfaceCount(0L);
351             syncWrite(LogicalDatastoreType.OPERATIONAL,
352                       VpnUtil.getVpnInstanceOpDataIdentifier(rd),
353                       builder.build(), DEFAULT_CALLBACK);
354
355             List<VpnTarget> vpnTargetList = config.getVpnTargets().getVpnTarget();
356
357             List<String> ertList = new ArrayList<String>();
358             List<String> irtList = new ArrayList<String>();
359
360             for (VpnTarget vpnTarget : vpnTargetList) {
361                 if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ExportExtcommunity) {
362                     ertList.add(vpnTarget.getVrfRTValue());
363                 }
364                 if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ImportExtcommunity) {
365                     irtList.add(vpnTarget.getVrfRTValue());
366                 }
367                 if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.Both) {
368                     ertList.add(vpnTarget.getVrfRTValue());
369                     irtList.add(vpnTarget.getVrfRTValue());
370                 }
371             }
372
373             try {
374                 bgpManager.addVrf(rd, irtList, ertList);
375             } catch(Exception e) {
376                 LOG.error("Exception when adding VRF to BGP", e);
377             }
378         }
379         //Try to add up vpn Interfaces if already in Operational Datastore
380         InstanceIdentifier<VpnInterfaces> vpnInterfacesId = InstanceIdentifier.builder(VpnInterfaces.class).build();
381         Optional<VpnInterfaces> optionalVpnInterfaces = read(LogicalDatastoreType.CONFIGURATION, vpnInterfacesId);
382
383         if(optionalVpnInterfaces.isPresent()) {
384             List<VpnInterface> vpnInterfaces = optionalVpnInterfaces.get().getVpnInterface();
385             for(VpnInterface vpnInterface : vpnInterfaces) {
386                 if(vpnInterface.getVpnInstanceName().equals(vpnInstanceName)) {
387                     LOG.debug("VpnInterface {} will be added from VPN {}", vpnInterface.getName(), vpnInstanceName);
388                     vpnInterfaceManager.add(
389                                 VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()), vpnInterface);
390
391                 }
392             }
393         }
394         vpnInterfaceManager.handleVpnsExportingRoutes(vpnInstanceName, rd);
395     }
396
397     public boolean isVPNConfigured() {
398
399         InstanceIdentifier<VpnInstances> vpnsIdentifier =
400                 InstanceIdentifier.builder(VpnInstances.class).build();
401         Optional<VpnInstances> optionalVpns = read( LogicalDatastoreType.CONFIGURATION,
402                 vpnsIdentifier);
403         if (!optionalVpns.isPresent() ||
404                 optionalVpns.get().getVpnInstance() == null ||
405                 optionalVpns.get().getVpnInstance().isEmpty()) {
406             LOG.trace("No VPNs configured.");
407             return false;
408         }
409         LOG.trace("VPNs are configured on the system.");
410         return true;
411     }
412
413     private InstanceIdentifier<?> getWildCardPath() {
414         return InstanceIdentifier.create(VpnInstances.class).child(VpnInstance.class);
415     }
416
417     private InstanceIdentifier<?> getFibEntryListenerPath() {
418         return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class)
419                 .child(VrfEntry.class);
420     }
421
422     private InstanceIdentifier<?> getVpnInstanceOpListenerPath() {
423         return InstanceIdentifier.create(VpnInstanceOpData.class).child(VpnInstanceOpDataEntry.class);
424     }
425
426     @Override
427     public void close() throws Exception {
428         if (listenerRegistration != null) {
429             try {
430                 listenerRegistration.close();
431             } catch (final Exception e) {
432                 LOG.error("Error when cleaning up Vpn DataChangeListener.", e);
433             }
434             listenerRegistration = null;
435         }
436         if (fibListenerRegistration != null) {
437             try {
438                 fibListenerRegistration.close();
439             } catch (final Exception e) {
440                 LOG.error("Error when cleaning up Fib entries DataChangeListener.", e);
441             }
442             fibListenerRegistration = null;
443         }
444         LOG.trace("VPN Manager Closed");
445     }
446
447     private <T extends DataObject> Optional<T> read(LogicalDatastoreType datastoreType,
448             InstanceIdentifier<T> path) {
449
450         ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
451
452         Optional<T> result = Optional.absent();
453         try {
454             result = tx.read(datastoreType, path).get();
455         } catch (Exception e) {
456             throw new RuntimeException(e);
457         }
458
459         return result;
460     }
461
462     private <T extends DataObject> void asyncWrite(LogicalDatastoreType datastoreType,
463             InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
464         WriteTransaction tx = broker.newWriteOnlyTransaction();
465         tx.put(datastoreType, path, data, true);
466         Futures.addCallback(tx.submit(), callback);
467     }
468
469     private <T extends DataObject> void syncWrite(LogicalDatastoreType datastoreType,
470                                                    InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
471         WriteTransaction tx = broker.newWriteOnlyTransaction();
472         tx.put(datastoreType, path, data, true);
473         CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
474         try {
475             futures.get();
476         } catch (InterruptedException | ExecutionException e) {
477             LOG.error("Error writing VPN instance to ID info to datastore (path, data) : ({}, {})", path, data);
478             throw new RuntimeException(e.getMessage());
479         }
480     }
481
482     protected VpnInstance getVpnInstance(String vpnInstanceName) {
483         return VpnUtil.getVpnInstance(broker, vpnInstanceName);
484     }
485
486     protected VpnInstanceOpDataEntry getVpnInstanceOpData(String rd) {
487         InstanceIdentifier<VpnInstanceOpDataEntry> id = VpnUtil.getVpnInstanceOpDataIdentifier(rd);
488         Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = read(LogicalDatastoreType.OPERATIONAL, id);
489         if(vpnInstanceOpData.isPresent()) {
490             return vpnInstanceOpData.get();
491         }
492         return null;
493     }
494
495     private class FibEntriesListener extends AbstractDataChangeListener<VrfEntry>  {
496
497         public FibEntriesListener() {
498             super(VrfEntry.class);
499         }
500
501         @Override
502         protected void remove(InstanceIdentifier<VrfEntry> identifier,
503                 VrfEntry del) {
504             LOG.trace("Remove Fib event - Key : {}, value : {} ", identifier, del);
505             final VrfTablesKey key = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class);
506             String rd = key.getRouteDistinguisher();
507             Long label = del.getLabel();
508             VpnInstanceOpDataEntry vpnInstanceOpData = getVpnInstanceOpData(rd);
509             if(vpnInstanceOpData != null) {
510                 List<Long> routeIds = vpnInstanceOpData.getRouteEntryId();
511                 if(routeIds == null) {
512                     LOG.debug("Fib Route entry is empty.");
513                     return;
514                 }
515                 LOG.debug("Removing label from vpn info - {}", label);
516                 routeIds.remove(label);
517                 asyncWrite(LogicalDatastoreType.OPERATIONAL, VpnUtil.getVpnInstanceOpDataIdentifier(rd),
518                            new VpnInstanceOpDataEntryBuilder(vpnInstanceOpData).setRouteEntryId(routeIds).build(), DEFAULT_CALLBACK);
519             } else {
520                 LOG.warn("No VPN Instance found for RD: {}", rd);
521             }
522         }
523
524         @Override
525         protected void update(InstanceIdentifier<VrfEntry> identifier,
526                 VrfEntry original, VrfEntry update) {
527             // TODO Auto-generated method stub
528
529         }
530
531         @Override
532         protected void add(InstanceIdentifier<VrfEntry> identifier,
533                            VrfEntry add) {
534             LOG.trace("Add Vrf Entry event - Key : {}, value : {}", identifier, add);
535             final VrfTablesKey key = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class);
536             String rd = key.getRouteDistinguisher();
537             Long label = add.getLabel();
538             VpnInstanceOpDataEntry vpn = getVpnInstanceOpData(rd);
539             if(vpn != null) {
540                 List<Long> routeIds = vpn.getRouteEntryId();
541                 if(routeIds == null) {
542                     routeIds = new ArrayList<>();
543                 }
544                 LOG.debug("Adding label to vpn info - {}", label);
545                 routeIds.add(label);
546                 asyncWrite(LogicalDatastoreType.OPERATIONAL, VpnUtil.getVpnInstanceOpDataIdentifier(rd),
547                            new VpnInstanceOpDataEntryBuilder(vpn).setRouteEntryId(routeIds).build(), DEFAULT_CALLBACK);
548             } else {
549                 LOG.warn("No VPN Instance found for RD: {}", rd);
550             }
551         }
552     }
553 }