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