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