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