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