2 * Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
8 package org.opendaylight.netvirt.vpnmanager;
10 import java.util.ArrayList;
11 import java.util.List;
12 import java.util.concurrent.*;
14 import com.google.common.util.concurrent.*;
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;
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;
53 import com.google.common.base.Optional;
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;
67 private static final FutureCallback<Void> DEFAULT_CALLBACK =
68 new FutureCallback<Void>() {
70 public void onSuccess(Void result) {
71 LOG.debug("Success in Datastore operation");
75 public void onFailure(Throwable error) {
76 LOG.error("Error in Datastore operation", error);
81 * Listens for data change related to VPN Instance
82 * Informs the BGP about VRF information
84 * @param db dataBroker reference
85 * @param bgpManager Used to advertise routes to the BGP Router
87 public VpnManager(final DataBroker db, final IBgpManager bgpManager) {
88 super(VpnInstance.class);
90 this.bgpManager = bgpManager;
91 this.fibListener = new FibEntriesListener();
95 private void registerListener(final DataBroker db) {
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);
107 public void setIdManager(IdManagerService idManager) {
108 this.idManager = idManager;
111 public void setVpnInterfaceManager(VpnInterfaceManager vpnInterfaceManager) {
112 this.vpnInterfaceManager = vpnInterfaceManager;
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;
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));
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();
137 //intfCount = vpnOpEntry.getVpnInterfaceCount();
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;
146 LOG.info("VPNInstance removal count of interface at {} for for rd {}, vpnname {}",
147 intfCount, rd, vpnName);
149 LOG.info("VPNInstance removal thread waiting for {} seconds for rd {}, vpnname {}",
150 (timeout / 1000), rd, vpnName);
153 Thread.sleep(timeout);
154 } catch (java.lang.InterruptedException e) {
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();
171 //currentIntfCount = vpnOpEntry.getVpnInterfaceCount();
172 if ((currentIntfCount == 0) || (currentIntfCount >= intfCount)) {
173 // Either the FibManager completed its job to cleanup all vpnInterfaces in VPN
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) {
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;
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);
189 LOG.info("VPNInstance bailing out of wait loop as currentIntfCount is {} and max retries exceeded for for rd {}, vpnname {}",
190 currentIntfCount, rd, vpnName);
194 // There is some progress by FibManager, so let us give it some more time!
195 intfCount = currentIntfCount;
197 LOG.info("current interface count {} for vpn {} and rd {} showing progress, waiting for it to drive to 0.", currentIntfCount, vpnName, rd);
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.
207 LOG.info("Returned out of waiting for Op Data removal for rd {}, vpnname {}", rd, vpnName);
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;
217 //TODO(vpnteam): Entire code would need refactoring to listen only on the parent object - VPNInstance
219 if ((rd != null) && (!rd.isEmpty())) {
220 vpnOpValue = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
221 VpnUtil.getVpnInstanceOpDataIdentifier(rd));
223 vpnOpValue = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
224 VpnUtil.getVpnInstanceOpDataIdentifier(vpnName));
226 } catch (Exception e) {
227 LOG.error("Exception when attempting to retrieve VpnInstanceOpDataEntry for VPN {}. ", vpnName, e);
231 if (vpnOpValue == null || !vpnOpValue.isPresent()) {
232 LOG.error("Unable to retrieve VpnInstanceOpDataEntry for VPN {}. ", vpnName);
236 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
237 dataStoreCoordinator.enqueueJob("VPN-" + vpnName,
238 new DeleteVpnInstanceWorker(idManager, broker, del));
241 private class DeleteVpnInstanceWorker implements Callable<List<ListenableFuture<Void>>> {
242 IdManagerService idManager;
244 VpnInstance vpnInstance;
246 public DeleteVpnInstanceWorker(IdManagerService idManager,
249 this.idManager = idManager;
250 this.broker = broker;
251 this.vpnInstance = value;
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);
263 waitForOpRemoval(vpnName, vpnName);
266 // Clean up VpnInstanceToVpnId from Config DS
267 VpnUtil.removeVpnIdToVpnInstance(broker, vpnId, writeTxn);
268 VpnUtil.removeVpnInstanceToVpnId(broker, vpnName, writeTxn);
270 List<ListenableFuture<Void>> futures = new ArrayList<>();
271 futures.add(writeTxn.submit());
272 LOG.trace("Removed vpnIdentifier for rd{} vpnname {}", rd, vpnName);
274 synchronized (rd.intern()) {
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);
282 // Clean up VPNExtraRoutes Operational DS
283 VpnUtil.removeVpnExtraRouteForVpn(broker, rd, null);
285 // Clean up VPNInstanceOpDataEntry
286 VpnUtil.removeVpnOpInstance(broker, rd, null);
288 // Clean up FIB Entries Config DS
289 synchronized (vpnName.intern()) {
290 VpnUtil.removeVrfTableForVpn(broker, vpnName, null);
292 // Clean up VPNExtraRoutes Operational DS
293 VpnUtil.removeVpnExtraRouteForVpn(broker, vpnName, null);
295 // Clean up VPNInstanceOpDataEntry
296 VpnUtil.removeVpnOpInstance(broker, vpnName, null);
298 // Clean up PrefixToInterface Operational DS
299 VpnUtil.removePrefixToInterfaceForVpnId(broker, vpnId, null);
301 // Clean up L3NextHop Operational DS
302 VpnUtil.removeL3nexthopForVpnId(broker, vpnId, null);
304 // Release the ID used for this VPN back to IdManager
305 VpnUtil.releaseId(idManager, VpnConstants.VPN_IDPOOL_NAME, vpnName);
312 protected void update(InstanceIdentifier<VpnInstance> identifier,
313 VpnInstance original, VpnInstance update) {
314 LOG.trace("Update VPN event key: {}, value: {}", identifier, update);
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();
324 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
325 dataStoreCoordinator.enqueueJob("VPN-" + vpnName,
326 new AddVpnInstanceWorker(idManager, vpnInterfaceManager, broker, value));
329 private class AddVpnInstanceWorker implements Callable<List<ListenableFuture<Void>>> {
330 IdManagerService idManager;
331 VpnInterfaceManager vpnInterfaceManager;
332 VpnInstance vpnInstance;
335 public AddVpnInstanceWorker(IdManagerService idManager,
336 VpnInterfaceManager vpnInterfaceManager,
339 this.idManager = idManager;
340 this.vpnInterfaceManager = vpnInterfaceManager;
341 this.broker = broker;
342 this.vpnInstance = value;
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);
357 Futures.addCallback(listenableFuture,
358 new AddBgpVrfWorker(config , vpnInstance.getVpnInstanceName()));
364 private void addVpnInstance(VpnInstance value, WriteTransaction writeTxn) {
365 VpnAfConfig config = value.getIpv4Family();
366 String rd = config.getRouteDistinguisher();
367 String vpnInstanceName = value.getVpnInstanceName();
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
375 if (writeTxn != null) {
376 writeTxn.put(LogicalDatastoreType.CONFIGURATION, VpnUtil.getVpnInstanceToVpnIdIdentifier(vpnInstanceName),
377 vpnInstanceToVpnId, true);
379 syncWrite(LogicalDatastoreType.CONFIGURATION, VpnUtil.getVpnInstanceToVpnIdIdentifier(vpnInstanceName),
380 vpnInstanceToVpnId, DEFAULT_CALLBACK);
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*/);
387 if (writeTxn != null) {
388 writeTxn.put(LogicalDatastoreType.CONFIGURATION,
389 VpnUtil.getVpnIdToVpnInstanceIdentifier(vpnId),
390 vpnIdToVpnInstance, true);
392 syncWrite(LogicalDatastoreType.CONFIGURATION,
393 VpnUtil.getVpnIdToVpnInstanceIdentifier(vpnId),
394 vpnIdToVpnInstance, DEFAULT_CALLBACK);
397 IFibManager fibManager = vpnInterfaceManager.getFibManager();
399 String cachedTransType = fibManager.getConfTransType();
400 LOG.trace("Value for confTransportType is " + cachedTransType);
401 if (cachedTransType.equals("Invalid")) {
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());
409 LOG.trace(":cached val is neither unset/invalid. NO-op.");
411 } catch (Exception e) {
412 LOG.error(e.getMessage());
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);
424 syncWrite(LogicalDatastoreType.OPERATIONAL, VpnUtil.getVpnInstanceOpDataIdentifier(vpnInstanceName),
425 builder.build(), DEFAULT_CALLBACK);
428 VpnInstanceOpDataEntryBuilder builder =
429 new VpnInstanceOpDataEntryBuilder().setVrfId(rd).setVpnId(vpnId).setVpnInstanceName(vpnInstanceName)
430 .setVpnInterfaceCount(0L).setActiveDpnCount(0L);
432 if (writeTxn != null) {
433 writeTxn.merge(LogicalDatastoreType.OPERATIONAL,
434 VpnUtil.getVpnInstanceOpDataIdentifier(rd),
435 builder.build(), true);
437 syncWrite(LogicalDatastoreType.OPERATIONAL,
438 VpnUtil.getVpnInstanceOpDataIdentifier(rd),
439 builder.build(), DEFAULT_CALLBACK);
445 private class AddBgpVrfWorker implements FutureCallback<List<Void>> {
449 public AddBgpVrfWorker(VpnAfConfig config, String vpnName) {
450 this.config = config;
451 this.vpnName = vpnName;
456 * This implies that all the future instances have returned success. -- TODO: Confirm this
459 public void onSuccess(List<Void> voids) {
460 String rd = config.getRouteDistinguisher();
462 List<VpnTarget> vpnTargetList = config.getVpnTargets().getVpnTarget();
464 List<String> ertList = new ArrayList<String>();
465 List<String> irtList = new ArrayList<String>();
467 for (VpnTarget vpnTarget : vpnTargetList) {
468 if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ExportExtcommunity) {
469 ertList.add(vpnTarget.getVrfRTValue());
471 if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ImportExtcommunity) {
472 irtList.add(vpnTarget.getVrfRTValue());
474 if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.Both) {
475 ertList.add(vpnTarget.getVrfRTValue());
476 irtList.add(vpnTarget.getVrfRTValue());
481 bgpManager.addVrf(rd, irtList, ertList);
482 } catch (Exception e) {
483 LOG.error("Exception when adding VRF to BGP", e);
486 vpnInterfaceManager.handleVpnsExportingRoutes(this.vpnName, rd);
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.
499 public void onFailure(Throwable throwable) {
500 LOG.warn("Job: failed with exception: {}", throwable.getStackTrace());
504 public boolean isVPNConfigured() {
506 InstanceIdentifier<VpnInstances> vpnsIdentifier =
507 InstanceIdentifier.builder(VpnInstances.class).build();
508 Optional<VpnInstances> optionalVpns = read( LogicalDatastoreType.CONFIGURATION,
510 if (!optionalVpns.isPresent() ||
511 optionalVpns.get().getVpnInstance() == null ||
512 optionalVpns.get().getVpnInstance().isEmpty()) {
513 LOG.trace("No VPNs configured.");
516 LOG.trace("VPNs are configured on the system.");
520 private InstanceIdentifier<?> getWildCardPath() {
521 return InstanceIdentifier.create(VpnInstances.class).child(VpnInstance.class);
524 private InstanceIdentifier<?> getFibEntryListenerPath() {
525 return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class)
526 .child(VrfEntry.class);
529 private InstanceIdentifier<?> getVpnInstanceOpListenerPath() {
530 return InstanceIdentifier.create(VpnInstanceOpData.class).child(VpnInstanceOpDataEntry.class);
534 public void close() throws Exception {
535 if (listenerRegistration != null) {
537 listenerRegistration.close();
538 } catch (final Exception e) {
539 LOG.error("Error when cleaning up Vpn DataChangeListener.", e);
541 listenerRegistration = null;
543 if (fibListenerRegistration != null) {
545 fibListenerRegistration.close();
546 } catch (final Exception e) {
547 LOG.error("Error when cleaning up Fib entries DataChangeListener.", e);
549 fibListenerRegistration = null;
551 LOG.trace("VPN Manager Closed");
554 private <T extends DataObject> Optional<T> read(LogicalDatastoreType datastoreType,
555 InstanceIdentifier<T> path) {
557 ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
559 Optional<T> result = Optional.absent();
561 result = tx.read(datastoreType, path).get();
562 } catch (Exception e) {
563 throw new RuntimeException(e);
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);
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();
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());
589 protected VpnInstance getVpnInstance(String vpnInstanceName) {
590 return VpnUtil.getVpnInstance(broker, vpnInstanceName);
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();
602 private class FibEntriesListener extends AbstractDataChangeListener<VrfEntry> {
604 public FibEntriesListener() {
605 super(VrfEntry.class);
609 protected void remove(InstanceIdentifier<VrfEntry> identifier,
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.");
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);
627 LOG.warn("No VPN Instance found for RD: {}", rd);
632 protected void update(InstanceIdentifier<VrfEntry> identifier,
633 VrfEntry original, VrfEntry update) {
634 // TODO Auto-generated method stub
639 protected void add(InstanceIdentifier<VrfEntry> identifier,
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);
647 List<Long> routeIds = vpn.getRouteEntryId();
648 if(routeIds == null) {
649 routeIds = new ArrayList<>();
651 LOG.debug("Adding label to vpn info - {}", label);
653 asyncWrite(LogicalDatastoreType.OPERATIONAL, VpnUtil.getVpnInstanceOpDataIdentifier(rd),
654 new VpnInstanceOpDataEntryBuilder(vpn).setRouteEntryId(routeIds).build(), DEFAULT_CALLBACK);
656 LOG.warn("No VPN Instance found for RD: {}", rd);