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