Fixup Augmentable and Identifiable methods changing
[netvirt.git] / vpnmanager / impl / src / main / java / org / opendaylight / netvirt / vpnmanager / VpnFootprintService.java
1 /*
2  * Copyright (c) 2016, 2017 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
9 package org.opendaylight.netvirt.vpnmanager;
10
11 import com.google.common.base.Optional;
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.MoreExecutors;
16 import java.math.BigInteger;
17 import java.util.ArrayList;
18 import java.util.List;
19 import java.util.concurrent.ExecutionException;
20 import java.util.concurrent.atomic.AtomicBoolean;
21 import javax.inject.Inject;
22 import javax.inject.Singleton;
23 import org.apache.commons.lang3.tuple.ImmutablePair;
24 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
25 import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
26 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
27 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
28 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
29 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
30 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
31 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
32 import org.opendaylight.netvirt.vpnmanager.api.IVpnFootprintService;
33 import org.opendaylight.netvirt.vpnmanager.api.VpnHelper;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AddDpnEvent;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AddDpnEventBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AddInterfaceToDpnOnVpnEvent;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AddInterfaceToDpnOnVpnEventBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.RemoveDpnEvent;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.RemoveDpnEventBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.RemoveInterfaceFromDpnOnVpnEvent;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.RemoveInterfaceFromDpnOnVpnEventBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.add._interface.to.dpn.on.vpn.event.AddInterfaceEventData;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.add._interface.to.dpn.on.vpn.event.AddInterfaceEventDataBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.add.dpn.event.AddEventData;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.add.dpn.event.AddEventDataBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.remove._interface.from.dpn.on.vpn.event.RemoveInterfaceEventData;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.remove._interface.from.dpn.on.vpn.event.RemoveInterfaceEventDataBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.remove.dpn.event.RemoveEventData;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.remove.dpn.event.RemoveEventDataBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddressesBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddressesKey;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesKey;
59 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
60 import org.slf4j.Logger;
61 import org.slf4j.LoggerFactory;
62
63 @Singleton
64 public class VpnFootprintService implements IVpnFootprintService {
65
66     private static final Logger LOG = LoggerFactory.getLogger(VpnFootprintService.class);
67
68     private final DataBroker dataBroker;
69     private final ManagedNewTransactionRunner txRunner;
70     private final IFibManager fibManager;
71     private final VpnOpDataSyncer vpnOpDataSyncer;
72     private final NotificationPublishService notificationPublishService;
73     private final IInterfaceManager interfaceManager;
74
75     @Inject
76     public VpnFootprintService(final DataBroker dataBroker, final IFibManager fibManager,
77             final NotificationPublishService notificationPublishService, final VpnOpDataSyncer vpnOpDataSyncer,
78             final IInterfaceManager interfaceManager) {
79         this.dataBroker = dataBroker;
80         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
81         this.fibManager = fibManager;
82         this.vpnOpDataSyncer = vpnOpDataSyncer;
83         this.notificationPublishService = notificationPublishService;
84         this.interfaceManager = interfaceManager;
85     }
86
87     @Override
88     public void updateVpnToDpnMapping(BigInteger dpId, String vpnName, String primaryRd, String interfaceName,
89             ImmutablePair<IpAddresses.IpAddressSource, String> ipAddressSourceValuePair, boolean add) {
90         long vpnId = VpnUtil.getVpnId(dataBroker, vpnName);
91         if (!dpId.equals(BigInteger.ZERO)) {
92             if (add) {
93                 // Considering the possibility of VpnInstanceOpData not being ready yet cause
94                 // the VPN is
95                 // still in its creation process
96                 if (vpnId == VpnConstants.INVALID_ID) {
97                     LOG.error("updateVpnToDpnMapping: Operational data  for vpn not ready. Waiting to update vpn"
98                             + " footprint for vpn {} on dpn {} interface {}", vpnName, dpId, interfaceName);
99                     vpnOpDataSyncer.waitForVpnDataReady(VpnOpDataSyncer.VpnOpDataType.vpnInstanceToId, vpnName,
100                             VpnConstants.PER_VPN_INSTANCE_OPDATA_MAX_WAIT_TIME_IN_MILLISECONDS);
101                     vpnId = VpnUtil.getVpnId(dataBroker, vpnName);
102                 }
103                 if (interfaceName != null) {
104                     createOrUpdateVpnToDpnListForInterfaceName(vpnId, primaryRd, dpId, interfaceName, vpnName);
105                     publishInterfaceAddedToVpnNotification(interfaceName, dpId, vpnName, vpnId);
106                 } else {
107                     createOrUpdateVpnToDpnListForIPAddress(vpnId, primaryRd, dpId, ipAddressSourceValuePair, vpnName);
108                 }
109             } else {
110                 if (interfaceName != null) {
111                     removeOrUpdateVpnToDpnListForInterfaceName(vpnId, primaryRd, dpId, interfaceName, vpnName);
112                     publishInterfaceRemovedFromVpnNotification(interfaceName, dpId, vpnName, vpnId);
113                 } else {
114                     removeOrUpdateVpnToDpnListForIpAddress(vpnId, primaryRd, dpId, ipAddressSourceValuePair, vpnName);
115                 }
116             }
117         }
118     }
119
120     private void createOrUpdateVpnToDpnListForInterfaceName(long vpnId, String primaryRd, BigInteger dpnId,
121             String intfName, String vpnName) {
122         AtomicBoolean newDpnOnVpn = new AtomicBoolean(false);
123
124         synchronized (vpnName.intern()) {
125             InstanceIdentifier<VpnToDpnList> id = VpnHelper.getVpnToDpnListIdentifier(primaryRd, dpnId);
126             Optional<VpnToDpnList> dpnInVpn = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
127             VpnInterfaces vpnInterface = new VpnInterfacesBuilder().setInterfaceName(intfName).build();
128
129             ListenableFuture<Void> future = txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
130                 if (dpnInVpn.isPresent()) {
131                     VpnToDpnList vpnToDpnList = dpnInVpn.get();
132                     List<VpnInterfaces> vpnInterfaces = vpnToDpnList.getVpnInterfaces();
133                     if (vpnInterfaces == null) {
134                         vpnInterfaces = new ArrayList<>();
135                     }
136                     vpnInterfaces.add(vpnInterface);
137                     VpnToDpnListBuilder vpnToDpnListBuilder = new VpnToDpnListBuilder(vpnToDpnList);
138                     vpnToDpnListBuilder.setDpnState(VpnToDpnList.DpnState.Active).setVpnInterfaces(vpnInterfaces);
139
140                     tx.put(LogicalDatastoreType.OPERATIONAL, id, vpnToDpnListBuilder.build(),
141                             WriteTransaction.CREATE_MISSING_PARENTS);
142                     /*
143                      * If earlier state was inactive, it is considered new DPN coming back to the
144                      * same VPN
145                      */
146                     if (vpnToDpnList.getDpnState() == VpnToDpnList.DpnState.Inactive) {
147                         newDpnOnVpn.set(true);
148                     }
149                     LOG.debug("createOrUpdateVpnToDpnList: Updating vpn footprint for vpn {} vpnId {} interface {}"
150                             + " on dpn {}", vpnName, vpnId, intfName, dpnId);
151                 } else {
152                     List<VpnInterfaces> vpnInterfaces = new ArrayList<>();
153                     vpnInterfaces.add(vpnInterface);
154                     VpnToDpnListBuilder vpnToDpnListBuilder = new VpnToDpnListBuilder().setDpnId(dpnId);
155                     vpnToDpnListBuilder.setDpnState(VpnToDpnList.DpnState.Active).setVpnInterfaces(vpnInterfaces);
156
157                     tx.put(LogicalDatastoreType.OPERATIONAL, id, vpnToDpnListBuilder.build(),
158                             WriteTransaction.CREATE_MISSING_PARENTS);
159                     newDpnOnVpn.set(true);
160                     LOG.debug("createOrUpdateVpnToDpnList: Creating vpn footprint for vpn {} vpnId {} interface {}"
161                             + " on dpn {}", vpnName, vpnId, intfName, dpnId);
162                 }
163             });
164
165             try {
166                 future.get();
167             } catch (InterruptedException | ExecutionException e) {
168                 LOG.error("createOrUpdateVpnToDpnList: Error adding to dpnToVpnList for vpn {} vpnId {} interface {}"
169                         + " dpn {}", vpnName, vpnId, intfName, dpnId, e);
170                 throw new RuntimeException(e.getMessage(), e);
171             }
172         }
173         LOG.info("createOrUpdateVpnToDpnList: Created/Updated vpn footprint for vpn {} vpnId {} interfacName{}"
174                 + " on dpn {}", vpnName, vpnId, intfName, dpnId);
175         /*
176          * Informing the FIB only after writeTxn is submitted successfully.
177          */
178         if (newDpnOnVpn.get()) {
179             if (VpnUtil.isVlan(dataBroker ,intfName)) {
180                 if (!VpnUtil.shouldPopulateFibForVlan(dataBroker, vpnName, null, dpnId, interfaceManager)) {
181                     return;
182                 }
183             }
184             fibManager.populateFibOnNewDpn(dpnId, vpnId, primaryRd,
185                     new DpnEnterExitVpnWorker(dpnId, vpnName, primaryRd, true /* entered */));
186             LOG.info("createOrUpdateVpnToDpnList: Sent populateFib event for new dpn {} in VPN {} for interface {}",
187                     dpnId, vpnName, intfName);
188         }
189     }
190
191     private void createOrUpdateVpnToDpnListForIPAddress(long vpnId, String primaryRd, BigInteger dpnId,
192             ImmutablePair<IpAddresses.IpAddressSource, String> ipAddressSourceValuePair, String vpnName) {
193         AtomicBoolean newDpnOnVpn = new AtomicBoolean(false);
194
195         synchronized (vpnName.intern()) {
196             InstanceIdentifier<VpnToDpnList> id = VpnHelper.getVpnToDpnListIdentifier(primaryRd, dpnId);
197             Optional<VpnToDpnList> dpnInVpn = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
198             IpAddressesBuilder ipAddressesBldr = new IpAddressesBuilder()
199                     .setIpAddressSource(ipAddressSourceValuePair.getKey());
200             ipAddressesBldr.withKey(new IpAddressesKey(ipAddressSourceValuePair.getValue()));
201             ipAddressesBldr.setIpAddress(ipAddressSourceValuePair.getValue());
202
203             ListenableFuture<Void> future = txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
204                 if (dpnInVpn.isPresent()) {
205                     VpnToDpnList vpnToDpnList = dpnInVpn.get();
206                     List<IpAddresses> ipAddresses = vpnToDpnList.getIpAddresses();
207                     if (ipAddresses == null) {
208                         ipAddresses = new ArrayList<>();
209                     }
210                     ipAddresses.add(ipAddressesBldr.build());
211                     VpnToDpnListBuilder vpnToDpnListBuilder = new VpnToDpnListBuilder(vpnToDpnList);
212                     vpnToDpnListBuilder.setDpnState(VpnToDpnList.DpnState.Active).setIpAddresses(ipAddresses);
213
214                     tx.put(LogicalDatastoreType.OPERATIONAL, id, vpnToDpnListBuilder.build(), true);
215                     /*
216                      * If earlier state was inactive, it is considered new DPN coming back to the
217                      * same VPN
218                      */
219                     if (vpnToDpnList.getDpnState() == VpnToDpnList.DpnState.Inactive) {
220                         newDpnOnVpn.set(true);
221                     }
222                 } else {
223                     List<IpAddresses> ipAddresses = new ArrayList<>();
224                     ipAddresses.add(ipAddressesBldr.build());
225                     VpnToDpnListBuilder vpnToDpnListBuilder = new VpnToDpnListBuilder().setDpnId(dpnId);
226                     vpnToDpnListBuilder.setDpnState(VpnToDpnList.DpnState.Active).setIpAddresses(ipAddresses);
227
228                     tx.put(LogicalDatastoreType.OPERATIONAL, id, vpnToDpnListBuilder.build(), true);
229                     newDpnOnVpn.set(true);
230                 }
231             });
232             try {
233                 future.get();
234             } catch (InterruptedException | ExecutionException e) {
235                 LOG.error("Error adding to dpnToVpnList for vpn {} ipAddresses {} dpn {}", vpnName,
236                         ipAddressSourceValuePair.getValue(), dpnId, e);
237                 throw new RuntimeException(e.getMessage(), e);
238             }
239         }
240         /*
241          * Informing the Fib only after writeTxn is submitted successfuly.
242          */
243         if (newDpnOnVpn.get()) {
244             LOG.debug("Sending populateFib event for new dpn {} in VPN {}", dpnId, vpnName);
245             fibManager.populateFibOnNewDpn(dpnId, vpnId, primaryRd,
246                     new DpnEnterExitVpnWorker(dpnId, vpnName, primaryRd, true /* entered */));
247         }
248     }
249
250     private void removeOrUpdateVpnToDpnListForInterfaceName(long vpnId, String rd, BigInteger dpnId, String intfName,
251             String vpnName) {
252         AtomicBoolean lastDpnOnVpn = new AtomicBoolean(false);
253         synchronized (vpnName.intern()) {
254             InstanceIdentifier<VpnToDpnList> id = VpnHelper.getVpnToDpnListIdentifier(rd, dpnId);
255             VpnToDpnList dpnInVpn = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id).orNull();
256             if (dpnInVpn == null) {
257                 LOG.error("removeOrUpdateVpnToDpnList: Could not find DpnToVpn map for VPN=[name={} rd={} id={}]"
258                         + " and dpnId={}", vpnName, rd, id, dpnId);
259                 return;
260             }
261             List<VpnInterfaces> vpnInterfaces = dpnInVpn.getVpnInterfaces();
262             if (vpnInterfaces == null) {
263                 LOG.error("Could not find vpnInterfaces for DpnInVpn map for VPN=[name={} rd={} id={}] and dpnId={}",
264                         vpnName, rd, id, dpnId);
265                 return;
266             }
267
268             VpnInterfaces currVpnInterface = new VpnInterfacesBuilder().setInterfaceName(intfName).build();
269             if (vpnInterfaces.remove(currVpnInterface)) {
270                 try {
271                     txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
272                         if (vpnInterfaces.isEmpty()) {
273                             List<IpAddresses> ipAddresses = dpnInVpn.getIpAddresses();
274                             VpnToDpnListBuilder dpnInVpnBuilder =
275                                     new VpnToDpnListBuilder(dpnInVpn).setVpnInterfaces(null);
276                             if (ipAddresses == null || ipAddresses.isEmpty()) {
277                                 dpnInVpnBuilder.setDpnState(VpnToDpnList.DpnState.Inactive);
278                                 lastDpnOnVpn.set(true);
279                             } else {
280                                 LOG.error("removeOrUpdateVpnToDpnList: vpn interfaces are empty but ip addresses are "
281                                         + "present for the vpn {} in dpn {} interface {}", vpnName, dpnId, intfName);
282                             }
283                             LOG.debug("removeOrUpdateVpnToDpnList: Removing vpn footprint for vpn {} vpnId {} "
284                                     + "interface {}, on dpn {}", vpnName, vpnName, intfName, dpnId);
285                             tx.put(LogicalDatastoreType.OPERATIONAL, id, dpnInVpnBuilder.build(),
286                                     WriteTransaction.CREATE_MISSING_PARENTS);
287
288                         } else {
289                             tx.delete(LogicalDatastoreType.OPERATIONAL,
290                                     id.child(VpnInterfaces.class, new VpnInterfacesKey(intfName)));
291                             LOG.debug("removeOrUpdateVpnToDpnList: Updating vpn footprint for vpn {} vpnId {} "
292                                     + "interface {}, on dpn {}", vpnName, vpnName, intfName, dpnId);
293                         }
294                     }).get();
295                 } catch (InterruptedException | ExecutionException e) {
296                     LOG.error("removeOrUpdateVpnToDpnList: Error removing from dpnToVpnList for vpn {} vpnId {}"
297                             + " interface {} dpn {}", vpnName, vpnId, intfName, dpnId, e);
298                     throw new RuntimeException(e.getMessage(), e);
299                 }
300             }
301         } // Ends synchronized block
302         LOG.info("removeOrUpdateVpnToDpnList: Updated/Removed vpn footprint for vpn {} vpnId {} interface {},"
303                 + " on dpn {}", vpnName, vpnName, intfName, dpnId);
304
305         if (lastDpnOnVpn.get()) {
306             fibManager.cleanUpDpnForVpn(dpnId, vpnId, rd,
307                     new DpnEnterExitVpnWorker(dpnId, vpnName, rd, false /* exited */));
308             LOG.info("removeOrUpdateVpnToDpnList: Sent cleanup event for dpn {} in VPN {} vpnId {} interface {}", dpnId,
309                     vpnName, vpnId, intfName);
310         }
311     }
312
313     private void removeOrUpdateVpnToDpnListForIpAddress(long vpnId, String rd, BigInteger dpnId,
314             ImmutablePair<IpAddresses.IpAddressSource, String> ipAddressSourceValuePair, String vpnName) {
315         AtomicBoolean lastDpnOnVpn = new AtomicBoolean(false);
316         synchronized (vpnName.intern()) {
317             InstanceIdentifier<VpnToDpnList> id = VpnHelper.getVpnToDpnListIdentifier(rd, dpnId);
318             VpnToDpnList dpnInVpn = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id).orNull();
319             if (dpnInVpn == null) {
320                 LOG.error("removeOrUpdateVpnToDpnList: Could not find DpnToVpn map for VPN=[name={} rd={} id={}]"
321                         + " and dpnId={}", vpnName, rd, id, dpnId);
322                 return;
323             }
324             List<IpAddresses> ipAddresses = dpnInVpn.getIpAddresses();
325             if (ipAddresses == null) {
326                 LOG.info("Could not find ipAddresses for DpnInVpn map for VPN=[name={} rd={} id={}] and dpnId={}",
327                         vpnName, rd, id, dpnId);
328                 return;
329             }
330
331             IpAddresses currIpAddress = new IpAddressesBuilder()
332                     .withKey(new IpAddressesKey(ipAddressSourceValuePair.getValue()))
333                     .setIpAddressSource(ipAddressSourceValuePair.getKey()).build();
334             if (ipAddresses.remove(currIpAddress)) {
335                 try {
336                     txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
337                         if (ipAddresses.isEmpty()) {
338                             List<VpnInterfaces> vpnInterfaces = dpnInVpn.getVpnInterfaces();
339                             VpnToDpnListBuilder dpnInVpnBuilder =
340                                     new VpnToDpnListBuilder(dpnInVpn).setIpAddresses(null);
341                             if (vpnInterfaces == null || vpnInterfaces.isEmpty()) {
342                                 dpnInVpnBuilder.setDpnState(VpnToDpnList.DpnState.Inactive);
343                                 lastDpnOnVpn.set(true);
344                             } else {
345                                 LOG.warn("ip addresses are empty but vpn interfaces are present for the vpn {} in "
346                                         + "dpn {}", vpnName, dpnId);
347                             }
348                             tx.put(LogicalDatastoreType.OPERATIONAL, id, dpnInVpnBuilder.build(), true);
349
350                         } else {
351                             tx.delete(LogicalDatastoreType.OPERATIONAL, id.child(IpAddresses.class,
352                                     new IpAddressesKey(ipAddressSourceValuePair.getValue())));
353                         }
354                     }).get();
355                 } catch (InterruptedException | ExecutionException e) {
356                     LOG.error("Error removing from dpnToVpnList for vpn {} Ipaddress {} dpn {}", vpnName,
357                             ipAddressSourceValuePair.getValue(), dpnId, e);
358                     throw new RuntimeException(e.getMessage(), e);
359                 }
360             }
361         } // Ends synchronized block
362
363         if (lastDpnOnVpn.get()) {
364             LOG.debug("Sending cleanup event for dpn {} in VPN {}", dpnId, vpnName);
365             fibManager.cleanUpDpnForVpn(dpnId, vpnId, rd,
366                     new DpnEnterExitVpnWorker(dpnId, vpnName, rd, false /* exited */));
367         }
368     }
369
370     private void publishAddNotification(final BigInteger dpnId, final String vpnName, final String rd) {
371         LOG.debug("publishAddNotification: Sending notification for add dpn {} in vpn {} rd {} event ", dpnId, vpnName,
372                 rd);
373         AddEventData data = new AddEventDataBuilder().setVpnName(vpnName).setRd(rd).setDpnId(dpnId).build();
374         AddDpnEvent event = new AddDpnEventBuilder().setAddEventData(data).build();
375         final ListenableFuture<?> eventFuture = notificationPublishService.offerNotification(event);
376         Futures.addCallback(eventFuture, new FutureCallback<Object>() {
377             @Override
378             public void onFailure(Throwable error) {
379                 LOG.error("publishAddNotification: Error in notifying listeners for add dpn {} in vpn {} rd {} event ",
380                         dpnId, vpnName, rd, error);
381             }
382
383             @Override
384             public void onSuccess(Object arg) {
385                 LOG.info("publishAddNotification: Successful in notifying listeners for add dpn {} in vpn {} rd {}"
386                         + " event ", dpnId, vpnName, rd);
387             }
388         }, MoreExecutors.directExecutor());
389     }
390
391     private void publishRemoveNotification(final BigInteger dpnId, final String vpnName, final String rd) {
392         LOG.debug("publishRemoveNotification: Sending notification for remove dpn {} in vpn {} rd {} event ", dpnId,
393                 vpnName, rd);
394         RemoveEventData data = new RemoveEventDataBuilder().setVpnName(vpnName).setRd(rd).setDpnId(dpnId).build();
395         RemoveDpnEvent event = new RemoveDpnEventBuilder().setRemoveEventData(data).build();
396         final ListenableFuture<?> eventFuture = notificationPublishService.offerNotification(event);
397         Futures.addCallback(eventFuture, new FutureCallback<Object>() {
398             @Override
399             public void onFailure(Throwable error) {
400                 LOG.error("publishRemoveNotification: Error in notifying listeners for remove dpn {} in vpn {} rd {}"
401                         + " event ", dpnId, vpnName, rd, error);
402             }
403
404             @Override
405             public void onSuccess(Object arg) {
406                 LOG.info("publishRemoveNotification: Successful in notifying listeners for remove dpn {} in vpn {}"
407                         + " rd {} event ", dpnId, vpnName, rd);
408             }
409         }, MoreExecutors.directExecutor());
410     }
411
412     private void publishInterfaceAddedToVpnNotification(String interfaceName, BigInteger dpnId, String vpnName,
413             Long vpnId) {
414         LOG.debug("publishInterfaceAddedToVpnNotification: Sending notification for addition of interface {} on dpn {}"
415                 + " for vpn {}", interfaceName, dpnId, vpnName);
416         AddInterfaceEventData data = new AddInterfaceEventDataBuilder().setInterfaceName(interfaceName).setVpnId(vpnId)
417                 .setDpnId(dpnId).build();
418         AddInterfaceToDpnOnVpnEvent event = new AddInterfaceToDpnOnVpnEventBuilder().setAddInterfaceEventData(data)
419                 .build();
420         final ListenableFuture<?> eventFuture = notificationPublishService.offerNotification(event);
421         Futures.addCallback(eventFuture, new FutureCallback<Object>() {
422             @Override
423             public void onFailure(Throwable error) {
424                 LOG.warn("publishInterfaceAddedToVpnNotification: Error in notifying listeners for add interface {}"
425                         + " on dpn {} in vpn {} event ", interfaceName, dpnId, vpnName, error);
426             }
427
428             @Override
429             public void onSuccess(Object arg) {
430                 LOG.trace("publishInterfaceAddedToVpnNotification: Successful in notifying listeners for add"
431                         + " interface {} on dpn {} in vpn {} event ", interfaceName, dpnId, vpnName);
432             }
433         }, MoreExecutors.directExecutor());
434     }
435
436     private void publishInterfaceRemovedFromVpnNotification(String interfaceName, BigInteger dpnId, String vpnName,
437             Long vpnId) {
438         LOG.debug("publishInterfaceAddedToVpnNotification: Sending notification for removal of interface {}"
439                 + " from dpn {} for vpn {}", interfaceName, dpnId, vpnName);
440         RemoveInterfaceEventData data = new RemoveInterfaceEventDataBuilder().setInterfaceName(interfaceName)
441                 .setVpnId(vpnId).setDpnId(dpnId).build();
442         RemoveInterfaceFromDpnOnVpnEvent event = new RemoveInterfaceFromDpnOnVpnEventBuilder()
443                 .setRemoveInterfaceEventData(data).build();
444         final ListenableFuture<?> eventFuture = notificationPublishService.offerNotification(event);
445         Futures.addCallback(eventFuture, new FutureCallback<Object>() {
446             @Override
447             public void onFailure(Throwable error) {
448                 LOG.warn(
449                         "publishInterfaceAddedToVpnNotification: Error in notifying listeners"
450                                 + " for removing interface {} from dpn {} in vpn {} event ",
451                         interfaceName, dpnId, vpnName, error);
452             }
453
454             @Override
455             public void onSuccess(Object arg) {
456                 LOG.trace("publishInterfaceAddedToVpnNotification: Successful in notifying listeners for removing"
457                         + " interface {} from dpn {} in vpn {} event ", interfaceName, dpnId, vpnName);
458             }
459         }, MoreExecutors.directExecutor());
460     }
461
462     /**
463      * JobCallback class is used as a future callback for main and rollback workers
464      * to handle success and failure.
465      */
466     private class DpnEnterExitVpnWorker implements FutureCallback<List<Void>> {
467         private final Logger log = LoggerFactory.getLogger(DpnEnterExitVpnWorker.class);
468         BigInteger dpnId;
469         String vpnName;
470         String rd;
471         boolean entered;
472
473         DpnEnterExitVpnWorker(BigInteger dpnId, String vpnName, String rd, boolean entered) {
474             this.entered = entered;
475             this.dpnId = dpnId;
476             this.vpnName = vpnName;
477             this.rd = rd;
478         }
479
480         /**
481          * This implies that all the future instances have returned success. -- TODO:
482          * Confirm this
483          */
484         @Override
485         public void onSuccess(List<Void> voids) {
486             if (entered) {
487                 publishAddNotification(dpnId, vpnName, rd);
488                 log.info("onSuccess: FootPrint established for vpn {} rd {} on dpn {}", vpnName, rd, dpnId);
489             } else {
490                 publishRemoveNotification(dpnId, vpnName, rd);
491                 log.info("onSuccess: FootPrint cleared for vpn {} rd {} on dpn {}", vpnName, rd, dpnId);
492             }
493         }
494
495         /**
496          * This method is used to handle failure callbacks. If more retry needed, the
497          * retrycount is decremented and mainworker is executed again. After retries
498          * completed, rollbackworker is executed. If rollbackworker fails, this is a
499          * double-fault. Double fault is logged and ignored.
500          */
501         @Override
502         public void onFailure(Throwable throwable) {
503             log.info("onFailure: Failed to establish/clear footprint for vpn {} rd {} on dpn {} ", vpnName, rd, dpnId,
504                     throwable);
505         }
506     }
507
508     boolean isVpnFootPrintCleared(VpnInstanceOpDataEntry vpnInstanceOpData) {
509         return vpnInstanceOpData.getVpnToDpnList() == null || vpnInstanceOpData.getVpnToDpnList().isEmpty();
510     }
511 }