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