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