Bug 7831 : BgpRouter receives unnecessary events
[netvirt.git] / vpnservice / natservice / natservice-impl / src / main / java / org / opendaylight / netvirt / natservice / internal / NatTunnelInterfaceStateListener.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
9 package org.opendaylight.netvirt.natservice.internal;
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.JdkFutureAdapters;
15 import com.google.common.util.concurrent.ListenableFuture;
16 import java.math.BigInteger;
17 import java.util.ArrayList;
18 import java.util.HashMap;
19 import java.util.List;
20 import java.util.concurrent.Future;
21 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
22 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
23 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
24 import org.opendaylight.genius.mdsalutil.BucketInfo;
25 import org.opendaylight.genius.mdsalutil.FlowEntity;
26 import org.opendaylight.genius.mdsalutil.GroupEntity;
27 import org.opendaylight.genius.mdsalutil.MDSALUtil;
28 import org.opendaylight.genius.mdsalutil.NwConstants;
29 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
30 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
31 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
32 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
33 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
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.types.rev131026.instruction.list.Instruction;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeExternal;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeHwvtep;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeInternal;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelsState;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInput;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInputBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInput;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInputBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.DpnRoutersList;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.dpn.routers.list.RoutersList;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPorts;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.Ports;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMap;
55 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
56 import org.opendaylight.yangtools.yang.common.RpcResult;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59
60 public class NatTunnelInterfaceStateListener
61     extends AsyncDataTreeChangeListenerBase<StateTunnelList, NatTunnelInterfaceStateListener>
62     implements AutoCloseable {
63
64     private static final Logger LOG = LoggerFactory.getLogger(NatTunnelInterfaceStateListener.class);
65     private final DataBroker dataBroker;
66     private IFibManager fibManager;
67     private SNATDefaultRouteProgrammer defaultRouteProgrammer;
68     private NaptSwitchHA naptSwitchHA;
69     private IMdsalApiManager mdsalManager;
70     private IdManagerService idManager;
71     private IBgpManager bgpManager;
72     private ExternalRoutersListener externalRouterListner;
73     private OdlInterfaceRpcService interfaceService;
74     private FloatingIPListener floatingIPListener;
75     private FibRpcService fibRpcService;
76
77     protected enum TunnelAction {
78         TUNNEL_EP_ADD,
79         TUNNEL_EP_DELETE,
80         TUNNEL_EP_UPDATE
81     }
82
83     /**
84      * Responsible for listening to tunnel interface state change.
85      *
86      * @param dataBroker             - dataBroker service reference
87      * @param bgpManager             Used to advertise routes to the BGP Router
88      * @param fibManager             - FIB Manager
89      * @param defaultRouteProgrammer - Default Route Programmer
90      * @param naptSwitchHA           - NAPT Switch HA
91      * @param mdsalManager           - MDSAL Manager
92      * @param idManager              - ID manager
93      * @param externalRouterListner  - External Router Listner
94      * @param interfaceService       - Interface Service
95      * @param floatingIPListener     -  Floating IP Listner
96      * @param fibRpcService          - FIB RPC Service
97      */
98     public NatTunnelInterfaceStateListener(final DataBroker dataBroker,
99                                            final IBgpManager bgpManager,
100                                            final IFibManager fibManager,
101                                            final SNATDefaultRouteProgrammer defaultRouteProgrammer,
102                                            final NaptSwitchHA naptSwitchHA,
103                                            final IMdsalApiManager mdsalManager,
104                                            final IdManagerService idManager,
105                                            final ExternalRoutersListener externalRouterListner,
106                                            final OdlInterfaceRpcService interfaceService,
107                                            final FloatingIPListener floatingIPListener,
108                                            final FibRpcService fibRpcService) {
109         super(StateTunnelList.class, NatTunnelInterfaceStateListener.class);
110         this.dataBroker = dataBroker;
111         this.bgpManager = bgpManager;
112         this.fibManager = fibManager;
113         this.defaultRouteProgrammer = defaultRouteProgrammer;
114         this.naptSwitchHA = naptSwitchHA;
115         this.mdsalManager = mdsalManager;
116         this.idManager = idManager;
117         this.externalRouterListner = externalRouterListner;
118         this.interfaceService = interfaceService;
119         this.floatingIPListener = floatingIPListener;
120         this.fibRpcService = fibRpcService;
121     }
122
123     @Override
124     public void init() {
125         LOG.info("{} init", getClass().getSimpleName());
126         registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
127     }
128
129     @Override
130     protected InstanceIdentifier<StateTunnelList> getWildCardPath() {
131         return InstanceIdentifier.create(TunnelsState.class).child(StateTunnelList.class);
132     }
133
134     @Override
135     protected NatTunnelInterfaceStateListener getDataTreeChangeListener() {
136         return NatTunnelInterfaceStateListener.this;
137     }
138
139     @Override
140     protected void add(InstanceIdentifier<StateTunnelList> instanceIdentifier, StateTunnelList add) {
141         LOG.trace("NAT Service : TEP addtion---- {}", add);
142         hndlTepEvntsForDpn(add, TunnelAction.TUNNEL_EP_ADD);
143     }
144
145     @Override
146     protected void remove(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList del) {
147         LOG.trace("NAT Service : TEP deletion---- {}", del);
148         hndlTepEvntsForDpn(del, TunnelAction.TUNNEL_EP_DELETE);
149     }
150
151     @Override
152     protected void update(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList original,
153                           StateTunnelList update) {
154         LOG.trace("NAT Service : Tunnel updation---- {}", update);
155         //UPDATE IS A SEQUENCE OF DELETE AND ADD EVENTS . DELETE MIGHT HAVE CHANGED THE PRIMARY AND ADVERTISED. SO
156         // NOTHING TO HANDLE
157     }
158
159     private int getTunnelType(StateTunnelList stateTunnelList) {
160         int tunTypeVal = 0;
161         if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeInternal.class) {
162             tunTypeVal = NatConstants.ITMTunnelLocType.Internal.getValue();
163         } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeExternal.class) {
164             tunTypeVal = NatConstants.ITMTunnelLocType.External.getValue();
165         } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeHwvtep.class) {
166             tunTypeVal = NatConstants.ITMTunnelLocType.Hwvtep.getValue();
167         } else {
168             tunTypeVal = NatConstants.ITMTunnelLocType.Invalid.getValue();
169         }
170         return tunTypeVal;
171     }
172
173     // TODO Clean up the exception handling
174     @SuppressWarnings("checkstyle:IllegalCatch")
175     void removeSNATFromDPN(BigInteger dpnId, String routerName, long routerVpnId, Uuid networkId) {
176         //irrespective of naptswitch or non-naptswitch, SNAT default miss entry need to be removed
177         //remove miss entry to NAPT switch
178         //if naptswitch elect new switch and install Snat flows and remove those flows in oldnaptswitch
179
180         //get ExternalIpIn prior
181         List<String> externalIpCache;
182         //HashMap Label
183         HashMap<String, Long> externalIpLabel;
184         Long routerId = NatUtil.getVpnId(dataBroker, routerName);
185         if (routerId == NatConstants.INVALID_ID) {
186             LOG.error("NAT Service : SNAT -> Invalid routerId returned for routerName {}", routerName);
187             return;
188         }
189         externalIpCache = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
190         externalIpLabel = NatUtil.getExternalIpsLabelForRouter(dataBroker, routerId);
191         try {
192             final String externalVpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
193             if (externalVpnName == null) {
194                 LOG.error("NAT Service : SNAT -> No VPN associated with ext nw {} in router {}",
195                     networkId, routerId);
196                 return;
197             }
198
199             BigInteger naptSwitch = dpnId;
200             boolean naptStatus =
201                 naptSwitchHA.isNaptSwitchDown(routerName, dpnId, naptSwitch, routerVpnId, externalIpCache, false);
202             if (!naptStatus) {
203                 LOG.debug("NAT Service : SNAT -> NaptSwitchDown: Switch with DpnId {} is not naptSwitch for router {}",
204                     dpnId, routerName);
205                 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
206                 FlowEntity flowEntity = null;
207                 try {
208                     flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId,
209                         routerVpnId, NatConstants.DEL_FLOW);
210                     if (flowEntity == null) {
211                         LOG.debug("NAT Service : SNAT -> Failed to populate flowentity for "
212                             + "router {} with dpnId {} groupIs {}", routerName, dpnId, groupId);
213                         return;
214                     }
215                     LOG.debug("NAT Service : SNAT -> Removing default SNAT miss entry flow entity {}", flowEntity);
216                     mdsalManager.removeFlow(flowEntity);
217
218                 } catch (Exception ex) {
219                     LOG.debug("NAT Service : SNAT -> Failed to remove default SNAT miss entry flow entity {} : {}",
220                         flowEntity, ex);
221                     return;
222                 }
223                 LOG.debug("NAT Service : SNAT -> Removed default SNAT miss entry flow for dpnID {} with routername {}",
224                     dpnId, routerName);
225
226                 //remove group
227                 GroupEntity groupEntity = null;
228                 try {
229                     groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
230                         GroupTypes.GroupAll, null);
231                     LOG.info("NAT Service : SNAT -> Removing NAPT GroupEntity:{}", groupEntity);
232                     mdsalManager.removeGroup(groupEntity);
233                 } catch (Exception ex) {
234                     LOG.debug("NAT Service : SNAT -> Failed to remove group entity {} : {}", groupEntity, ex);
235                     return;
236                 }
237                 LOG.debug("NAT Service : SNAT -> Removed default SNAT miss entry flow for dpnID {} with routerName {}",
238                     dpnId, routerName);
239             } else {
240                 naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, dpnId, externalIpLabel);
241                 //remove table 26 flow ppointing to table46
242                 FlowEntity flowEntity = null;
243                 try {
244                     flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName, routerVpnId,
245                         NatConstants.DEL_FLOW);
246                     if (flowEntity == null) {
247                         LOG.debug("NAT Service : SNAT -> Failed to populate flowentity for router {} with dpnId {}",
248                             routerName, dpnId);
249                         return;
250                     }
251                     LOG.debug("NAT Service : SNAT -> Removing default SNAT miss entry flow entity for "
252                         + "router {} with dpnId {} in napt switch {}", routerName, dpnId, naptSwitch);
253                     mdsalManager.removeFlow(flowEntity);
254
255                 } catch (Exception ex) {
256                     LOG.debug("NAT Service : SNAT -> Failed to remove default SNAT miss entry flow entity {} : {}",
257                         flowEntity, ex);
258                     return;
259                 }
260                 LOG.debug("NAT Service : SNAT -> Removed default SNAT miss entry flow for dpnID {} with routername {}",
261                     dpnId, routerName);
262
263                 //best effort to check IntExt model
264                 naptSwitchHA.bestEffortDeletion(routerId, routerName, externalIpLabel);
265             }
266         } catch (Exception ex) {
267             LOG.debug("NAT Service : SNAT -> Exception while handling naptSwitch down for router {} : {}",
268                 routerName, ex);
269         }
270     }
271
272     // TODO Clean up the exception handling
273     @SuppressWarnings("checkstyle:IllegalCatch")
274     private void hndlTepEvntsForDpn(StateTunnelList stateTunnelList, TunnelAction tunnelAction) {
275         final BigInteger srcDpnId = new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId());
276         final String srcTepIp = String.valueOf(stateTunnelList.getSrcInfo().getTepIp().getValue());
277         final String destTepIp = String.valueOf(stateTunnelList.getDstInfo().getTepIp().getValue());
278         LOG.trace("NAT Service : Handle tunnel event for srcDpn {} SrcTepIp {} DestTepIp {} ", srcDpnId, srcTepIp,
279             destTepIp);
280         int tunTypeVal = getTunnelType(stateTunnelList);
281
282         LOG.trace("NAT Service : tunTypeVal is {}", tunTypeVal);
283
284         try {
285             String srcTepId = stateTunnelList.getSrcInfo().getTepDeviceId();
286             String tunnelType = stateTunnelList.getTransportType().toString();
287             String tunnelName = stateTunnelList.getTunnelInterfaceName();
288
289             if (tunTypeVal == NatConstants.ITMTunnelLocType.Invalid.getValue()) {
290                 LOG.warn("NAT Service : Ignoring TEP event {} for the DPN {} "
291                         + "since its a INVALID TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and " + "TUNNEL NAME {} ",
292                     tunnelAction, srcTepId, tunnelType, srcTepIp, destTepIp, tunnelName);
293                 return;
294             }
295
296             switch (tunnelAction) {
297                 case TUNNEL_EP_ADD:
298                     if (!hndlTepAddForAllRtrs(srcDpnId, tunnelType, tunnelName, srcTepIp, destTepIp)) {
299                         LOG.debug("NAT Service : Unable to process TEP ADD");
300                     }
301                     break;
302                 case TUNNEL_EP_DELETE:
303                     if (!handleTepDelForAllRtrs(srcDpnId, tunnelType, tunnelName, srcTepIp, destTepIp)) {
304                         LOG.debug("NAT Service : Unable to process TEP DEL");
305                     }
306                     break;
307                 default:
308                     LOG.warn("hndlTepEvntsForDpn: unknown tunnelAction: {}", tunnelAction);
309                     break;
310             }
311         } catch (Exception e) {
312             LOG.error("NAT Service : Unable to handle the TEP event.", e);
313             return;
314         }
315     }
316
317     private boolean hndlTepAddForAllRtrs(BigInteger srcDpnId, String tunnelType, String tunnelName, String srcTepIp,
318                                          String destTepIp) throws Exception {
319         LOG.trace("NAT Service: TEP ADD ----- for EXTERNAL/HWVTEP ITM Tunnel, TYPE {} ,State is UP b/w SRC IP"
320             + " : {} and DEST IP: {}", fibManager.getTransportTypeStr(tunnelType), srcTepIp, destTepIp);
321
322         InstanceIdentifier<DpnRoutersList> dpnRoutersListId = NatUtil.getDpnRoutersId(srcDpnId);
323         Optional<DpnRoutersList> optionalRouterDpnList = NatUtil.read(dataBroker, LogicalDatastoreType
324             .OPERATIONAL, dpnRoutersListId);
325         if (!optionalRouterDpnList.isPresent()) {
326             LOG.warn("NAT Service : RouterDpnList model is empty for DPN {}. Hence ignoring TEP add event for the ITM "
327                     + "TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and TUNNEL NAME {} ",
328                 srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
329             return false;
330         }
331
332         List<RoutersList> routersList = optionalRouterDpnList.get().getRoutersList();
333         if (routersList == null) {
334             LOG.debug("NAT Service : Ignoring TEP add for the DPN {} since no routers are associated"
335                 + " for the DPN having the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and"
336                 + "TUNNEL NAME {} ", srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
337             return false;
338         }
339
340         String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, srcDpnId);
341         for (RoutersList router : routersList) {
342
343             LOG.debug("NAT Service : TEP ADD : DNAT -> Advertising routes for router {} ", router.getRouter());
344             hndlTepAddForDnatInEachRtr(router, nextHopIp, srcDpnId);
345
346             LOG.debug("NAT Service : TEP ADD : SNAT -> Advertising routes for router {} ", router.getRouter());
347             hndlTepAddForSnatInEachRtr(router, srcDpnId, tunnelType, srcTepIp, destTepIp,
348                 tunnelName, nextHopIp);
349         }
350         return true;
351     }
352
353     // TODO Clean up the exception handling
354     @SuppressWarnings("checkstyle:IllegalCatch")
355     private boolean handleTepDelForAllRtrs(BigInteger srcDpnId, String tunnelType, String tunnelName, String srcTepIp,
356                                            String destTepIp) throws Exception {
357
358         LOG.trace("NAT Service: TEP DEL ----- for EXTERNAL/HWVTEP ITM Tunnel, TYPE {} ,State is UP b/w SRC IP"
359             + " : {} and DEST IP: {}", fibManager.getTransportTypeStr(tunnelType), srcTepIp, destTepIp);
360
361         // When tunnel EP is deleted on a DPN , VPN gets two deletion event.
362         // One for a DPN on which tunnel EP was deleted and another for other-end DPN.
363         // Handle only the DPN on which it was deleted , ignore other event.
364         // DPN on which TEP is deleted , endpoint IP will be null.
365         String endpointIpForDPN = null;
366         try {
367             endpointIpForDPN = NatUtil.getEndpointIpAddressForDPN(dataBroker, srcDpnId);
368         } catch (Exception e) {
369                 /* this dpn does not have the VTEP */
370             LOG.debug("NAT Service : DPN {} does not have the VTEP", srcDpnId);
371             endpointIpForDPN = null;
372         }
373
374         if (endpointIpForDPN != null) {
375             LOG.trace("NAT Service : Ignore TEP DELETE event received for DPN {} VTEP IP {} since its "
376                  + "the other end DPN w.r.t the delted TEP", srcDpnId, srcTepIp);
377             return false;
378         }
379
380         List<RoutersList> routersList = null;
381         InstanceIdentifier<DpnRoutersList> dpnRoutersListId = NatUtil.getDpnRoutersId(srcDpnId);
382         Optional<DpnRoutersList> optionalRouterDpnList = NatUtil.read(dataBroker, LogicalDatastoreType
383             .OPERATIONAL, dpnRoutersListId);
384         if (optionalRouterDpnList.isPresent()) {
385             routersList = optionalRouterDpnList.get().getRoutersList();
386         } else {
387             LOG.warn("NAT Service : RouterDpnList is empty for DPN {}. Hence ignoring TEP DEL event for the ITM "
388                     + "TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and TUNNEL NAME {} ",
389                 srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
390             return false;
391         }
392
393         if (routersList == null) {
394             LOG.debug("NAT Service : DPN {} does not have the Routers presence", srcDpnId);
395             return false;
396         }
397
398         for (RoutersList router : routersList) {
399             LOG.debug("NAT Service :  TEP DEL : DNAT -> Withdrawing routes for router {} ", router.getRouter());
400             hndlTepDelForDnatInEachRtr(router, srcDpnId);
401             LOG.debug("NAT Service :  TEP DEL : SNAT -> Withdrawing and Advertising routes for router {} ",
402                 router.getRouter());
403             hndlTepDelForSnatInEachRtr(router, srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
404         }
405         return true;
406     }
407
408     private void hndlTepAddForSnatInEachRtr(RoutersList router, final BigInteger srcDpnId, String tunnelType,
409                                             String srcTepIp, String destTepIp, String tunnelName, String nextHopIp) {
410
411         /*SNAT : Remove the old routes to the external IP having the old TEP IP as the next hop IP
412                  Advertise to the BGP about the new route to the external IP having the new TEP IP
413                   added as the next hop IP
414          */
415         String routerName = router.getRouter();
416
417         // Check if this is externalRouter else ignore
418         InstanceIdentifier<Routers> extRoutersId = NatUtil.buildRouterIdentifier(routerName);
419         Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType
420             .CONFIGURATION, extRoutersId);
421         if (!routerData.isPresent()) {
422             LOG.debug("NAT Service : SNAT -> Ignoring TEP add for router {} since its not External Router",
423                 routerName);
424             return;
425         }
426
427         long routerId = NatUtil.getVpnId(dataBroker, routerName);
428         BigInteger naptId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
429         if (naptId == null || naptId.equals(BigInteger.ZERO)) {
430             LOG.warn("NAT Service : SNAT -> Ignoring TEP add for the DPN {} having the router {} since"
431                 + " the router is not part of the NAT service  - the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and"
432                 + "TUNNEL NAME {} ", srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
433             return;
434         }
435
436         //Check if the DPN having the router is the NAPT switch
437         if (!naptId.equals(srcDpnId)) {
438             /*
439             1) Install default NAT rule from table 21 to 26
440             2) Install the group which forward packet to the tunnel port for the NAPT switch.
441             3) Install the flow 26 which forwards the packet to the group.
442             */
443             if (!hndlTepAddOnNonNaptSwitch(srcDpnId, naptId, tunnelType, srcTepIp, destTepIp, tunnelName,
444                 routerName, routerId)) {
445                 LOG.debug("NAT Service : Unable to process the TEP add event on NON-NAPT switch {}", srcDpnId);
446                 return;
447             }
448             return;
449         }
450         if (!hndlTepAddOnNaptSwitch(srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName, routerId,
451             routerData, nextHopIp)) {
452             LOG.debug("NAT Service : Unable to process the TEP add event on NAPT switch {}", srcDpnId);
453             return;
454         }
455         return;
456     }
457
458     private boolean hndlTepAddOnNonNaptSwitch(BigInteger srcDpnId, BigInteger primaryDpnId, String tunnelType,
459                                               String srcTepIp, String destTepIp, String tunnelName, String routerName,
460                                               long routerId) {
461
462         /*
463         1) Install default NAT rule from table 21 to 26
464         2) Install the group which forward packet to the tunnel port for the NAPT switch.
465         3) Install the flow 26 which forwards the packet to the group.
466         */
467         LOG.debug("NAT Service : SNAT -> Processing TEP add for the DPN {} having the router {} since "
468                 + "its THE NON NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} "
469                 + "and TUNNEL NAME {} ",
470             srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
471         LOG.debug("NAT Service : SNAT -> Install default NAT rule from table 21 to 26");
472         Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerName);
473         Long vpnId;
474         if (vpnName == null) {
475             LOG.debug("NAT Service : SNAT -> Internal VPN associated to router {}", routerId);
476             vpnId = routerId;
477             if (vpnId == NatConstants.INVALID_ID) {
478                 LOG.error("NAT Service : SNAT -> Invalid Internal VPN ID returned for routerName {}", routerId);
479                 return false;
480             }
481             LOG.debug("NAT Service : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerName);
482             //Install default entry in FIB to SNAT table
483             LOG.debug("NAT Service : Installing default route in FIB on DPN {} for router {} with"
484                 + " vpn {}...", srcDpnId, routerName, vpnId);
485             defaultRouteProgrammer.installDefNATRouteInDPN(srcDpnId, vpnId);
486
487             LOG.debug("NAT Service : SNAT -> Install the group which forward packet to the tunnel port "
488                 + "for the NAPT switch {} and the flow 26 which forwards to group", primaryDpnId);
489             externalRouterListner.handleSwitches(srcDpnId, routerName, primaryDpnId);
490         } else {
491             LOG.debug("NAT Service : SNAT -> External BGP VPN (Private BGP) associated to router {}", routerId);
492             vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
493             if (vpnId == NatConstants.INVALID_ID) {
494                 LOG.error("NAT Service : SNAT -> Invalid Private BGP VPN ID returned for routerName {}", routerId);
495                 return false;
496             }
497             if (routerId == NatConstants.INVALID_ID) {
498                 LOG.error("NAT Service : SNAT -> Invalid routId returned for routerName {}", routerId);
499                 return false;
500             }
501             LOG.debug("NAT Service : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerId);
502             //Install default entry in FIB to SNAT table
503             LOG.debug("NAT Service : Installing default route in FIB on dpn {} for routerId {} "
504                 + "with vpnId {}...", srcDpnId, routerId, vpnId);
505             defaultRouteProgrammer.installDefNATRouteInDPN(srcDpnId, vpnId, routerId);
506
507             LOG.debug("NAT Service : Install group in non NAPT switch {}", srcDpnId);
508             List<BucketInfo> bucketInfoForNonNaptSwitches =
509                 externalRouterListner.getBucketInfoForNonNaptSwitches(srcDpnId, srcDpnId, routerName);
510             long groupId = externalRouterListner.installGroup(srcDpnId, routerName, bucketInfoForNonNaptSwitches);
511
512             LOG.debug("NAT Service : SNAT -> in the SNAT miss entry pointing to group {} in the non NAPT switch {}",
513                 vpnId, groupId, srcDpnId);
514             FlowEntity flowEntity =
515                 externalRouterListner.buildSnatFlowEntityWithUpdatedVpnId(srcDpnId, routerName, groupId, vpnId);
516             mdsalManager.installFlow(flowEntity);
517         }
518         return true;
519     }
520
521     private boolean hndlTepAddOnNaptSwitch(BigInteger srcDpnId, String tunnelType, String srcTepIp,
522                                            String destTepIp, String tunnelName, long routerId,
523                                            Optional<Routers> routerData, String nextHopIp) {
524         if (!routerData.isPresent()) {
525             LOG.warn("hndlTepAddOnNaptSwitch: routerData is not present");
526             return false;
527         }
528         String routerName = routerData.get().getRouterName();
529         LOG.debug("NAT Service : SNAT -> Processing TEP add for the DPN {} having the router {} since "
530             + "its THE NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} "
531             + "and TUNNEL NAME {} ", srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
532
533         Uuid networkId = routerData.get().getNetworkId();
534         if (networkId == null) {
535             LOG.warn("NAT Service : SNAT -> Ignoring TEP add since the router {} is not associated to the "
536                 + "external network", routerName);
537             return false;
538         }
539
540         LOG.debug("NAT Service : SNAT -> Router {} is associated with Ext nw {}", routerId, networkId);
541         Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerName);
542         Long vpnId;
543         if (vpnName == null) {
544             LOG.debug("NAT Service : SNAT -> Internal VPN associated to router {}", routerId);
545             vpnId = NatUtil.getVpnId(dataBroker, routerId);
546             if (vpnId == null || vpnId == NatConstants.INVALID_ID) {
547                 LOG.error("Invalid External VPN-ID returned for routerName {}", routerName);
548                 return false;
549             }
550             LOG.debug("NAT Service : SNAT -> Retrieved External VPN-ID {} for router {}", vpnId, routerId);
551         } else {
552             LOG.debug("NAT Service : SNAT -> Private BGP VPN associated to router {}", routerId);
553             vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
554             if (vpnId == null || vpnId == NatConstants.INVALID_ID) {
555                 LOG.error("NAT Service : Invalid vpnId returned for routerName {}", routerName);
556                 return false;
557             }
558             LOG.debug("NAT Service : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerId);
559         }
560
561         /*1) Withdraw the old route to the external IP from the BGP which was having the
562              next hop as the old TEP IP.
563           2) Advertise to the BGP about the new route to the external IP having the
564           new TEP IP as the next hop.
565           3) Populate a new FIB entry with the next hop IP as the new TEP IP using the
566           FIB manager.
567         */
568
569         //Withdraw the old route to the external IP from the BGP which was having the
570         //next hop as the old TEP IP.
571         final String externalVpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
572         if (externalVpnName == null) {
573             LOG.error("NAT Service :  SNAT -> No VPN associated with ext nw {} in router {}",
574                 networkId, routerId);
575             return false;
576         }
577         List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
578         if (externalIps != null) {
579             LOG.debug("NAT Service : Clearing the FIB entries but not the BGP routes");
580             for (String externalIp : externalIps) {
581                 String rd = NatUtil.getVpnRd(dataBroker, externalVpnName);
582                 LOG.debug("NAT Service : Removing Fib entry rd {} prefix {}", rd, externalIp);
583                 fibManager.removeFibEntry(dataBroker, rd, externalIp, null);
584             }
585         }
586
587         /*
588         Advertise to the BGP about the new route to the external IP having the
589         new TEP IP as the next hop.
590         Populate a new FIB entry with the next hop IP as the new TEP IP using the
591         FIB manager.
592         */
593         String rd = NatUtil.getVpnRd(dataBroker, externalVpnName);
594         if (externalIps != null) {
595             for (final String externalIp : externalIps) {
596                 Long label = externalRouterListner.checkExternalIpLabel(routerId,
597                     externalIp);
598                 if (label == null || label == NatConstants.INVALID_ID) {
599                     LOG.debug("NAT Service : SNAT -> Unable to advertise to the DC GW since label is invalid");
600                     return false;
601                 }
602
603                 LOG.debug("NAT Service : SNAT -> Advertise the route to the externalIp {} having nextHopIp {}",
604                     externalIp, nextHopIp);
605                 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, externalVpnName, rd, externalIp,
606                     nextHopIp, label, LOG, RouteOrigin.STATIC, srcDpnId);
607
608                 LOG.debug("NAT Service : SNAT -> Install custom FIB routes "
609                     + "(Table 21 -> Push MPLS label to Tunnel port");
610                 List<Instruction> customInstructions = new ArrayList<>();
611                 customInstructions.add(new InstructionGotoTable(NwConstants.INBOUND_NAPT_TABLE).buildInstruction(0));
612                 CreateFibEntryInput input =
613                     new CreateFibEntryInputBuilder().setVpnName(externalVpnName).setSourceDpid(srcDpnId)
614                         .setInstruction(customInstructions).setIpAddress(externalIp + "/32")
615                         .setServiceId(label).setInstruction(customInstructions).build();
616                 Future<RpcResult<Void>> future = fibRpcService.createFibEntry(input);
617                 ListenableFuture<RpcResult<Void>> listenableFuture = JdkFutureAdapters.listenInPoolThread(future);
618
619                 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<Void>>() {
620
621                     @Override
622                     public void onFailure(Throwable error) {
623                         LOG.error("NAT Service : SNAT -> Error in generate label or fib install process", error);
624                     }
625
626                     @Override
627                     public void onSuccess(RpcResult<Void> result) {
628                         if (result.isSuccessful()) {
629                             LOG.info("NAT Service : SNAT -> Successfully installed custom FIB routes for prefix {}",
630                                 externalIp);
631                         } else {
632                             LOG.error("NAT Service : SNAT -> Error in rpc call to create custom Fib entries "
633                                     + "for prefix {} in DPN {}, {}",
634                                 externalIp, srcDpnId, result.getErrors());
635                         }
636                     }
637                 });
638             }
639         }
640         return true;
641     }
642
643     private void hndlTepAddForDnatInEachRtr(RoutersList router, String nextHopIp, BigInteger tepAddedDpnId) {
644         //DNAT : Advertise the new route to the floating IP having the new TEP IP as the next hop IP
645         final String routerName = router.getRouter();
646
647         InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerName);
648         Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType
649             .CONFIGURATION, routerPortsId);
650         if (!optRouterPorts.isPresent()) {
651             LOG.debug("NAT Service : DNAT -> Could not read Router Ports data object with id: {} from DNAT "
652                 + "FloatinIpInfo", routerName);
653             return;
654         }
655         RouterPorts routerPorts = optRouterPorts.get();
656         List<Ports> interfaces = routerPorts.getPorts();
657
658         Uuid extNwId = routerPorts.getExternalNetworkId();
659         final String vpnName = NatUtil.getAssociatedVPN(dataBroker, extNwId, LOG);
660         if (vpnName == null) {
661             LOG.info("NAT Service : DNAT -> No External VPN associated with ext nw {} for router {}",
662                 extNwId, routerName);
663             return;
664         }
665
666         String rd = NatUtil.getVpnRd(dataBroker, vpnName);
667         for (Ports port : interfaces) {
668             //Get the DPN on which this interface resides
669             final String interfaceName = port.getPortName();
670             final BigInteger fipCfgdDpnId = NatUtil.getDpnForInterface(interfaceService, interfaceName);
671             if (fipCfgdDpnId.equals(BigInteger.ZERO)) {
672                 LOG.info("NAT Service : DNAT -> Skip processing Floating ip configuration for the port {}, "
673                     + "since no DPN present for it", interfaceName);
674                 continue;
675             }
676             if (!fipCfgdDpnId.equals(tepAddedDpnId)) {
677                 LOG.debug("NAT Service : DNAT -> TEP added DPN {} is not the DPN {} which has the "
678                     + "floating IP configured for the port: {}",
679                     tepAddedDpnId, fipCfgdDpnId, interfaceName);
680                 continue;
681             }
682             List<InternalToExternalPortMap> intExtPortMapList = port.getInternalToExternalPortMap();
683             for (InternalToExternalPortMap intExtPortMap : intExtPortMapList) {
684                 final String internalIp = intExtPortMap.getInternalIp();
685                 final String externalIp = intExtPortMap.getExternalIp();
686                 LOG.debug("NAT Service : DNAT -> Advertising the FIB route to the floating IP {} configured "
687                     + "for the port: {}",
688                     externalIp, interfaceName);
689                 long label = floatingIPListener.getOperationalIpMapping(routerName, interfaceName, internalIp);
690                 if (label == NatConstants.INVALID_ID) {
691                     LOG.debug("NAT Service : DNAT -> Unable to advertise to the DC GW since label is invalid");
692                     return;
693                 }
694                 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, vpnName, rd,
695                     externalIp + "/32", nextHopIp, label, LOG, RouteOrigin.STATIC, fipCfgdDpnId);
696
697                 //Install custom FIB routes (Table 21 -> Push MPLS label to Tunnel port
698                 List<Instruction> customInstructions = new ArrayList<>();
699                 customInstructions.add(new InstructionGotoTable(NwConstants.PDNAT_TABLE).buildInstruction(0));
700                 CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName)
701                     .setSourceDpid(fipCfgdDpnId).setInstruction(customInstructions)
702                     .setIpAddress(externalIp + "/32").setServiceId(label).setInstruction(customInstructions).build();
703                 Future<RpcResult<Void>> future = fibRpcService.createFibEntry(input);
704                 ListenableFuture<RpcResult<Void>> listenableFuture = JdkFutureAdapters.listenInPoolThread(future);
705
706                 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<Void>>() {
707
708                     @Override
709                     public void onFailure(Throwable error) {
710                         LOG.error("NAT Service : DNAT -> Error in generate label or fib install process", error);
711                     }
712
713                     @Override
714                     public void onSuccess(RpcResult<Void> result) {
715                         if (result.isSuccessful()) {
716                             LOG.info("NAT Service : DNAT -> Successfully installed custom FIB routes for prefix {}",
717                                 externalIp);
718                         } else {
719                             LOG.error("NAT Service : DNAT -> Error in rpc call to create custom Fib "
720                                 + "entries for prefix {} in DPN {}, {}", externalIp, fipCfgdDpnId, result.getErrors());
721                         }
722                     }
723                 });
724             }
725         }
726     }
727
728     private void hndlTepDelForSnatInEachRtr(RoutersList router, BigInteger dpnId, String tunnelType,
729                                             String srcTepIp, String destTepIp, String tunnelName) {
730         /*SNAT :
731             1) Elect a new switch as the primary NAPT
732             2) Advertise the new routes to BGP for the newly elected TEP IP as the DPN IP
733             3) This will make sure old routes are withdrawn and new routes are advertised.
734          */
735
736         String routerName = router.getRouter();
737         LOG.debug("NAT Service : SNAT -> Trying to clear routes to the External fixed IP associated to the router"
738             + " {}", routerName);
739
740         // Check if this is externalRouter else ignore
741         InstanceIdentifier<Routers> extRoutersId = NatUtil.buildRouterIdentifier(routerName);
742         Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType
743             .CONFIGURATION, extRoutersId);
744         if (!routerData.isPresent()) {
745             LOG.debug("NAT Service : SNAT -> Ignoring TEP del for router {} since its not External Router",
746                 routerName);
747             return;
748         }
749
750         //Check if the router ID is valid
751         long routerId = NatUtil.getVpnId(dataBroker, routerName);
752         if (routerId == NatConstants.INVALID_ID) {
753             LOG.error("NAT Service : SNAT -> Invalid ROUTER-ID {} returned for routerName {}", routerId, routerName);
754             return;
755         }
756
757         //Check if the DPN having the router is the NAPT switch
758         BigInteger naptId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
759         if (naptId == null || naptId.equals(BigInteger.ZERO) || (!naptId.equals(dpnId))) {
760             LOG.warn("NAT Service : SNAT -> Ignoring TEP delete for the DPN {} since"
761                 + " its NOT a NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and"
762                 + "TUNNEL NAME {} ", dpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
763             return;
764         }
765
766         Uuid networkId = routerData.get().getNetworkId();
767         if (networkId == null) {
768             LOG.debug("NAT Service : SNAT -> Ignoring TEP delete for the DPN {} having the router {} "
769                 + "since the Router instance {} not found in ExtRouters model b/w SRC IP {} and DST IP {} "
770                 + "and TUNNEL NAME {} ", dpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
771             return;
772         }
773
774         LOG.debug("NAT Service : SNAT -> Router {} is associated with ext nw {}", routerId, networkId);
775         Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerName);
776         Long vpnId;
777         if (vpnName == null) {
778             LOG.debug("NAT Service : SNAT -> Internal VPN-ID {} associated to router {}", routerId, routerName);
779             vpnId = routerId;
780
781             //Install default entry in FIB to SNAT table
782             LOG.debug("NAT Service : Installing default route in FIB on DPN {} for router {} with"
783                 + " vpn {}...", dpnId, routerName, vpnId);
784             defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId);
785         } else {
786             vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
787             if (vpnId == NatConstants.INVALID_ID) {
788                 LOG.error("NAT Service : SNAT -> Invalid Private BGP VPN ID returned for routerName {}", routerName);
789                 return;
790             }
791             LOG.debug("NAT Service : SNAT -> External BGP VPN (Private BGP) {} associated to router {}",
792                 vpnId, routerName);
793             //Install default entry in FIB to SNAT table
794             LOG.debug("NAT Service : Installing default route in FIB on dpn {} for routerId {} "
795                 + "with vpnId {}...", dpnId, routerId, vpnId);
796             defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, routerId);
797         }
798
799         if (routerData.get().isEnableSnat()) {
800             LOG.info("NAT Service : SNAT enabled for router {}", routerId);
801
802             long routerVpnId = routerId;
803             long bgpVpnId = NatConstants.INVALID_ID;
804             Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
805             if (bgpVpnUuid != null) {
806                 bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
807             }
808             if (bgpVpnId != NatConstants.INVALID_ID) {
809                 LOG.debug("NAT Service : SNAT -> Private BGP VPN ID (Internal BGP VPN ID) {} associated "
810                     + "to the router {}", bgpVpnId, routerName);
811                 routerVpnId = bgpVpnId;
812             } else {
813                 LOG.debug("NAT Service : SNAT -> Internal L3 VPN ID (Router ID) {} associated to the router {}",
814                     routerVpnId, routerName);
815             }
816             //Re-elect the other available switch as the NAPT switch and program the NAT flows.
817             removeSNATFromDPN(dpnId, routerName, routerVpnId, networkId);
818         } else {
819             LOG.info("NAT Service : SNAT is not enabled for router {} to handle addDPN event {}", routerId, dpnId);
820         }
821     }
822
823     private void hndlTepDelForDnatInEachRtr(RoutersList router, BigInteger tepDeletedDpnId) {
824         //DNAT : Withdraw the routes from the BGP
825         String routerName = router.getRouter();
826         LOG.debug("NAT Service : DNAT -> Trying to clear routes to the Floating IP associated to the router {}",
827             routerName);
828
829         InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerName);
830         Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType
831             .CONFIGURATION, routerPortsId);
832         if (!optRouterPorts.isPresent()) {
833             LOG.debug("NAT Service : DNAT -> Could not read Router Ports data object with id: {} from DNAT "
834                     + "FloatingIpInfo",
835                 routerName);
836             return;
837         }
838         RouterPorts routerPorts = optRouterPorts.get();
839         List<Ports> interfaces = routerPorts.getPorts();
840         Uuid extNwId = routerPorts.getExternalNetworkId();
841         final String vpnName = NatUtil.getAssociatedVPN(dataBroker, extNwId, LOG);
842         if (vpnName == null) {
843             LOG.info("NAT Service : DNAT -> No External VPN associated with Ext N/W {} for Router {}",
844                 extNwId, routerName);
845             return;
846         }
847         String rd = NatUtil.getVpnRd(dataBroker, vpnName);
848         for (Ports port : interfaces) {
849             //Get the DPN on which this interface resides
850             String interfaceName = port.getPortName();
851             BigInteger fipCfgdDpnId = NatUtil.getDpnForInterface(interfaceService, interfaceName);
852             if (fipCfgdDpnId.equals(BigInteger.ZERO)) {
853                 LOG.info("NAT Service : DNAT -> Abort processing Floating ip configuration. No DPN for port : {}",
854                     interfaceName);
855                 continue;
856             }
857             if (!fipCfgdDpnId.equals(tepDeletedDpnId)) {
858                 LOG.info("NAT Service : DNAT -> TEP deleted DPN {} is not the DPN {} which has the "
859                     + "floating IP configured for the port: {}",
860                     tepDeletedDpnId, fipCfgdDpnId, interfaceName);
861                 continue;
862             }
863             List<InternalToExternalPortMap> intExtPortMapList = port.getInternalToExternalPortMap();
864             for (InternalToExternalPortMap intExtPortMap : intExtPortMapList) {
865                 String internalIp = intExtPortMap.getInternalIp();
866                 String externalIp = intExtPortMap.getExternalIp();
867                 LOG.debug("NAT Service : DNAT -> Withdrawing the FIB route to the floating IP {} "
868                     + "configured for the port: {}",
869                     externalIp, interfaceName);
870                 NatUtil.removePrefixFromBGP(dataBroker, bgpManager, fibManager, rd, externalIp + "/32", vpnName, LOG);
871                 long label = floatingIPListener.getOperationalIpMapping(routerName, interfaceName, internalIp);
872                 if (label == NatConstants.INVALID_ID) {
873                     LOG.debug("NAT Service : DNAT -> Unable to remove the table 21 entry pushing the "
874                         + "MPLS label to the tunnel since label is invalid");
875                     return;
876                 }
877                 RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName)
878                     .setSourceDpid(fipCfgdDpnId).setIpAddress(externalIp + "/32").setServiceId(label).build();
879                 Future<RpcResult<Void>> future = fibRpcService.removeFibEntry(input);
880                 ListenableFuture<RpcResult<Void>> listenableFuture = JdkFutureAdapters.listenInPoolThread(future);
881
882                 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<Void>>() {
883
884                     @Override
885                     public void onFailure(Throwable error) {
886                         LOG.error("NAT Service : DNAT -> Error in removing the table 21 entry pushing "
887                             + "the MPLS label to the tunnel since label is invalid ", error);
888                     }
889
890                     @Override
891                     public void onSuccess(RpcResult<Void> result) {
892                         if (result.isSuccessful()) {
893                             LOG.info("NAT Service : DNAT -> Successfully removed the entry pushing the "
894                                 + "MPLS label to the tunnel");
895                         } else {
896                             LOG.error("NAT Service : DNAT -> Error in fib rpc call to remove the table 21 "
897                                 + "entry pushing the MPLS label to the tunnnel due to {}", result.getErrors());
898                         }
899                     }
900                 });
901             }
902         }
903     }
904 }