Merge "Copy default aclservice-config.xml to etc/...config"
[netvirt.git] / vpnservice / vpnmanager / vpnmanager-impl / src / main / java / org / opendaylight / netvirt / vpnmanager / intervpnlink / InterVpnLinkListener.java
1 /*
2  * Copyright (c) 2016 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 package org.opendaylight.netvirt.vpnmanager.intervpnlink;
9
10 import com.google.common.base.Preconditions;
11 import com.google.common.util.concurrent.FutureCallback;
12 import com.google.common.util.concurrent.Futures;
13 import com.google.common.util.concurrent.ListenableFuture;
14 import java.math.BigInteger;
15 import java.util.ArrayList;
16 import java.util.List;
17 import java.util.concurrent.ExecutionException;
18 import java.util.concurrent.Future;
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
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.AsyncDataBroker;
24 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
25 import org.opendaylight.genius.interfacemanager.globals.IfmConstants;
26 import org.opendaylight.genius.mdsalutil.AbstractDataChangeListener;
27 import org.opendaylight.genius.mdsalutil.MDSALUtil;
28 import org.opendaylight.genius.mdsalutil.NwConstants;
29 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
30 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
31 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
32 import org.opendaylight.netvirt.vpnmanager.VpnConstants;
33 import org.opendaylight.netvirt.vpnmanager.VpnUtil;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.InterVpnLinkCreationError;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.InterVpnLinkCreationErrorBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.InterVpnLinks;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.creation.error.InterVpnLinkCreationErrorMessage;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.creation.error.InterVpnLinkCreationErrorMessageBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkState;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkStateBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.inter.vpn.link.state.FirstEndpointState;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.inter.vpn.link.state.FirstEndpointStateBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.inter.vpn.link.state.SecondEndpointState;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.inter.vpn.link.state.SecondEndpointStateBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.links.InterVpnLink;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.links.InterVpnLinkKey;
59 import org.opendaylight.yangtools.concepts.ListenerRegistration;
60 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
61 import org.opendaylight.yangtools.yang.common.RpcResult;
62 import org.slf4j.Logger;
63 import org.slf4j.LoggerFactory;
64
65 public class InterVpnLinkListener extends AbstractDataChangeListener<InterVpnLink> implements  AutoCloseable {
66     private static final Logger LOG = LoggerFactory.getLogger(InterVpnLinkListener.class);
67     private ListenerRegistration<DataChangeListener> listenerRegistration;
68     private final DataBroker dataBroker;
69     private final IMdsalApiManager mdsalManager;
70     private final IdManagerService idManager;
71     private final IBgpManager bgpManager;
72     private final NotificationPublishService notificationsService;
73     private static final String NBR_OF_DPNS_PROPERTY_NAME = "vpnservice.intervpnlink.number.dpns";
74     private static final long INVALID_ID = 0;
75
76     public InterVpnLinkListener(final DataBroker dataBroker, final IdManagerService idManager,
77                                 final IMdsalApiManager mdsalManager, final IBgpManager bgpManager,
78                                 final NotificationPublishService notifService) {
79         super(InterVpnLink.class);
80         this.dataBroker = dataBroker;
81         this.idManager = idManager;
82         this.mdsalManager = mdsalManager;
83         this.bgpManager = bgpManager;
84         this.notificationsService = notifService;
85     }
86
87     public void start() {
88         LOG.info("{} start", getClass().getSimpleName());
89         listenerRegistration = dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
90                 getWildCardPath(), this, AsyncDataBroker.DataChangeScope.SUBTREE);
91     }
92
93     private InstanceIdentifier<InterVpnLink> getWildCardPath() {
94         return InstanceIdentifier.create(InterVpnLinks.class).child(InterVpnLink.class);
95     }
96
97     @Override
98     public void close() throws Exception {
99         if (listenerRegistration != null) {
100             listenerRegistration.close();
101             listenerRegistration = null;
102         }
103         LOG.info("{} close", getClass().getSimpleName());
104     }
105
106     private String getInterVpnLinkIfaceName(String vpnUuid, BigInteger dpnId ) {
107         return String.format("InterVpnLink.%s.%s", vpnUuid, dpnId.toString());
108     }
109
110     @Override
111     protected void add(InstanceIdentifier<InterVpnLink> identifier, InterVpnLink add) {
112
113         LOG.debug("Reacting to IVpnLink {} creation. Vpn1=[name={}  EndpointIp={}]  Vpn2=[name={} endpointIP={}]",
114                 add.getName(), add.getFirstEndpoint().getVpnUuid(), add.getFirstEndpoint().getIpAddress(),
115                 add.getSecondEndpoint().getVpnUuid(), add.getSecondEndpoint().getIpAddress());
116
117         int numberOfDpns = Integer.getInteger(NBR_OF_DPNS_PROPERTY_NAME, 1);
118         // Create VpnLink state
119         InstanceIdentifier<InterVpnLinkState> vpnLinkStateIid = VpnUtil.getInterVpnLinkStateIid(add.getName());
120         InterVpnLinkState vpnLinkState = new InterVpnLinkStateBuilder().setInterVpnLinkName(add.getName()).build();
121         MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnLinkStateIid, vpnLinkState);
122
123         InterVpnLinkKey key = add.getKey();
124         Uuid firstEndpointVpnUuid = add.getFirstEndpoint().getVpnUuid();
125         Uuid secondEndpointVpnUuid = add.getSecondEndpoint().getVpnUuid();
126         // First VPN
127         if ( VpnUtil.getVpnInstance(this.dataBroker, firstEndpointVpnUuid.getValue()) == null ) {
128             String errMsg = "InterVpnLink " + add.getName() + " creation error: could not find 1st endpoint Vpn "
129                     + firstEndpointVpnUuid.getValue();
130             setInError(vpnLinkStateIid, vpnLinkState, errMsg);
131             return;
132         }
133         if (!checkVpnAvailability(key, firstEndpointVpnUuid)) {
134             String errMsg = "InterVpnLink " + add.getName() + " creation error: Vpn " + firstEndpointVpnUuid.getValue()
135                     + " is already associated to an inter-vpn-link ";
136             setInError(vpnLinkStateIid, vpnLinkState, errMsg);
137             return;
138         }
139
140         // Second VPN
141         if ( VpnUtil.getVpnInstance(this.dataBroker, secondEndpointVpnUuid.getValue()) == null ) {
142             String errMsg = "InterVpnLink " + add.getName() + " creation error: could not find 2nd endpoint Vpn "
143                     + secondEndpointVpnUuid.getValue();
144             setInError(vpnLinkStateIid, vpnLinkState, errMsg);
145             return;
146         }
147         if (!checkVpnAvailability(key, secondEndpointVpnUuid)) {
148             String errMsg = "InterVpnLink " + add.getName() + " creation error: Vpn " + secondEndpointVpnUuid.getValue()
149                     + " is already associated with an inter-vpn-link";
150             setInError(vpnLinkStateIid, vpnLinkState, errMsg);
151             return;
152         }
153
154         // TODO: Doing like this we are retrieving operative DPNs from MDSAL when we just need one. Fix it
155         List<BigInteger> firstDpnList = VpnUtil.pickRandomDPNs(dataBroker, numberOfDpns, null);
156         if (firstDpnList != null && !firstDpnList.isEmpty()) {
157             // TODO: Limitation to be solved later
158             // List<BigInteger> secondDpnList = VpnUtil.pickRandomDPNs(dataBroker, numberOfDpns, firstDpnList);
159             List<BigInteger> secondDpnList = firstDpnList;
160
161             Long firstVpnLportTag = allocateVpnLinkLportTag(key.getName() + firstEndpointVpnUuid.getValue());
162             Long secondVpnLportTag = allocateVpnLinkLportTag(key.getName() + secondEndpointVpnUuid.getValue());
163             FirstEndpointState firstEndPointState =
164                 new FirstEndpointStateBuilder().setVpnUuid(firstEndpointVpnUuid).setDpId(firstDpnList)
165                                                .setLportTag(firstVpnLportTag).build();
166             SecondEndpointState secondEndPointState =
167                 new SecondEndpointStateBuilder().setVpnUuid(secondEndpointVpnUuid).setDpId(secondDpnList)
168                                                 .setLportTag(secondVpnLportTag).build();
169
170             InterVpnLinkUtil.updateInterVpnLinkState(dataBroker, add.getName(), InterVpnLinkState.State.Active,
171                                                      firstEndPointState, secondEndPointState);
172
173             // Note that in the DPN of the firstEndpoint we install the lportTag of the secondEndpoint and viceversa
174             InterVpnLinkUtil.installLPortDispatcherTableFlow(dataBroker, mdsalManager, add, firstDpnList,
175                                                              secondEndpointVpnUuid, secondVpnLportTag);
176             InterVpnLinkUtil.installLPortDispatcherTableFlow(dataBroker, mdsalManager, add, secondDpnList,
177                                                              firstEndpointVpnUuid, firstVpnLportTag);
178             // Update the VPN -> DPNs Map.
179             // Note: when a set of DPNs is calculated for Vpn1, these DPNs are added to the VpnToDpn map of Vpn2. Why?
180             // because we do the handover from Vpn1 to Vpn2 in those DPNs, so in those DPNs we must know how to reach
181             // to Vpn2 targets. If new Vpn2 targets are added later, the Fib will be maintained in these DPNs even if
182             // Vpn2 is not physically present there.
183             InterVpnLinkUtil.updateVpnToDpnMap(dataBroker, firstDpnList, secondEndpointVpnUuid);
184             InterVpnLinkUtil.updateVpnToDpnMap(dataBroker, secondDpnList, firstEndpointVpnUuid);
185
186             // Now, if the corresponding flags are activated, there will be some routes exchange
187             leakRoutesIfNeeded(add);
188         } else {
189             // If there is no connection to DPNs, the InterVpnLink is created and the InterVpnLinkState is also created
190             // with the corresponding LPortTags but no DPN is assigned since there is no DPN operative.
191             Long firstVpnLportTag = allocateVpnLinkLportTag(key.getName() + firstEndpointVpnUuid.getValue());
192             Long secondVpnLportTag = allocateVpnLinkLportTag(key.getName() + secondEndpointVpnUuid.getValue());
193             FirstEndpointState firstEndPointState =
194                 new FirstEndpointStateBuilder().setVpnUuid(firstEndpointVpnUuid)
195                                                .setLportTag(firstVpnLportTag).build();
196             SecondEndpointState secondEndPointState =
197                 new SecondEndpointStateBuilder().setVpnUuid(secondEndpointVpnUuid)
198                                                 .setLportTag(secondVpnLportTag).build();
199             InterVpnLinkUtil.updateInterVpnLinkState(dataBroker, add.getName(), InterVpnLinkState.State.Error,
200                                                      firstEndPointState, secondEndPointState);
201         }
202
203
204     }
205
206     private void leakRoutesIfNeeded(InterVpnLink vpnLink) {
207
208         // The type of routes to exchange depend on the leaking flags that have been activated
209         List<RouteOrigin> originsToConsider = new ArrayList<>();
210         if ( vpnLink.isBgpRoutesLeaking() ) {
211             originsToConsider.add(RouteOrigin.BGP);
212         }
213
214         /* For now, only BGP leaking. Leave this here for when the other leakings are activated
215         if ( vpnLink.isConnectedRoutesLeaking() ) {
216             originsToConsider.add(RouteOrigin.CONNECTED);
217         }
218         if ( vpnLink.isStaticRoutesLeaking() ) {
219             originsToConsider.add(RouteOrigin.STATIC);
220             NOTE: There are 2 types of static routes depending on the nexthop:
221               + static route when nexthop is a VM, the Dc-GW or a DPNIP
222               + static route when nexthop is an InterVPN Link
223             Only the 1st type should be considered since the 2nd has a special treatment
224         } */
225         String vpn1Uuid = vpnLink.getFirstEndpoint().getVpnUuid().getValue();
226         String vpn2Uuid = vpnLink.getSecondEndpoint().getVpnUuid().getValue();
227
228         if ( ! originsToConsider.isEmpty() ) {
229             // 1st Endpoint ==> 2nd endpoint
230             leakRoutes(vpnLink, vpn1Uuid, vpn2Uuid, originsToConsider);
231
232             // 2nd Endpoint ==> 1st endpoint
233             leakRoutes(vpnLink, vpn2Uuid, vpn1Uuid, originsToConsider);
234         }
235
236         // Static routes in Vpn1 pointing to Vpn2's endpoint
237         leakExtraRoutesToVpnEndpoint(vpnLink, vpn1Uuid, vpn2Uuid);
238
239         // Static routes in Vpn2 pointing to Vpn1's endpoint
240         leakExtraRoutesToVpnEndpoint(vpnLink, vpn2Uuid, vpn1Uuid);
241     }
242
243     private void leakRoutes(InterVpnLink vpnLink, String srcVpnUuid, String dstVpnUuid,
244                             List<RouteOrigin> originsToConsider) {
245         String srcVpnRd = VpnUtil.getVpnRd(dataBroker, srcVpnUuid);
246         String dstVpnRd = VpnUtil.getVpnRd(dataBroker, dstVpnUuid);
247         List<VrfEntry> srcVpnRemoteVrfEntries = VpnUtil.getVrfEntriesByOrigin(dataBroker, srcVpnRd, originsToConsider);
248         for ( VrfEntry vrfEntry : srcVpnRemoteVrfEntries ) {
249             long label = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
250                                              VpnUtil.getNextHopLabelKey(dstVpnRd, vrfEntry.getDestPrefix()));
251
252             VpnUtil.leakRoute(dataBroker, bgpManager, vpnLink, srcVpnUuid, dstVpnUuid,
253                               vrfEntry.getDestPrefix(), label);
254         }
255     }
256
257     /*
258      * Checks if there are static routes in Vpn1 whose nexthop is Vpn2's endpoint. Those routes must be leaked to Vpn1.
259      *
260      * @param vpnLink
261      * @param vpn1Uuid
262      * @param vpn2Uuid
263      */
264     private void leakExtraRoutesToVpnEndpoint(InterVpnLink vpnLink, String vpn1Uuid, String vpn2Uuid) {
265
266         String vpn1Rd = VpnUtil.getVpnRd(dataBroker, vpn1Uuid);
267         String vpn2Endpoint = vpnLink.getSecondEndpoint().getIpAddress().getValue();
268         List<VrfEntry> allVpnVrfEntries = VpnUtil.getAllVrfEntries(dataBroker, vpn1Rd);
269         for ( VrfEntry vrfEntry : allVpnVrfEntries ) {
270             if ( vrfEntry.getNextHopAddressList() != null
271                 && vrfEntry.getNextHopAddressList().contains(vpn2Endpoint) ) {
272                 // Vpn1 has a route pointing to Vpn2's endpoint. Forcing the leaking of the route will update the
273                 // BGP accordingly
274                 long label = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
275                                                   VpnUtil.getNextHopLabelKey(vpn1Rd, vrfEntry.getDestPrefix()));
276
277                 VpnUtil.leakRoute(dataBroker, bgpManager, vpnLink, vpn2Uuid, vpn1Uuid, vrfEntry.getDestPrefix(),
278                                   label, RouteOrigin.value(vrfEntry.getOrigin()));
279             }
280         }
281
282     }
283
284     private boolean checkVpnAvailability(InterVpnLinkKey key, Uuid vpnId) {
285         Preconditions.checkNotNull(vpnId);
286
287         List<InterVpnLink> interVpnLinks = VpnUtil.getAllInterVpnLinks(dataBroker);
288         if ( interVpnLinks != null ) {
289             for (InterVpnLink interVpnLink : interVpnLinks) {
290                 if (!key.equals(interVpnLink.getKey())
291                     && (vpnId.equals(interVpnLink.getFirstEndpoint().getVpnUuid())
292                         || vpnId.equals(interVpnLink.getSecondEndpoint().getVpnUuid()))) {
293                     return false;
294                 }
295             }
296         }
297         return true;
298     }
299
300
301     @Override
302     protected void remove(InstanceIdentifier<InterVpnLink> identifier, InterVpnLink del) {
303
304         LOG.debug("Reacting to InterVpnLink {} removal", del.getName());
305         // Remove learnt routes
306         // Remove entries in the LPortDispatcher table
307         // Remove the corresponding entries in InterVpnLinkState
308
309         // For each endpoint, remove all routes that have been learnt by intervpnLink
310         String vpn1Uuid = del.getFirstEndpoint().getVpnUuid().getValue();
311         String rd1 = VpnUtil.getVpnRdFromVpnInstanceConfig(dataBroker, vpn1Uuid);
312         LOG.debug("Removing leaked routes in VPN {}  rd={}", vpn1Uuid, rd1);
313         VpnUtil.removeVrfEntriesByOrigin(dataBroker, rd1, RouteOrigin.INTERVPN);
314         VpnUtil.removeVrfEntriesByNexthop(dataBroker, rd1, del.getSecondEndpoint().getIpAddress().getValue());
315
316         String vpn2Uuid = del.getSecondEndpoint().getVpnUuid().getValue();
317         String rd2 = VpnUtil.getVpnRdFromVpnInstanceConfig(dataBroker, vpn2Uuid);
318         LOG.debug("Removing leaked routes in VPN {}  rd={}", vpn2Uuid, rd2);
319         VpnUtil.removeVrfEntriesByOrigin(dataBroker, rd2, RouteOrigin.INTERVPN);
320         VpnUtil.removeVrfEntriesByNexthop(dataBroker, rd2, del.getFirstEndpoint().getIpAddress().getValue());
321
322         InterVpnLinkState interVpnLinkState = VpnUtil.getInterVpnLinkState(dataBroker, del.getName());
323         Long firstEndpointLportTag = interVpnLinkState.getFirstEndpointState().getLportTag();
324         Long secondEndpointLportTag = interVpnLinkState.getSecondEndpointState().getLportTag();
325         removeVpnLinkEndpointFlows(del.getName(), rd1, vpn1Uuid, interVpnLinkState.getFirstEndpointState().getDpId(),
326                 secondEndpointLportTag.intValue(),
327                 del.getSecondEndpoint().getIpAddress().getValue());
328         removeVpnLinkEndpointFlows(del.getName(), rd2, vpn2Uuid, interVpnLinkState.getSecondEndpointState().getDpId(),
329                 firstEndpointLportTag.intValue(), del.getFirstEndpoint().getIpAddress().getValue());
330
331         // Release idManager with LPortTag associated to endpoints
332         LOG.debug("Releasing InterVpnLink {} endpoints LportTags", del.getName());
333         InterVpnLinkKey key = del.getKey();
334         Uuid firstEndpointVpnUuid = del.getFirstEndpoint().getVpnUuid();
335         Uuid secondEndpointVpnUuid = del.getSecondEndpoint().getVpnUuid();
336         releaseVpnLinkLPortTag(key.getName() + firstEndpointVpnUuid.getValue());
337         releaseVpnLinkLPortTag(key.getName() + secondEndpointVpnUuid.getValue());
338
339         // Routes with nextHop pointing to an end-point of the inter-vpn-link are populated into FIB table.
340         // The action in that case is a nx_resubmit to LPortDispatcher table. This is done in FibManager.
341         // At this point. we need to check if is there any entry in FIB table pointing to LPortDispatcher table.
342         // Remove it in that case.
343
344         // Removing the InterVpnLinkState
345         InstanceIdentifier<InterVpnLinkState> interVpnLinkStateIid = VpnUtil.getInterVpnLinkStateIid(del.getName());
346         VpnUtil.delete(dataBroker, LogicalDatastoreType.CONFIGURATION, interVpnLinkStateIid);
347     }
348
349     private void removeVpnLinkEndpointFlows( String interVpnLinkName, String rd, String vpnUuid, List<BigInteger> dpns,
350                                              int otherEndpointLportTag, String otherEndpointIpAddr ) {
351         LOG.debug("Removing endpoint flows for vpn {}.  InterVpnLink={}.  OtherEndpointLportTag={}",
352                 vpnUuid, interVpnLinkName, otherEndpointLportTag);
353         if ( dpns == null ) {
354             LOG.debug("VPN {} endpoint is not instantiated in any DPN for InterVpnLink {}",
355                     vpnUuid, interVpnLinkName);
356             return;
357         }
358
359         for ( BigInteger dpnId : dpns ) {
360             try {
361                 // Removing flow from LportDispatcher table
362                 String flowRef = InterVpnLinkUtil.getLportDispatcherFlowRef(interVpnLinkName, otherEndpointLportTag);
363                 FlowKey flowKey = new FlowKey(new FlowId(flowRef));
364                 Flow flow = new FlowBuilder().setKey(flowKey).setId(new FlowId(flowRef))
365                         .setTableId(NwConstants.LPORT_DISPATCHER_TABLE).setFlowName(flowRef)
366                         .build();
367                 mdsalManager.removeFlow(dpnId, flow);
368
369                 // Removing flow from Fib table
370                 String fibFlowRef = getInterVpnFibFlowRef(dpnId, NwConstants.L3_FIB_TABLE, interVpnLinkName,
371                         otherEndpointIpAddr);
372                 FlowKey fibFlowKey = new FlowKey(new FlowId(fibFlowRef));
373                 Flow fibFlow = new FlowBuilder().setKey(fibFlowKey).setId(new FlowId(fibFlowRef))
374                         .setTableId(NwConstants.L3_FIB_TABLE).setFlowName(fibFlowRef).build();
375                 mdsalManager.removeFlow(dpnId, fibFlow);
376
377                 // Also remove the 'fake' iface from the VpnToDpn map
378                 VpnUtil.removeIfaceFromVpnToDpnMap(dataBroker, rd, dpnId, getInterVpnLinkIfaceName(vpnUuid, dpnId));
379
380             } catch ( Exception e ) {
381                 // Whatever happens it should not stop it from trying to remove as much as possible
382                 LOG.warn("Error while removing InterVpnLink {} Endpoint flows on dpn {}. Reason: {}",
383                         interVpnLinkName, dpnId, e);
384             }
385         }
386     }
387
388     private void releaseVpnLinkLPortTag(String idKey) {
389         ReleaseIdInput releaseIdInput =
390                 new ReleaseIdInputBuilder().setPoolName(VpnConstants.PSEUDO_LPORT_TAG_ID_POOL_NAME).setIdKey(idKey).build();
391         idManager.releaseId(releaseIdInput);
392     }
393
394     @Override
395     protected void update(InstanceIdentifier<InterVpnLink> identifier, InterVpnLink original, InterVpnLink update) {
396      // TODO
397     }
398
399     private String getInterVpnFibFlowRef(BigInteger dpnId, short tableId, String interVpnLinkName,  String nextHop ) {
400         return new StringBuilder(64).append(VpnConstants.FLOWID_PREFIX).append(dpnId)
401                 .append(NwConstants.FLOWID_SEPARATOR).append(tableId)
402                 .append(NwConstants.FLOWID_SEPARATOR).append(interVpnLinkName)
403                 .append(NwConstants.FLOWID_SEPARATOR).append(nextHop)
404                 .toString();
405     }
406
407     private Long allocateVpnLinkLportTag(String idKey) {
408         AllocateIdInput getIdInput =
409                 new AllocateIdInputBuilder().setPoolName(VpnConstants.PSEUDO_LPORT_TAG_ID_POOL_NAME)
410                         .setIdKey(idKey)
411                         .build();
412         try {
413             Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
414             RpcResult<AllocateIdOutput> rpcResult = result.get();
415             if (rpcResult.isSuccessful()) {
416                 return rpcResult.getResult().getIdValue();
417             } else {
418                 LOG.warn("RPC Call to Get Unique Id returned with Errors {}", rpcResult.getErrors());
419             }
420         } catch (InterruptedException | ExecutionException e) {
421             LOG.warn("Exception when getting Unique Id",e);
422         }
423         return INVALID_ID;
424     }
425
426     protected void setInError(final InstanceIdentifier<InterVpnLinkState> vpnLinkStateIid,
427                               final InterVpnLinkState vpnLinkState,
428                               String errorMsg) {
429         LOG.error("Setting InterVpnLink {} in error. Reason: {}", vpnLinkState.getInterVpnLinkName(), errorMsg);
430         // Setting InterVPNLink in error state in MDSAL
431         InterVpnLinkState vpnLinkErrorState =
432             new InterVpnLinkStateBuilder(vpnLinkState).setState(InterVpnLinkState.State.Error)
433                                                       .setErrorDescription(errorMsg)
434                                                       .build();
435         WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
436         tx.put(LogicalDatastoreType.CONFIGURATION, vpnLinkStateIid, vpnLinkErrorState, true);
437         tx.submit();
438
439         // Sending out an error Notification
440         InterVpnLinkCreationErrorMessage errMsg =
441             new InterVpnLinkCreationErrorMessageBuilder().setErrorMessage(errorMsg).build();
442         InterVpnLinkCreationError notif =
443             new InterVpnLinkCreationErrorBuilder().setInterVpnLinkCreationErrorMessage(errMsg).build();
444         final ListenableFuture<? extends Object> eventFuture = this.notificationsService.offerNotification(notif);
445         Futures.addCallback(eventFuture, new FutureCallback<Object>() {
446             @Override
447             public void onFailure(Throwable error) {
448                 LOG.warn("Error when sending notification about InterVpnLink creation issue. InterVpnLink name={}. Error={}",
449                             vpnLinkState.getInterVpnLinkName(), vpnLinkState, error);
450             }
451
452             @Override
453             public void onSuccess(Object arg) {
454                 LOG.trace("Error notification for InterVpnLink successfully sent. VpnLink={} error={}",
455                              vpnLinkState.getInterVpnLinkName(), vpnLinkState);
456             }
457         });
458     }
459 }