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