2 * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.netvirt.vpnmanager;
11 import com.google.common.base.Optional;
12 import com.google.common.util.concurrent.CheckedFuture;
13 import com.google.common.util.concurrent.FutureCallback;
14 import com.google.common.util.concurrent.Futures;
15 import com.google.common.util.concurrent.ListenableFuture;
16 import java.math.BigInteger;
17 import java.util.ArrayList;
18 import java.util.List;
19 import java.util.concurrent.ExecutionException;
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.controller.md.sal.common.api.data.TransactionCommitFailedException;
25 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
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.RemoveDpnEvent;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.RemoveDpnEventBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.add.dpn.event.AddEventData;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.add.dpn.event.AddEventDataBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.remove.dpn.event.RemoveEventData;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.remove.dpn.event.RemoveEventDataBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListBuilder;
38 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;
39 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;
40 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;
41 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;
42 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
46 public class VpnFootprintService {
48 // TODO: Should this class have its own interface instead of being under IVpnManager's umbrella?
50 private static final Logger LOG = LoggerFactory.getLogger(VpnFootprintService.class);
52 private final DataBroker dataBroker;
53 private final IFibManager fibManager;
54 private final VpnOpDataSyncer vpnOpDataSyncer;
55 private final OdlInterfaceRpcService ifaceMgrRpcService;
56 private final NotificationPublishService notificationPublishService;
58 public VpnFootprintService(final DataBroker dataBroker, final IFibManager fibManager,
59 final OdlInterfaceRpcService ifaceRpcService, final NotificationPublishService notificationPublishService,
60 final VpnOpDataSyncer vpnOpDataSyncer) {
61 this.dataBroker = dataBroker;
62 this.fibManager = fibManager;
63 this.vpnOpDataSyncer = vpnOpDataSyncer;
64 this.ifaceMgrRpcService = ifaceRpcService;
65 this.notificationPublishService = notificationPublishService;
68 public void updateVpnToDpnMapping(BigInteger dpId, String vpnName, String interfaceName, boolean add) {
69 long vpnId = VpnUtil.getVpnId(dataBroker, vpnName);
71 dpId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, interfaceName);
73 if (!dpId.equals(BigInteger.ZERO)) {
75 // Considering the possibility of VpnInstanceOpData not being ready yet cause the VPN is
76 // still in its creation process
77 if (vpnId == VpnConstants.INVALID_ID) {
78 vpnOpDataSyncer.waitForVpnDataReady(VpnOpDataSyncer.VpnOpDataType.vpnInstanceToId, vpnName,
79 VpnConstants.PER_VPN_INSTANCE_OPDATA_MAX_WAIT_TIME_IN_MILLISECONDS);
80 vpnId = VpnUtil.getVpnId(dataBroker, vpnName);
82 createOrUpdateVpnToDpnList(vpnId, dpId, interfaceName, vpnName);
84 removeOrUpdateVpnToDpnList(vpnId, dpId, interfaceName, vpnName);
89 private void createOrUpdateVpnToDpnList(long vpnId, BigInteger dpnId, String intfName, String vpnName) {
90 String primaryRd = VpnUtil.getPrimaryRd(dataBroker, vpnName);
91 Boolean newDpnOnVpn = Boolean.FALSE;
93 synchronized (vpnName.intern()) {
94 WriteTransaction writeTxn = dataBroker.newWriteOnlyTransaction();
95 InstanceIdentifier<VpnToDpnList> id = VpnUtil.getVpnToDpnListIdentifier(primaryRd, dpnId);
96 Optional<VpnToDpnList> dpnInVpn = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
97 VpnInterfaces vpnInterface = new VpnInterfacesBuilder().setInterfaceName(intfName).build();
99 if (dpnInVpn.isPresent()) {
100 VpnToDpnList vpnToDpnList = dpnInVpn.get();
101 List<VpnInterfaces> vpnInterfaces = vpnToDpnList.getVpnInterfaces();
102 if (vpnInterfaces == null) {
103 vpnInterfaces = new ArrayList<>();
105 vpnInterfaces.add(vpnInterface);
106 VpnToDpnListBuilder vpnToDpnListBuilder = new VpnToDpnListBuilder(vpnToDpnList);
107 vpnToDpnListBuilder.setDpnState(VpnToDpnList.DpnState.Active).setVpnInterfaces(vpnInterfaces);
109 writeTxn.put(LogicalDatastoreType.OPERATIONAL, id, vpnToDpnListBuilder.build(), true);
110 /* If earlier state was inactive, it is considered new DPN coming back to the
113 if (vpnToDpnList.getDpnState() == VpnToDpnList.DpnState.Inactive) {
114 newDpnOnVpn = Boolean.TRUE;
117 List<VpnInterfaces> vpnInterfaces = new ArrayList<>();
118 vpnInterfaces.add(vpnInterface);
119 VpnToDpnListBuilder vpnToDpnListBuilder = new VpnToDpnListBuilder().setDpnId(dpnId);
120 vpnToDpnListBuilder.setDpnState(VpnToDpnList.DpnState.Active).setVpnInterfaces(vpnInterfaces);
122 writeTxn.put(LogicalDatastoreType.OPERATIONAL, id, vpnToDpnListBuilder.build(), true);
123 newDpnOnVpn = Boolean.TRUE;
125 CheckedFuture<Void, TransactionCommitFailedException> futures = writeTxn.submit();
128 } catch (InterruptedException | ExecutionException e) {
129 LOG.error("Error adding to dpnToVpnList for vpn {} interface {} dpn {}", vpnName, intfName, dpnId, e);
130 throw new RuntimeException(e.getMessage());
134 * Informing the Fib only after writeTxn is submitted successfuly.
137 LOG.debug("Sending populateFib event for new dpn {} in VPN {}", dpnId, vpnName);
138 fibManager.populateFibOnNewDpn(dpnId, vpnId, primaryRd, new DpnEnterExitVpnWorker(dpnId, vpnName, primaryRd,
139 true /* entered */));
143 private void removeOrUpdateVpnToDpnList(long vpnId, BigInteger dpnId, String intfName, String vpnName) {
144 Boolean lastDpnOnVpn = Boolean.FALSE;
145 String rd = VpnUtil.getVpnRd(dataBroker, vpnName);
146 synchronized (vpnName.intern()) {
147 InstanceIdentifier<VpnToDpnList> id = VpnUtil.getVpnToDpnListIdentifier(rd, dpnId);
148 Optional<VpnToDpnList> dpnInVpn = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
149 WriteTransaction writeTxn = dataBroker.newWriteOnlyTransaction();
150 if (dpnInVpn.isPresent()) {
151 List<VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
152 VpnInterfaces currVpnInterface = new VpnInterfacesBuilder().setInterfaceName(intfName).build();
154 if (vpnInterfaces.remove(currVpnInterface)) {
155 if (vpnInterfaces.isEmpty()) {
156 List<IpAddresses> ipAddresses = dpnInVpn.get().getIpAddresses();
157 if (ipAddresses == null || ipAddresses.isEmpty()) {
158 VpnToDpnListBuilder dpnInVpnBuilder =
159 new VpnToDpnListBuilder(dpnInVpn.get()).setDpnState(VpnToDpnList.DpnState.Inactive)
160 .setVpnInterfaces(null);
161 writeTxn.put(LogicalDatastoreType.OPERATIONAL, id, dpnInVpnBuilder.build(), true);
162 lastDpnOnVpn = Boolean.TRUE;
164 LOG.warn("vpn interfaces are empty but ip addresses are present for the vpn {} in dpn {}",
168 writeTxn.delete(LogicalDatastoreType.OPERATIONAL, id.child(VpnInterfaces.class,
169 new VpnInterfacesKey(intfName)));
173 CheckedFuture<Void, TransactionCommitFailedException> futures = writeTxn.submit();
176 } catch (InterruptedException | ExecutionException e) {
177 LOG.error("Error removing from dpnToVpnList for vpn {} interface {} dpn {}",
178 vpnName, intfName, dpnId, e);
179 throw new RuntimeException(e.getMessage());
183 LOG.debug("Sending cleanup event for dpn {} in VPN {}", dpnId, vpnName);
184 fibManager.cleanUpDpnForVpn(dpnId, vpnId, rd, new DpnEnterExitVpnWorker(dpnId, vpnName, rd,
185 false /* exited */));
189 void publishAddNotification(final BigInteger dpnId, final String vpnName, final String rd) {
190 LOG.debug("Sending notification for add dpn {} in vpn {} event ", dpnId, vpnName);
191 AddEventData data = new AddEventDataBuilder().setVpnName(vpnName).setRd(rd).setDpnId(dpnId).build();
192 AddDpnEvent event = new AddDpnEventBuilder().setAddEventData(data).build();
193 final ListenableFuture<? extends Object> eventFuture = notificationPublishService.offerNotification(event);
194 Futures.addCallback(eventFuture, new FutureCallback<Object>() {
196 public void onFailure(Throwable error) {
197 LOG.warn("Error in notifying listeners for add dpn {} in vpn {} event ", dpnId, vpnName, error);
201 public void onSuccess(Object arg) {
202 LOG.trace("Successful in notifying listeners for add dpn {} in vpn {} event ", dpnId, vpnName);
207 void publishRemoveNotification(final BigInteger dpnId, final String vpnName, final String rd) {
208 LOG.debug("Sending notification for remove dpn {} in vpn {} event ", dpnId, vpnName);
209 RemoveEventData data = new RemoveEventDataBuilder().setVpnName(vpnName).setRd(rd).setDpnId(dpnId).build();
210 RemoveDpnEvent event = new RemoveDpnEventBuilder().setRemoveEventData(data).build();
211 final ListenableFuture<? extends Object> eventFuture = notificationPublishService.offerNotification(event);
212 Futures.addCallback(eventFuture, new FutureCallback<Object>() {
214 public void onFailure(Throwable error) {
215 LOG.warn("Error in notifying listeners for remove dpn {} in vpn {} event ", dpnId, vpnName, error);
219 public void onSuccess(Object arg) {
220 LOG.trace("Successful in notifying listeners for remove dpn {} in vpn {} event ", dpnId, vpnName);
227 * JobCallback class is used as a future callback for
228 * main and rollback workers to handle success and failure.
230 private class DpnEnterExitVpnWorker implements FutureCallback<List<Void>> {
236 DpnEnterExitVpnWorker(BigInteger dpnId, String vpnName, String rd, boolean entered) {
237 this.entered = entered;
239 this.vpnName = vpnName;
244 * This implies that all the future instances have returned success. -- TODO: Confirm this
247 public void onSuccess(List<Void> voids) {
249 publishAddNotification(dpnId, vpnName, rd);
251 publishRemoveNotification(dpnId, vpnName, rd);
256 * This method is used to handle failure callbacks.
257 * If more retry needed, the retrycount is decremented and mainworker is executed again.
258 * After retries completed, rollbackworker is executed.
259 * If rollbackworker fails, this is a double-fault. Double fault is logged and ignored.
262 public void onFailure(Throwable throwable) {
263 LOG.warn("Job: failed with exception: ", throwable);