5bb6675fea6b7ecce23693057f64523cb1e4db91
[netvirt.git] / 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 static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
12 import static org.opendaylight.netvirt.natservice.internal.NatUtil.requireNonNullElse;
13
14 import com.google.common.base.Optional;
15 import com.google.common.base.Strings;
16 import com.google.common.util.concurrent.FutureCallback;
17 import com.google.common.util.concurrent.Futures;
18 import com.google.common.util.concurrent.ListenableFuture;
19 import com.google.common.util.concurrent.MoreExecutors;
20 import java.math.BigInteger;
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.concurrent.ExecutionException;
27 import javax.annotation.Nonnull;
28 import javax.annotation.PostConstruct;
29 import javax.inject.Inject;
30 import javax.inject.Singleton;
31 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
32 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
33 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
34 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
35 import org.opendaylight.genius.infra.Datastore.Configuration;
36 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
37 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
38 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
39 import org.opendaylight.genius.infra.TypedWriteTransaction;
40 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
41 import org.opendaylight.genius.mdsalutil.BucketInfo;
42 import org.opendaylight.genius.mdsalutil.FlowEntity;
43 import org.opendaylight.genius.mdsalutil.MDSALUtil;
44 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
45 import org.opendaylight.genius.mdsalutil.NwConstants;
46 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
47 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
48 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
49 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
50 import org.opendaylight.netvirt.elanmanager.api.IElanService;
51 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
52 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
53 import org.opendaylight.netvirt.natservice.api.SnatServiceManager;
54 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
55 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefs;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeExternal;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeHwvtep;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeInternal;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelsState;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInput;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInputBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryOutput;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibEntryInputs;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInput;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInputBuilder;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryOutput;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.DpnRoutersList;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.dpn.routers.list.RoutersList;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig.NatMode;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPorts;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.Ports;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMap;
84 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
85 import org.opendaylight.yangtools.yang.common.RpcResult;
86 import org.slf4j.Logger;
87 import org.slf4j.LoggerFactory;
88
89 @Singleton
90 public class NatTunnelInterfaceStateListener
91     extends AsyncDataTreeChangeListenerBase<StateTunnelList, NatTunnelInterfaceStateListener> {
92
93     private static final Logger LOG = LoggerFactory.getLogger(NatTunnelInterfaceStateListener.class);
94     private final DataBroker dataBroker;
95     private final ManagedNewTransactionRunner txRunner;
96     private final IFibManager fibManager;
97     private final SNATDefaultRouteProgrammer defaultRouteProgrammer;
98     private final NaptSwitchHA naptSwitchHA;
99     private final IMdsalApiManager mdsalManager;
100     private final IdManagerService idManager;
101     private final IBgpManager bgpManager;
102     private final ExternalRoutersListener externalRouterListner;
103     private final SnatServiceManager natServiceManager;
104     private final OdlInterfaceRpcService interfaceService;
105     private final FloatingIPListener floatingIPListener;
106     private final FibRpcService fibRpcService;
107     private final IElanService elanManager;
108     private final IInterfaceManager interfaceManager;
109     private final NatOverVxlanUtil natOverVxlanUtil;
110     private final NatMode natMode;
111
112     protected enum TunnelAction {
113         TUNNEL_EP_ADD,
114         TUNNEL_EP_DELETE,
115         TUNNEL_EP_UPDATE
116     }
117
118     /**
119      * Responsible for listening to tunnel interface state change.
120      *
121      * @param dataBroker             - dataBroker service reference
122      * @param bgpManager             Used to advertise routes to the BGP Router
123      * @param fibManager             - FIB Manager
124      * @param defaultRouteProgrammer - Default Route Programmer
125      * @param naptSwitchHA           - NAPT Switch HA
126      * @param mdsalManager           - MDSAL Manager
127      * @param idManager              - ID manager
128      * @param externalRouterListner  - External Router Listener
129      * @param natServiceManager      - Nat Service Manager
130      * @param interfaceService       - Interface Service
131      * @param floatingIPListener     -  Floating IP Listener
132      * @param fibRpcService          - FIB RPC Service
133      * @param config                 - Nat Service Config
134      * @param elanManager            - Elan Manager
135      * @param interfaceManager       - Interface Manager
136      * @param natOverVxlanUtils      - Nat Over Vxlan Utility
137      */
138     @Inject
139     public NatTunnelInterfaceStateListener(final DataBroker dataBroker,
140                                            final IBgpManager bgpManager,
141                                            final IFibManager fibManager,
142                                            final SNATDefaultRouteProgrammer defaultRouteProgrammer,
143                                            final NaptSwitchHA naptSwitchHA,
144                                            final IMdsalApiManager mdsalManager,
145                                            final IdManagerService idManager,
146                                            final ExternalRoutersListener externalRouterListner,
147                                            final SnatServiceManager natServiceManager,
148                                            final OdlInterfaceRpcService interfaceService,
149                                            final FloatingIPListener floatingIPListener,
150                                            final FibRpcService fibRpcService,
151                                            final NatserviceConfig config,
152                                            final IElanService elanManager,
153                                            final IInterfaceManager interfaceManager,
154                                            final NatOverVxlanUtil natOverVxlanUtils) {
155         super(StateTunnelList.class, NatTunnelInterfaceStateListener.class);
156         this.dataBroker = dataBroker;
157         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
158         this.bgpManager = bgpManager;
159         this.fibManager = fibManager;
160         this.defaultRouteProgrammer = defaultRouteProgrammer;
161         this.naptSwitchHA = naptSwitchHA;
162         this.mdsalManager = mdsalManager;
163         this.idManager = idManager;
164         this.externalRouterListner = externalRouterListner;
165         this.natServiceManager = natServiceManager;
166         this.interfaceService = interfaceService;
167         this.floatingIPListener = floatingIPListener;
168         this.fibRpcService = fibRpcService;
169         this.elanManager = elanManager;
170         this.interfaceManager = interfaceManager;
171         this.natOverVxlanUtil = natOverVxlanUtils;
172         if (config != null) {
173             this.natMode = config.getNatMode();
174         } else {
175             this.natMode = NatMode.Controller;
176         }
177     }
178
179     @Override
180     @PostConstruct
181     public void init() {
182         LOG.info("{} init", getClass().getSimpleName());
183         registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
184     }
185
186     @Override
187     protected InstanceIdentifier<StateTunnelList> getWildCardPath() {
188         return InstanceIdentifier.create(TunnelsState.class).child(StateTunnelList.class);
189     }
190
191     @Override
192     protected NatTunnelInterfaceStateListener getDataTreeChangeListener() {
193         return NatTunnelInterfaceStateListener.this;
194     }
195
196     @Override
197     protected void add(InstanceIdentifier<StateTunnelList> instanceIdentifier, StateTunnelList add) {
198         LOG.trace("add : TEP addtion---- {}", add);
199         hndlTepEvntsForDpn(add, TunnelAction.TUNNEL_EP_ADD);
200     }
201
202     @Override
203     protected void remove(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList del) {
204         LOG.trace("remove : TEP deletion---- {}", del);
205         hndlTepEvntsForDpn(del, TunnelAction.TUNNEL_EP_DELETE);
206     }
207
208     @Override
209     protected void update(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList original,
210                           StateTunnelList update) {
211         LOG.trace("update : Tunnel updation---- {}", update);
212         //UPDATE IS A SEQUENCE OF DELETE AND ADD EVENTS . DELETE MIGHT HAVE CHANGED THE PRIMARY AND ADVERTISED. SO
213         // NOTHING TO HANDLE
214     }
215
216     private int getTunnelType(StateTunnelList stateTunnelList) {
217         int tunTypeVal = 0;
218         if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeInternal.class) {
219             tunTypeVal = NatConstants.ITMTunnelLocType.Internal.getValue();
220         } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeExternal.class) {
221             tunTypeVal = NatConstants.ITMTunnelLocType.External.getValue();
222         } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeHwvtep.class) {
223             tunTypeVal = NatConstants.ITMTunnelLocType.Hwvtep.getValue();
224         } else {
225             tunTypeVal = NatConstants.ITMTunnelLocType.Invalid.getValue();
226         }
227         return tunTypeVal;
228     }
229
230     // TODO Clean up the exception handling
231     @SuppressWarnings("checkstyle:IllegalCatch")
232     void removeSNATFromDPN(BigInteger dpnId, String routerName, long routerId, long routerVpnId,
233             Uuid networkId, ProviderTypes extNwProvType, TypedReadWriteTransaction<Configuration> confTx) {
234         //irrespective of naptswitch or non-naptswitch, SNAT default miss entry need to be removed
235         //remove miss entry to NAPT switch
236         //if naptswitch elect new switch and install Snat flows and remove those flows in oldnaptswitch
237
238         if (routerId == NatConstants.INVALID_ID) {
239             LOG.error("removeSNATFromDPN : SNAT -> Invalid routerId returned for routerName {}", routerName);
240             return;
241         }
242         Collection<String> externalIpCache = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
243         if (extNwProvType == null) {
244             return;
245         }
246         Map<String, Long> externalIpLabel;
247         if (extNwProvType == ProviderTypes.VXLAN) {
248             externalIpLabel = null;
249         } else {
250             externalIpLabel = NatUtil.getExternalIpsLabelForRouter(dataBroker, routerId);
251         }
252         try {
253             final String externalVpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
254             if (externalVpnName == null) {
255                 LOG.error("removeSNATFromDPN : SNAT -> No VPN associated with ext nw {} in router {}",
256                     networkId, routerId);
257                 return;
258             }
259
260             BigInteger naptSwitch = dpnId;
261             boolean naptStatus =
262                 naptSwitchHA.isNaptSwitchDown(routerName, routerId, dpnId, naptSwitch,
263                         routerVpnId, externalIpCache, false, confTx);
264             if (!naptStatus) {
265                 LOG.debug("removeSNATFromDPN:SNAT->NaptSwitchDown:Switch with DpnId {} is not naptSwitch for router {}",
266                     dpnId, routerName);
267                 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
268                 FlowEntity flowEntity = null;
269                 try {
270                     flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId,
271                         routerVpnId, NatConstants.DEL_FLOW);
272                     if (flowEntity == null) {
273                         LOG.error("removeSNATFromDPN : SNAT -> Failed to populate flowentity for "
274                             + "router {} with dpnId {} groupIs {}", routerName, dpnId, groupId);
275                         return;
276                     }
277                     LOG.debug("removeSNATFromDPN : SNAT->Removing default SNAT miss entry flow entity {}", flowEntity);
278                     mdsalManager.removeFlow(confTx, flowEntity);
279
280                 } catch (Exception ex) {
281                     LOG.error("removeSNATFromDPN : SNAT->Failed to remove default SNAT miss entry flow entity {}",
282                         flowEntity, ex);
283                     return;
284                 }
285                 LOG.debug("removeSNATFromDPN:SNAT->Removed default SNAT miss entry flow for dpnID {}, routername {}",
286                     dpnId, routerName);
287
288                 //remove group
289                 try {
290                     LOG.info("removeSNATFromDPN : SNAT->Removing NAPT Group :{} on Dpn {}", groupId, dpnId);
291                     mdsalManager.removeGroup(confTx, dpnId, groupId);
292                 } catch (Exception ex) {
293                     LOG.error("removeSNATFromDPN : SNAT->Failed to remove group {}", groupId, ex);
294                     return;
295                 }
296                 LOG.debug("removeSNATFromDPN : SNAT->Removed default SNAT miss entry flow for dpnID {}, routerName {}",
297                     dpnId, routerName);
298             } else {
299                 naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, routerId, dpnId, externalIpLabel, confTx);
300                 //remove table 26 flow ppointing to table46
301                 FlowEntity flowEntity = null;
302                 try {
303                     flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName, routerVpnId,
304                         NatConstants.DEL_FLOW);
305                     if (flowEntity == null) {
306                         LOG.error("removeSNATFromDPN : SNAT->Failed to populate flowentity for router {} with dpnId {}",
307                             routerName, dpnId);
308                         return;
309                     }
310                     LOG.debug("removeSNATFromDPN : SNAT->Removing default SNAT miss entry flow entity for "
311                         + "router {} with dpnId {} in napt switch {}", routerName, dpnId, naptSwitch);
312                     mdsalManager.removeFlow(confTx, flowEntity);
313
314                 } catch (Exception ex) {
315                     LOG.error("removeSNATFromDPN : SNAT->Failed to remove default SNAT miss entry flow entity {}",
316                         flowEntity, ex);
317                     return;
318                 }
319                 LOG.debug("removeSNATFromDPN : SNAT->Removed default SNAT miss entry flow for dpnID {} "
320                         + "with routername {}", dpnId, routerName);
321
322                 //best effort to check IntExt model
323                 naptSwitchHA.bestEffortDeletion(routerId, routerName, externalIpLabel, confTx);
324             }
325         } catch (InterruptedException | ExecutionException e) {
326             LOG.error("removeSNATFromDPN : SNAT->Exception while handling naptSwitch down for router {}",
327                 routerName, e);
328         }
329     }
330
331     private void hndlTepEvntsForDpn(StateTunnelList stateTunnelList, TunnelAction tunnelAction) {
332         final BigInteger srcDpnId = new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId());
333         final String srcTepIp = stateTunnelList.getSrcInfo().getTepIp().stringValue();
334         final String destTepIp = stateTunnelList.getDstInfo().getTepIp().stringValue();
335         LOG.trace("hndlTepEvntsForDpn : Handle tunnel event for srcDpn {} SrcTepIp {} DestTepIp {} ",
336                 srcDpnId, srcTepIp, destTepIp);
337         int tunTypeVal = getTunnelType(stateTunnelList);
338         LOG.trace("hndlTepEvntsForDpn : tunTypeVal is {}", tunTypeVal);
339         String srcTepId = stateTunnelList.getSrcInfo().getTepDeviceId();
340         String tunnelType = stateTunnelList.getTransportType().toString();
341         String tunnelName = stateTunnelList.getTunnelInterfaceName();
342
343         if (tunTypeVal == NatConstants.ITMTunnelLocType.Invalid.getValue()) {
344             LOG.warn("hndlTepEvntsForDpn : Ignoring TEP event {} for the DPN {} "
345                     + "since its a INVALID TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and " + "TUNNEL NAME {} ",
346                 tunnelAction, srcTepId, tunnelType, srcTepIp, destTepIp, tunnelName);
347             return;
348         }
349
350         switch (tunnelAction) {
351             case TUNNEL_EP_ADD:
352                 try {
353                     txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
354                         if (isTunnelInLogicalGroup(stateTunnelList)
355                                 || !hndlTepAddForAllRtrs(srcDpnId, tunnelType, tunnelName, srcTepIp, destTepIp,
356                                 tx)) {
357                             LOG.debug("hndlTepEvntsForDpn : Unable to process TEP ADD");
358                         }
359                     }).get();
360                 } catch (InterruptedException | ExecutionException e) {
361                     LOG.error("Error processing tunnel endpoint addition", e);
362                 }
363                 break;
364             case TUNNEL_EP_DELETE:
365                 try {
366                     txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
367                         if (!handleTepDelForAllRtrs(srcDpnId, tunnelType, tunnelName, srcTepIp, destTepIp, tx)) {
368                             LOG.debug("hndlTepEvntsForDpn : Unable to process TEP DEL");
369                         }
370                     }).get();
371                 } catch (InterruptedException | ExecutionException e) {
372                     LOG.error("Error processing tunnel endpoint removal", e);
373                 }
374                 break;
375             case TUNNEL_EP_UPDATE:
376                 break;
377             default:
378                 LOG.warn("hndlTepEvntsForDpn: unknown tunnelAction: {}", tunnelAction);
379                 break;
380         }
381     }
382
383     private boolean hndlTepAddForAllRtrs(BigInteger srcDpnId, String tunnelType, String tunnelName, String srcTepIp,
384                                          String destTepIp, TypedReadWriteTransaction<Configuration> writeFlowInvTx)
385             throws ExecutionException, InterruptedException {
386         LOG.trace("hndlTepAddForAllRtrs: TEP ADD ----- for EXTERNAL/HWVTEP ITM Tunnel, TYPE {} ,State is UP b/w SRC IP"
387             + " : {} and DEST IP: {}", fibManager.getTransportTypeStr(tunnelType), srcTepIp, destTepIp);
388
389         InstanceIdentifier<DpnRoutersList> dpnRoutersListId = NatUtil.getDpnRoutersId(srcDpnId);
390         Optional<DpnRoutersList> optionalRouterDpnList =
391                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
392                         LogicalDatastoreType.OPERATIONAL, dpnRoutersListId);
393         if (!optionalRouterDpnList.isPresent()) {
394             LOG.info("hndlTepAddForAllRtrs : RouterDpnList model is empty for DPN {}. Hence ignoring TEP add event "
395                     + "for the ITM TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and TUNNEL NAME {} ",
396                 srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
397             return false;
398         }
399
400         List<RoutersList> routersList = optionalRouterDpnList.get().getRoutersList();
401         if (routersList == null) {
402             LOG.debug("hndlTepAddForAllRtrs : Ignoring TEP add for the DPN {} since no routers are associated"
403                 + " for the DPN having the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and"
404                 + "TUNNEL NAME {} ", srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
405             return false;
406         }
407
408         String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, srcDpnId);
409         for (RoutersList router : routersList) {
410             String routerName = router.getRouter();
411             long routerId = NatUtil.getVpnId(dataBroker, routerName);
412             if (routerId == NatConstants.INVALID_ID) {
413                 LOG.error("hndlTepAddForAllRtrs :Invalid ROUTER-ID {} returned for routerName {}",
414                         routerId, routerName);
415                 return false;
416             }
417             LOG.debug("hndlTepAddForAllRtrs : TEP ADD : DNAT -> Advertising routes for router {} ", routerName);
418             Uuid externalNetworkId = NatUtil.getNetworkIdFromRouterName(dataBroker,routerName);
419             ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
420                     routerName, externalNetworkId);
421             if (extNwProvType == null) {
422                 return false;
423             }
424             hndlTepAddForDnatInEachRtr(router, routerId, nextHopIp, srcDpnId, extNwProvType, writeFlowInvTx);
425
426             LOG.debug("hndlTepAddForAllRtrs : TEP ADD : SNAT -> Advertising routes for router {} ", routerName);
427             hndlTepAddForSnatInEachRtr(router, routerId, srcDpnId, tunnelType, srcTepIp, destTepIp,
428                 tunnelName, nextHopIp, extNwProvType, writeFlowInvTx);
429         }
430         return true;
431     }
432
433     // TODO Clean up the exception handling
434     @SuppressWarnings("checkstyle:IllegalCatch")
435     private boolean handleTepDelForAllRtrs(BigInteger srcDpnId, String tunnelType, String tunnelName, String srcTepIp,
436                                            String destTepIp, TypedReadWriteTransaction<Configuration> writeFlowInvTx)
437             throws ExecutionException, InterruptedException {
438
439         LOG.trace("handleTepDelForAllRtrs : TEP DEL ----- for EXTERNAL/HWVTEP ITM Tunnel,TYPE {},State is UP b/w SRC IP"
440             + " : {} and DEST IP: {}", fibManager.getTransportTypeStr(tunnelType), srcTepIp, destTepIp);
441
442         // When tunnel EP is deleted on a DPN , VPN gets two deletion event.
443         // One for a DPN on which tunnel EP was deleted and another for other-end DPN.
444         // Handle only the DPN on which it was deleted , ignore other event.
445         // DPN on which TEP is deleted , endpoint IP will be null.
446         String endpointIpForDPN = null;
447         try {
448             endpointIpForDPN = NatUtil.getEndpointIpAddressForDPN(dataBroker, srcDpnId);
449         } catch (Exception e) {
450                 /* this dpn does not have the VTEP */
451             LOG.error("handleTepDelForAllRtrs : DPN {} does not have the VTEP", srcDpnId);
452         }
453
454         if (endpointIpForDPN != null) {
455             LOG.trace("handleTepDelForAllRtrs : Ignore TEP DELETE event received for DPN {} VTEP IP {} since its "
456                  + "the other end DPN w.r.t the delted TEP", srcDpnId, srcTepIp);
457             return false;
458         }
459
460         List<RoutersList> routersList = null;
461         InstanceIdentifier<DpnRoutersList> dpnRoutersListId = NatUtil.getDpnRoutersId(srcDpnId);
462         Optional<DpnRoutersList> optionalRouterDpnList =
463                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
464                         LogicalDatastoreType.OPERATIONAL, dpnRoutersListId);
465         if (optionalRouterDpnList.isPresent()) {
466             routersList = optionalRouterDpnList.get().getRoutersList();
467         } else {
468             LOG.warn("handleTepDelForAllRtrs : RouterDpnList is empty for DPN {}.Hence ignoring TEP DEL event "
469                     + "for the ITM TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and TUNNEL NAME {} ",
470                 srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
471             return false;
472         }
473
474         if (routersList == null) {
475             LOG.error("handleTepDelForAllRtrs : DPN {} does not have the Routers presence", srcDpnId);
476             return false;
477         }
478
479         for (RoutersList router : routersList) {
480             String routerName = router.getRouter();
481             LOG.debug("handleTepDelForAllRtrs :  TEP DEL : DNAT -> Withdrawing routes for router {} ", routerName);
482             long routerId = NatUtil.getVpnId(dataBroker, routerName);
483             if (routerId == NatConstants.INVALID_ID) {
484                 LOG.error("handleTepDelForAllRtrs :Invalid ROUTER-ID {} returned for routerName {}",
485                         routerId, routerName);
486                 return false;
487             }
488             Uuid externalNetworkId = NatUtil.getNetworkIdFromRouterName(dataBroker,routerName);
489             ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
490                     routerName, externalNetworkId);
491             if (extNwProvType == null) {
492                 return false;
493             }
494             hndlTepDelForDnatInEachRtr(router, routerId, srcDpnId, extNwProvType);
495             LOG.debug("handleTepDelForAllRtrs :  TEP DEL : SNAT -> Withdrawing and Advertising routes for router {} ",
496                 router.getRouter());
497             hndlTepDelForSnatInEachRtr(router, routerId, srcDpnId, tunnelType, srcTepIp, destTepIp,
498                     tunnelName, extNwProvType, writeFlowInvTx);
499         }
500         return true;
501     }
502
503     private void hndlTepAddForSnatInEachRtr(RoutersList router, long routerId, final BigInteger srcDpnId,
504             String tunnelType, String srcTepIp, String destTepIp, String tunnelName, String nextHopIp,
505             ProviderTypes extNwProvType, TypedReadWriteTransaction<Configuration> writeFlowInvTx)
506             throws ExecutionException, InterruptedException {
507
508         /*SNAT : Remove the old routes to the external IP having the old TEP IP as the next hop IP
509                  Advertise to the BGP about the new route to the external IP having the new TEP IP
510                   added as the next hop IP
511          */
512         String routerName = router.getRouter();
513
514         // Check if this is externalRouter else ignore
515         InstanceIdentifier<Routers> extRoutersId = NatUtil.buildRouterIdentifier(routerName);
516         Optional<Routers> routerData;
517         try {
518             routerData = writeFlowInvTx.read(extRoutersId).get();
519         } catch (InterruptedException | ExecutionException e) {
520             LOG.error("Error reading router data for {}", extRoutersId, e);
521             routerData = Optional.absent();
522         }
523         if (!routerData.isPresent()) {
524             LOG.warn("hndlTepAddForSnatInEachRtr : SNAT->Ignoring TEP add for router {} since its not External Router",
525                     routerName);
526             return;
527         }
528
529         BigInteger naptId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
530         if (naptId == null || naptId.equals(BigInteger.ZERO)) {
531             LOG.warn("hndlTepAddForSnatInEachRtr : SNAT -> Ignoring TEP add for the DPN {} having the router {} since"
532                     + " the router is not part of the NAT service  - the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and"
533                     + "TUNNEL NAME {} ", srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
534             return;
535         }
536         if (natMode == NatMode.Conntrack) {
537             Routers extRouter = routerData.get();
538             natServiceManager.notify(writeFlowInvTx, extRouter, null, naptId, srcDpnId,
539                     SnatServiceManager.Action.CNT_ROUTER_ALL_SWITCH_ENBL);
540             if (extRouter.isEnableSnat()) {
541                 natServiceManager.notify(writeFlowInvTx, extRouter, null, naptId, srcDpnId,
542                         SnatServiceManager.Action.SNAT_ROUTER_ENBL);
543             }
544         } else {
545             Uuid bgpVpnUuId = NatUtil.getVpnForRouter(dataBroker, routerName);
546             //Check if the DPN having the router is the NAPT switch
547             if (!naptId.equals(srcDpnId)) {
548                 /*
549             1) Install default NAT rule from table 21 to 26
550             2) Install the group which forward packet to the tunnel port for the NAPT switch.
551             3) Install the flow 26 which forwards the packet to the group.
552                  */
553                 if (!hndlTepAddOnNonNaptSwitch(srcDpnId, naptId, tunnelType, srcTepIp, destTepIp, tunnelName,
554                         routerName, routerId, bgpVpnUuId, writeFlowInvTx)) {
555                     LOG.error("hndlTepAddForSnatInEachRtr : Unable to process the TEP add event on NON-NAPT switch {}",
556                             srcDpnId);
557                     return;
558                 }
559                 return;
560             }
561             if (!hndlTepAddOnNaptSwitch(srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName, routerId,
562                     routerData, nextHopIp, bgpVpnUuId, extNwProvType, writeFlowInvTx)) {
563                 LOG.debug("hndlTepAddForSnatInEachRtr : Unable to process the TEP add event on NAPT switch {}",
564                         srcDpnId);
565                 return;
566             }
567         }
568         return;
569     }
570
571     private boolean hndlTepAddOnNonNaptSwitch(BigInteger srcDpnId, BigInteger primaryDpnId, String tunnelType,
572         String srcTepIp, String destTepIp, String tunnelName, String routerName, long routerId, Uuid vpnName,
573         TypedWriteTransaction<Configuration> confTx) {
574
575         /*
576         1) Install default NAT rule from table 21 to 26
577         2) Install the group which forward packet to the tunnel port for the NAPT switch.
578         3) Install the flow 26 which forwards the packet to the group.
579         */
580         LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Processing TEP add for the DPN {} having the router {} since "
581                 + "its THE NON NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} "
582                 + "and TUNNEL NAME {} ",
583             srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
584         LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Install default NAT rule from table 21 to 26");
585         Long vpnId;
586         if (vpnName == null) {
587             LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Internal VPN associated to router {}", routerId);
588             vpnId = routerId;
589             if (vpnId == NatConstants.INVALID_ID) {
590                 LOG.error("hndlTepAddOnNonNaptSwitch : SNAT -> Invalid Internal VPN ID returned for routerName {}",
591                         routerId);
592                 return false;
593             }
594             LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerName);
595             //Install default entry in FIB to SNAT table
596             LOG.debug("hndlTepAddOnNonNaptSwitch : Installing default route in FIB on DPN {} for router {} with"
597                 + " vpn {}...", srcDpnId, routerName, vpnId);
598             defaultRouteProgrammer.installDefNATRouteInDPN(srcDpnId, vpnId, confTx);
599
600             LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Install the group which forward packet to the tunnel port "
601                 + "for the NAPT switch {} and the flow 26 which forwards to group", primaryDpnId);
602             externalRouterListner.handleSwitches(srcDpnId, routerName, routerId, primaryDpnId);
603         } else {
604             LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> External BGP VPN (Private BGP) associated to router {}",
605                     routerId);
606             vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
607             if (vpnId == NatConstants.INVALID_ID) {
608                 LOG.error("hndlTepAddOnNonNaptSwitch : SNAT -> Invalid Private BGP VPN ID returned for routerName {}",
609                         routerId);
610                 return false;
611             }
612             if (routerId == NatConstants.INVALID_ID) {
613                 LOG.error("hndlTepAddOnNonNaptSwitch : SNAT -> Invalid routId returned for routerName {}", routerId);
614                 return false;
615             }
616             LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerId);
617             //Install default entry in FIB to SNAT table
618             LOG.debug("hndlTepAddOnNonNaptSwitch : Installing default route in FIB on dpn {} for routerId {} "
619                 + "with vpnId {}...", srcDpnId, routerId, vpnId);
620             defaultRouteProgrammer.installDefNATRouteInDPN(srcDpnId, vpnId, routerId, confTx);
621
622             LOG.debug("hndlTepAddOnNonNaptSwitch : Install group in non NAPT switch {} for router {}",
623                     srcDpnId, routerName);
624             List<BucketInfo> bucketInfoForNonNaptSwitches =
625                 externalRouterListner.getBucketInfoForNonNaptSwitches(srcDpnId, primaryDpnId, routerName, routerId);
626             long groupId = externalRouterListner.installGroup(srcDpnId, routerName, bucketInfoForNonNaptSwitches);
627
628             LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> in the SNAT miss entry pointing to group {} "
629                     + "in the non NAPT switch {}", groupId, srcDpnId);
630             FlowEntity flowEntity =
631                 externalRouterListner.buildSnatFlowEntityWithUpdatedVpnId(srcDpnId, routerName, groupId, vpnId);
632             mdsalManager.addFlow(confTx, flowEntity);
633         }
634         return true;
635     }
636
637     private boolean hndlTepAddOnNaptSwitch(BigInteger srcDpnId, String tunnelType, String srcTepIp,
638                                            String destTepIp, String tunnelName, long routerId,
639                                            Optional<Routers> routerData, String nextHopIp, Uuid vpnName,
640                                            ProviderTypes extNwProvType, TypedWriteTransaction<Configuration> confTx) {
641         if (!routerData.isPresent()) {
642             LOG.warn("hndlTepAddOnNaptSwitch: routerData is not present");
643             return false;
644         }
645         Routers router = routerData.get();
646         String routerName = router.getRouterName();
647         LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Processing TEP add for the DPN {} having the router {} since "
648             + "its THE NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} "
649             + "and TUNNEL NAME {} ", srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
650
651         Uuid networkId = router.getNetworkId();
652         if (networkId == null) {
653             LOG.warn("hndlTepAddOnNaptSwitch : SNAT -> Ignoring TEP add since the router {} is not associated to the "
654                 + "external network", routerName);
655             return false;
656         }
657
658         LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Router {} is associated with Ext nw {}", routerId, networkId);
659         Long vpnId;
660         if (vpnName == null) {
661             LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Internal VPN associated to router {}", routerId);
662             vpnId = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
663             if (vpnId == NatConstants.INVALID_ID) {
664                 LOG.error("hndlTepAddOnNaptSwitch : Invalid External VPN-ID returned for routerName {}", routerName);
665                 return false;
666             }
667             LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Retrieved External VPN-ID {} for router {}", vpnId, routerId);
668         } else {
669             LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Private BGP VPN associated to router {}", routerId);
670             vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
671             if (vpnId == NatConstants.INVALID_ID) {
672                 LOG.error("hndlTepAddOnNaptSwitch : Invalid vpnId returned for routerName {}", routerName);
673                 return false;
674             }
675             LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerId);
676         }
677
678         /*1) Withdraw the old route to the external IP from the BGP which was having the
679              next hop as the old TEP IP.
680           2) Advertise to the BGP about the new route to the external IP having the
681           new TEP IP as the next hop.
682           3) Populate a new FIB entry with the next hop IP as the new TEP IP using the
683           FIB manager.
684         */
685
686         //Withdraw the old route to the external IP from the BGP which was having the
687         //next hop as the old TEP IP.
688         final String externalVpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
689         if (externalVpnName == null) {
690             LOG.error("hndlTepAddOnNaptSwitch :  SNAT -> No VPN associated with ext nw {} in router {}",
691                 networkId, routerId);
692             return false;
693         }
694         Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
695         LOG.debug("hndlTepAddOnNaptSwitch : Clearing the FIB entries but not the BGP routes");
696         for (String externalIp : externalIps) {
697             String rd = NatUtil.getVpnRd(dataBroker, externalVpnName);
698             LOG.debug("hndlTepAddOnNaptSwitch : Removing Fib entry rd {} prefix {}", rd, externalIp);
699             fibManager.removeFibEntry(rd, externalIp, null);
700         }
701
702         /*
703         Advertise to the BGP about the new route to the external IP having the
704         new TEP IP as the next hop.
705         Populate a new FIB entry with the next hop IP as the new TEP IP using the
706         FIB manager.
707         */
708         String rd = NatUtil.getVpnRd(dataBroker, externalVpnName);
709         if (extNwProvType == null) {
710             return false;
711         }
712         String gwMacAddress = null;
713         long l3Vni = 0;
714         if (extNwProvType == ProviderTypes.VXLAN) {
715             // Get the External Gateway MAC Address which is Router gateway MAC address for SNAT
716             gwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
717             if (gwMacAddress != null) {
718                 LOG.debug("hndlTepAddOnNaptSwitch : External Gateway MAC address {} found for External Router ID {}",
719                         gwMacAddress, routerId);
720             } else {
721                 LOG.error("hndlTepAddOnNaptSwitch : No External Gateway MAC address found for External Router ID {}",
722                         routerId);
723                 return false;
724             }
725             //get l3Vni value for external VPN
726             l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
727             if (l3Vni == NatConstants.DEFAULT_L3VNI_VALUE) {
728                 LOG.debug("hndlTepAddOnNaptSwitch : L3VNI value is not configured in Internet VPN {} and RD {} "
729                         + "Carve-out L3VNI value from OpenDaylight VXLAN VNI Pool and continue to installing "
730                         + "NAT flows", vpnName, rd);
731                 l3Vni = natOverVxlanUtil.getInternetVpnVni(externalVpnName, routerId).longValue();
732             }
733         }
734
735         for (final String externalIp : externalIps) {
736             long serviceId = 0;
737             String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
738             if (extNwProvType == ProviderTypes.VXLAN) {
739                 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Advertise the route to the externalIp {} "
740                         + "having nextHopIp {}", externalIp, nextHopIp);
741                 NatEvpnUtil.addRoutesForVxLanProvType(dataBroker, bgpManager, fibManager, externalVpnName, rd,
742                         externalIp, nextHopIp, l3Vni, tunnelName, gwMacAddress, confTx, RouteOrigin.STATIC,
743                         srcDpnId, networkId);
744                 serviceId = l3Vni;
745             } else {
746
747                 Long label = externalRouterListner.checkExternalIpLabel(routerId,
748                         externalIp);
749                 if (label == null || label == NatConstants.INVALID_ID) {
750                     LOG.error("hndlTepAddOnNaptSwitch : SNAT->Unable to advertise to the DC GW "
751                             + "since label is invalid");
752                     return false;
753                 }
754                 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Advertise the route to the externalIp {} "
755                         + "having nextHopIp {}", externalIp, nextHopIp);
756                 long l3vni = 0;
757                 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
758                     l3vni = natOverVxlanUtil.getInternetVpnVni(externalVpnName, l3vni).longValue();
759                 }
760                 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, externalVpnName, rd,
761                     fibExternalIp, nextHopIp, networkId.getValue(), null /* mac-address */, label, l3vni,
762                         RouteOrigin.STATIC, srcDpnId);
763                 serviceId = label;
764             }
765
766             LOG.debug("hndlTepAddOnNaptSwitch: SNAT -> Install custom FIB routes "
767                     + "(Table 21 -> Push MPLS label to Tunnel port");
768             List<Instruction> customInstructions = new ArrayList<>();
769             int customInstructionIndex = 0;
770             long externalSubnetVpnId = NatUtil.getExternalSubnetVpnIdForRouterExternalIp(dataBroker, externalIp,
771                     router);
772             if (externalSubnetVpnId != NatConstants.INVALID_ID) {
773                 LOG.debug("hndlTepAddOnNaptSwitch : Will install custom FIB router with external subnet VPN ID {}",
774                         externalSubnetVpnId);
775                 BigInteger subnetIdMetaData = MetaDataUtil.getVpnIdMetadata(externalSubnetVpnId);
776                 customInstructions.add(new InstructionWriteMetadata(subnetIdMetaData,
777                         MetaDataUtil.METADATA_MASK_VRFID).buildInstruction(customInstructionIndex));
778                 customInstructionIndex++;
779             }
780             customInstructions.add(new InstructionGotoTable(NwConstants.INBOUND_NAPT_TABLE)
781                     .buildInstruction(customInstructionIndex));
782             CreateFibEntryInput input =
783                     new CreateFibEntryInputBuilder().setVpnName(externalVpnName).setSourceDpid(srcDpnId)
784                     .setInstruction(customInstructions).setIpAddress(fibExternalIp)
785                     .setIpAddressSource(FibEntryInputs.IpAddressSource.ExternalFixedIP)
786                     .setServiceId(serviceId).setInstruction(customInstructions).build();
787             ListenableFuture<RpcResult<CreateFibEntryOutput>> listenableFuture = fibRpcService.createFibEntry(input);
788
789             Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<CreateFibEntryOutput>>() {
790
791                 @Override
792                 public void onFailure(@Nonnull Throwable error) {
793                     LOG.error("hndlTepAddOnNaptSwitch : SNAT->Error in generate label or fib install process",
794                             error);
795                 }
796
797                 @Override
798                 public void onSuccess(@Nonnull RpcResult<CreateFibEntryOutput> result) {
799                     if (result.isSuccessful()) {
800                         LOG.info("hndlTepAddOnNaptSwitch : SNAT -> Successfully installed custom FIB routes "
801                                 + "for prefix {}", externalIp);
802                     } else {
803                         LOG.error("hndlTepAddOnNaptSwitch : SNAT -> Error in rpc call to create custom Fib entries "
804                                 + "for prefix {} in DPN {}, {}", externalIp, srcDpnId, result.getErrors());
805                     }
806                 }
807             }, MoreExecutors.directExecutor());
808         }
809
810         return true;
811     }
812
813     private void hndlTepAddForDnatInEachRtr(RoutersList router, long routerId, String nextHopIp,
814             BigInteger tepAddedDpnId, ProviderTypes extNwProvType, TypedWriteTransaction<Configuration> confTx) {
815         //DNAT : Advertise the new route to the floating IP having the new TEP IP as the next hop IP
816         final String routerName = router.getRouter();
817
818         InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerName);
819         Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType
820             .CONFIGURATION, routerPortsId);
821         if (!optRouterPorts.isPresent()) {
822             LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> Could not read Router Ports data object with id: {} "
823                     + "from DNAT FloatinIpInfo", routerName);
824             return;
825         }
826         RouterPorts routerPorts = optRouterPorts.get();
827         Uuid extNwId = routerPorts.getExternalNetworkId();
828         final String vpnName = NatUtil.getAssociatedVPN(dataBroker, extNwId);
829         if (vpnName == null) {
830             LOG.info("hndlTepAddForDnatInEachRtr : DNAT -> No External VPN associated with ext nw {} for router {}",
831                 extNwId, routerName);
832             return;
833         }
834
835         String rd = NatUtil.getVpnRd(dataBroker, vpnName);
836         if (extNwProvType == null) {
837             return;
838         }
839         String gwMacAddress = null;
840         long l3Vni = 0;
841         if (extNwProvType == ProviderTypes.VXLAN) {
842             // Get the External Gateway MAC Address which is Router gateway MAC address for SNAT
843             gwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
844             if (gwMacAddress != null) {
845                 LOG.debug("hndlTepAddForDnatInEachRtr : External GwMAC address {} found for External Router ID {}",
846                         gwMacAddress, routerId);
847             } else {
848                 LOG.error("hndlTepAddForDnatInEachRtr : No External GwMAC address found for External Router ID {}",
849                         routerId);
850                 return;
851             }
852             //get l3Vni value for external VPN
853             l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
854             if (l3Vni == NatConstants.DEFAULT_L3VNI_VALUE) {
855                 LOG.debug("hndlTepAddForDnatInEachRtr : L3VNI value is not configured in Internet VPN {} and RD {} "
856                         + "Carve-out L3VNI value from OpenDaylight VXLAN VNI Pool and continue to installing "
857                         + "NAT flows", vpnName, rd);
858                 l3Vni = natOverVxlanUtil.getInternetVpnVni(vpnName, routerId).longValue();
859             }
860         }
861         for (Ports port : requireNonNullElse(routerPorts.getPorts(), Collections.<Ports>emptyList())) {
862             //Get the DPN on which this interface resides
863             final String interfaceName = port.getPortName();
864             final BigInteger fipCfgdDpnId = NatUtil.getDpnForInterface(interfaceService, interfaceName);
865             if (fipCfgdDpnId.equals(BigInteger.ZERO)) {
866                 LOG.info("hndlTepAddForDnatInEachRtr : DNAT->Skip processing Floating ip configuration for the port {},"
867                     + "since no DPN present for it", interfaceName);
868                 continue;
869             }
870             if (!fipCfgdDpnId.equals(tepAddedDpnId)) {
871                 LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> TEP added DPN {} is not the DPN {} which has the "
872                     + "floating IP configured for the port: {}",
873                     tepAddedDpnId, fipCfgdDpnId, interfaceName);
874                 continue;
875             }
876             for (InternalToExternalPortMap intExtPortMap : requireNonNullElse(port.getInternalToExternalPortMap(),
877                     Collections.<InternalToExternalPortMap>emptyList())) {
878                 final String internalIp = intExtPortMap.getInternalIp();
879                 final String externalIp = intExtPortMap.getExternalIp();
880                 LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> Advertising the FIB route to the floating IP {} "
881                         + "configured for the port: {}", externalIp, interfaceName);
882                 long serviceId = 0;
883                 String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
884
885                 if (extNwProvType == ProviderTypes.VXLAN) {
886                     LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> Advertise the route to the externalIp {} "
887                             + "having nextHopIp {}", externalIp, nextHopIp);
888                     NatEvpnUtil.addRoutesForVxLanProvType(dataBroker, bgpManager, fibManager, vpnName, rd,
889                         externalIp, nextHopIp, l3Vni, interfaceName, gwMacAddress, confTx, RouteOrigin.STATIC,
890                         fipCfgdDpnId, extNwId);
891                     serviceId = l3Vni;
892                 } else {
893                     long label = floatingIPListener.getOperationalIpMapping(routerName, interfaceName, internalIp);
894                     if (label == NatConstants.INVALID_ID) {
895                         LOG.error("hndlTepAddForDnatInEachRtr : DNAT -> Unable to advertise to the DC GW since label "
896                                 + "is invalid");
897                         return;
898                     }
899                     LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> Advertise the route to the externalIp {} "
900                             + "having nextHopIp {}", externalIp, nextHopIp);
901                     long l3vni = 0;
902                     if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
903                         l3vni = natOverVxlanUtil.getInternetVpnVni(vpnName, l3vni).longValue();
904                     }
905                     NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, vpnName, rd,
906                         fibExternalIp, nextHopIp, null, null, label, l3vni, RouteOrigin.STATIC,
907                             fipCfgdDpnId);
908                     serviceId = label;
909                 }
910
911                 //Install custom FIB routes (Table 21 -> Push MPLS label to Tunnel port
912                 List<Instruction> customInstructions = new ArrayList<>();
913                 customInstructions.add(new InstructionGotoTable(NwConstants.PDNAT_TABLE).buildInstruction(0));
914                 CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName)
915                     .setSourceDpid(fipCfgdDpnId).setInstruction(customInstructions)
916                     .setIpAddressSource(FibEntryInputs.IpAddressSource.FloatingIP)
917                     .setIpAddress(fibExternalIp).setServiceId(serviceId).setInstruction(customInstructions)
918                         .build();
919                 ListenableFuture<RpcResult<CreateFibEntryOutput>> listenableFuture =
920                         fibRpcService.createFibEntry(input);
921
922                 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<CreateFibEntryOutput>>() {
923
924                     @Override
925                     public void onFailure(@Nonnull Throwable error) {
926                         LOG.error("hndlTepAddForDnatInEachRtr : DNAT -> Error in generate label or fib install process",
927                                 error);
928                     }
929
930                     @Override
931                     public void onSuccess(@Nonnull RpcResult<CreateFibEntryOutput> result) {
932                         if (result.isSuccessful()) {
933                             LOG.info("hndlTepAddForDnatInEachRtr : DNAT -> Successfully installed custom FIB routes "
934                                     + "for prefix {}", externalIp);
935                         } else {
936                             LOG.error("hndlTepAddForDnatInEachRtr : DNAT -> Error in rpc call to create custom Fib "
937                                 + "entries for prefix {} in DPN {}, {}", externalIp, fipCfgdDpnId, result.getErrors());
938                         }
939                     }
940                 }, MoreExecutors.directExecutor());
941             }
942         }
943     }
944
945     private void hndlTepDelForSnatInEachRtr(RoutersList router, long routerId, BigInteger dpnId, String tunnelType,
946             String srcTepIp, String destTepIp, String tunnelName, ProviderTypes extNwProvType,
947             TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
948        /*SNAT :
949             1) Elect a new switch as the primary NAPT
950             2) Advertise the new routes to BGP for the newly elected TEP IP as the DPN IP
951             3) This will make sure old routes are withdrawn and new routes are advertised.
952          */
953
954         String routerName = router.getRouter();
955         LOG.debug("hndlTepDelForSnatInEachRtr : SNAT -> Trying to clear routes to the External fixed IP associated "
956                 + "to the router {}", routerName);
957
958         // Check if this is externalRouter else ignore
959         InstanceIdentifier<Routers> extRoutersId = NatUtil.buildRouterIdentifier(routerName);
960         Optional<Routers> routerData;
961         try {
962             routerData = confTx.read(extRoutersId).get();
963         } catch (InterruptedException | ExecutionException e) {
964             LOG.error("Error retrieving routers {}", extRoutersId, e);
965             routerData = Optional.absent();
966         }
967         if (!routerData.isPresent()) {
968             LOG.debug("hndlTepDelForSnatInEachRtr : SNAT->Ignoring TEP del for router {} since its not External Router",
969                     routerName);
970             return;
971         }
972
973         //Check if the DPN having the router is the NAPT switch
974         BigInteger naptId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
975         if (naptId == null || naptId.equals(BigInteger.ZERO) || !naptId.equals(dpnId)) {
976             LOG.warn("hndlTepDelForSnatInEachRtr : SNAT -> Ignoring TEP delete for the DPN {} since"
977                     + " its NOT a NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and"
978                     + "TUNNEL NAME {} ", dpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
979             return;
980         }
981         if (natMode == NatMode.Conntrack) {
982             Routers extRouter = routerData.get();
983             natServiceManager.notify(confTx, extRouter, null, naptId, dpnId,
984                     SnatServiceManager.Action.CNT_ROUTER_DISBL);
985             if (extRouter.isEnableSnat()) {
986                 natServiceManager.notify(confTx,extRouter, null, naptId, dpnId,
987                         SnatServiceManager.Action.SNAT_ROUTER_DISBL);
988             }
989         } else {
990
991
992             Uuid networkId = routerData.get().getNetworkId();
993             if (networkId == null) {
994                 LOG.error("hndlTepDelForSnatInEachRtr : SNAT->Ignoring TEP delete for the DPN {} having the router {} "
995                                 + "since the Router instance {} not found in ExtRouters model b/w SRC IP {} and DST "
996                                 + "IP {} and TUNNEL NAME {} ", dpnId, routerData.get().getRouterName(), tunnelType,
997                         srcTepIp, destTepIp, tunnelName);
998                 return;
999             }
1000
1001             LOG.debug("hndlTepDelForSnatInEachRtr : SNAT->Router {} is associated with ext nw {}", routerId, networkId);
1002             Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
1003             Long bgpVpnId;
1004             if (bgpVpnUuid == null) {
1005                 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT->Internal VPN-ID {} associated to router {}",
1006                         routerId, routerName);
1007                 bgpVpnId = routerId;
1008
1009                 //Install default entry in FIB to SNAT table
1010                 LOG.debug("hndlTepDelForSnatInEachRtr : Installing default route in FIB on DPN {} for router {} with"
1011                         + " vpn {}...", dpnId, routerName, bgpVpnId);
1012                 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, bgpVpnId, confTx);
1013             } else {
1014                 bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
1015                 if (bgpVpnId == NatConstants.INVALID_ID) {
1016                     LOG.error("hndlTepDelForSnatInEachRtr :SNAT->Invalid Private BGP VPN ID returned for routerName {}",
1017                             routerName);
1018                     return;
1019                 }
1020                 LOG.debug("hndlTepDelForSnatInEachRtr :SNAT->External BGP VPN (Private BGP) {} associated to router {}",
1021                         bgpVpnId, routerName);
1022                 //Install default entry in FIB to SNAT table
1023                 LOG.debug("hndlTepDelForSnatInEachRtr : Installing default route in FIB on dpn {} for routerId {} "
1024                         + "with vpnId {}...", dpnId, routerId, bgpVpnId);
1025                 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, bgpVpnId, routerId, confTx);
1026             }
1027
1028             if (routerData.get().isEnableSnat()) {
1029                 LOG.info("hndlTepDelForSnatInEachRtr : SNAT enabled for router {}", routerId);
1030
1031                 long routerVpnId = routerId;
1032                 if (bgpVpnId != NatConstants.INVALID_ID) {
1033                     LOG.debug("hndlTepDelForSnatInEachRtr : SNAT -> Private BGP VPN ID (Internal BGP VPN ID) {} "
1034                             + "associated to the router {}", bgpVpnId, routerName);
1035                     routerVpnId = bgpVpnId;
1036                 } else {
1037                     LOG.debug("hndlTepDelForSnatInEachRtr : SNAT -> Internal L3 VPN ID (Router ID) {} "
1038                             + "associated to the router {}", routerVpnId, routerName);
1039                 }
1040                 //Re-elect the other available switch as the NAPT switch and program the NAT flows.
1041                 removeSNATFromDPN(dpnId, routerName, routerId, routerVpnId, networkId, extNwProvType, confTx);
1042             } else {
1043                 LOG.info("hndlTepDelForSnatInEachRtr : SNAT is not enabled for router {} to handle addDPN event {}",
1044                         routerId, dpnId);
1045             }
1046         }
1047     }
1048
1049     private void hndlTepDelForDnatInEachRtr(RoutersList router, long routerId, BigInteger tepDeletedDpnId,
1050             ProviderTypes extNwProvType) {
1051         //DNAT : Withdraw the routes from the BGP
1052         String routerName = router.getRouter();
1053
1054         LOG.debug("hndlTepDelForDnatInEachRtr : DNAT -> Trying to clear routes to the Floating IP "
1055                 + "associated to the router {}", routerName);
1056
1057         InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerName);
1058         Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType
1059             .CONFIGURATION, routerPortsId);
1060         if (!optRouterPorts.isPresent()) {
1061             LOG.debug("hndlTepDelForDnatInEachRtr : DNAT -> Could not read Router Ports data object with id: {} "
1062                     + "from DNAT FloatingIpInfo", routerName);
1063             return;
1064         }
1065         RouterPorts routerPorts = optRouterPorts.get();
1066         Uuid extNwId = routerPorts.getExternalNetworkId();
1067         final String vpnName = NatUtil.getAssociatedVPN(dataBroker, extNwId);
1068         if (vpnName == null) {
1069             LOG.error("hndlTepDelForDnatInEachRtr : DNAT -> No External VPN associated with Ext N/W {} for Router {}",
1070                 extNwId, routerName);
1071             return;
1072         }
1073         String rd = NatUtil.getVpnRd(dataBroker, vpnName);
1074         if (extNwProvType == null) {
1075             return;
1076         }
1077         long l3Vni = 0;
1078         if (extNwProvType == ProviderTypes.VXLAN) {
1079             //get l3Vni value for external VPN
1080             l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
1081             if (l3Vni == NatConstants.DEFAULT_L3VNI_VALUE) {
1082                 LOG.debug("hndlTepDelForDnatInEachRtr : L3VNI value is not configured in Internet VPN {} and RD {} "
1083                         + "Carve-out L3VNI value from OpenDaylight VXLAN VNI Pool and continue to installing "
1084                         + "NAT flows", vpnName, rd);
1085                 l3Vni = natOverVxlanUtil.getInternetVpnVni(vpnName, routerId).longValue();
1086             }
1087         }
1088         for (Ports port : requireNonNullElse(routerPorts.getPorts(), Collections.<Ports>emptyList())) {
1089             //Get the DPN on which this interface resides
1090             String interfaceName = port.getPortName();
1091             BigInteger fipCfgdDpnId = NatUtil.getDpnForInterface(interfaceService, interfaceName);
1092             if (fipCfgdDpnId.equals(BigInteger.ZERO)) {
1093                 LOG.info("hndlTepDelForDnatInEachRtr : DNAT -> Abort processing Floating ip configuration. "
1094                         + "No DPN for port : {}", interfaceName);
1095                 continue;
1096             }
1097             if (!fipCfgdDpnId.equals(tepDeletedDpnId)) {
1098                 LOG.info("hndlTepDelForDnatInEachRtr : DNAT -> TEP deleted DPN {} is not the DPN {} which has the "
1099                     + "floating IP configured for the port: {}",
1100                     tepDeletedDpnId, fipCfgdDpnId, interfaceName);
1101                 continue;
1102             }
1103             for (InternalToExternalPortMap intExtPortMap : requireNonNullElse(port.getInternalToExternalPortMap(),
1104                     Collections.<InternalToExternalPortMap>emptyList())) {
1105                 String internalIp = intExtPortMap.getInternalIp();
1106                 String externalIp = intExtPortMap.getExternalIp();
1107                 externalIp = NatUtil.validateAndAddNetworkMask(externalIp);
1108                 LOG.debug("hndlTepDelForDnatInEachRtr : DNAT -> Withdrawing the FIB route to the floating IP {} "
1109                     + "configured for the port: {}",
1110                     externalIp, interfaceName);
1111                 NatUtil.removePrefixFromBGP(bgpManager, fibManager, rd, externalIp, vpnName, LOG);
1112                 long serviceId = 0;
1113                 if (extNwProvType == ProviderTypes.VXLAN) {
1114                     serviceId = l3Vni;
1115                 } else {
1116                     long label = floatingIPListener.getOperationalIpMapping(routerName, interfaceName, internalIp);
1117                     if (label == NatConstants.INVALID_ID) {
1118                         LOG.error("hndlTepDelForDnatInEachRtr : DNAT -> Unable to remove the table 21 entry pushing the"
1119                                 + " MPLS label to the tunnel since label is invalid");
1120                         return;
1121                     }
1122                     serviceId = label;
1123                 }
1124
1125                 RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName)
1126                     .setSourceDpid(fipCfgdDpnId).setIpAddress(externalIp).setServiceId(serviceId)
1127                     .setIpAddressSource(RemoveFibEntryInput.IpAddressSource.FloatingIP).build();
1128                 ListenableFuture<RpcResult<RemoveFibEntryOutput>> listenableFuture =
1129                         fibRpcService.removeFibEntry(input);
1130
1131                 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<RemoveFibEntryOutput>>() {
1132
1133                     @Override
1134                     public void onFailure(@Nonnull Throwable error) {
1135                         LOG.error("hndlTepDelForDnatInEachRtr : DNAT -> Error in removing the table 21 entry pushing "
1136                             + "the MPLS label to the tunnel since label is invalid ", error);
1137                     }
1138
1139                     @Override
1140                     public void onSuccess(@Nonnull RpcResult<RemoveFibEntryOutput> result) {
1141                         if (result.isSuccessful()) {
1142                             LOG.info("hndlTepDelForDnatInEachRtr : DNAT -> Successfully removed the entry pushing the "
1143                                 + "MPLS label to the tunnel");
1144                         } else {
1145                             LOG.error("hndlTepDelForDnatInEachRtr : DNAT -> Error in fib rpc call to remove the table "
1146                                 + "21 entry pushing the MPLS label to the tunnnel due to {}", result.getErrors());
1147                         }
1148                     }
1149                 }, MoreExecutors.directExecutor());
1150             }
1151         }
1152     }
1153
1154     protected boolean isTunnelInLogicalGroup(StateTunnelList stateTunnelList) {
1155         String ifaceName = stateTunnelList.getTunnelInterfaceName();
1156         if (getTunnelType(stateTunnelList) == NatConstants.ITMTunnelLocType.Internal.getValue()) {
1157             Interface configIface = interfaceManager.getInterfaceInfoFromConfigDataStore(ifaceName);
1158             IfTunnel ifTunnel = configIface != null ? configIface.augmentation(IfTunnel.class) : null;
1159             if (ifTunnel != null && ifTunnel.getTunnelInterfaceType().isAssignableFrom(TunnelTypeVxlan.class)) {
1160                 ParentRefs refs = configIface.augmentation(ParentRefs.class);
1161                 if (refs != null && !Strings.isNullOrEmpty(refs.getParentInterface())) {
1162                     return true; //multiple VxLAN tunnels enabled, i.e. only logical tunnel should be treated
1163                 }
1164             }
1165         }
1166         LOG.trace("isTunnelInLogicalGroup: ignoring the tunnel event for {}", ifaceName);
1167         return false;
1168     }
1169 }