e4fa49ffebbc6201c993cbc8d4bd0522768eab27
[netvirt.git] / natservice / impl / src / main / java / org / opendaylight / netvirt / natservice / internal / NatTunnelInterfaceStateListener.java
1 /*
2  * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.netvirt.natservice.internal;
10
11 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
12
13 import com.google.common.base.Strings;
14 import com.google.common.util.concurrent.FutureCallback;
15 import com.google.common.util.concurrent.Futures;
16 import com.google.common.util.concurrent.ListenableFuture;
17 import com.google.common.util.concurrent.MoreExecutors;
18 import java.util.ArrayList;
19 import java.util.Collection;
20 import java.util.List;
21 import java.util.Optional;
22 import java.util.concurrent.ExecutionException;
23 import javax.annotation.PreDestroy;
24 import javax.inject.Inject;
25 import javax.inject.Singleton;
26 import org.eclipse.jdt.annotation.NonNull;
27 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
28 import org.opendaylight.genius.infra.Datastore.Configuration;
29 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
30 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
31 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
32 import org.opendaylight.genius.infra.TypedWriteTransaction;
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.MetaDataUtil;
37 import org.opendaylight.genius.mdsalutil.NwConstants;
38 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
39 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
40 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
41 import org.opendaylight.infrautils.utils.concurrent.Executors;
42 import org.opendaylight.mdsal.binding.api.DataBroker;
43 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
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.serviceutils.tools.listener.AbstractAsyncDataTreeChangeListener;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefs;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeExternal;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeHwvtep;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeInternal;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelsState;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.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.CreateFibEntryOutput;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibEntryInputs;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
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.opendaylight.yangtools.yang.common.Uint32;
80 import org.opendaylight.yangtools.yang.common.Uint64;
81 import org.slf4j.Logger;
82 import org.slf4j.LoggerFactory;
83
84 @Singleton
85 public class NatTunnelInterfaceStateListener extends AbstractAsyncDataTreeChangeListener<StateTunnelList> {
86
87     private static final Logger LOG = LoggerFactory.getLogger(NatTunnelInterfaceStateListener.class);
88     private final DataBroker dataBroker;
89     private final ManagedNewTransactionRunner txRunner;
90     private final IFibManager fibManager;
91     private final SNATDefaultRouteProgrammer defaultRouteProgrammer;
92     private final NaptSwitchHA naptSwitchHA;
93     private final IMdsalApiManager mdsalManager;
94     private final IdManagerService idManager;
95     private final IBgpManager bgpManager;
96     private final ExternalRoutersListener externalRouterListner;
97     private final SnatServiceManager natServiceManager;
98     private final OdlInterfaceRpcService interfaceService;
99     private final FloatingIPListener floatingIPListener;
100     private final FibRpcService fibRpcService;
101     private final IElanService elanManager;
102     private final IInterfaceManager interfaceManager;
103     private final NatOverVxlanUtil natOverVxlanUtil;
104     private final NatMode natMode;
105
106     protected enum TunnelAction {
107         TUNNEL_EP_ADD,
108         TUNNEL_EP_DELETE,
109         TUNNEL_EP_UPDATE
110     }
111
112     /**
113      * Responsible for listening to tunnel interface state change.
114      *
115      * @param dataBroker             - dataBroker service reference
116      * @param bgpManager             Used to advertise routes to the BGP Router
117      * @param fibManager             - FIB Manager
118      * @param defaultRouteProgrammer - Default Route Programmer
119      * @param naptSwitchHA           - NAPT Switch HA
120      * @param mdsalManager           - MDSAL Manager
121      * @param idManager              - ID manager
122      * @param externalRouterListner  - External Router Listener
123      * @param natServiceManager      - Nat Service Manager
124      * @param interfaceService       - Interface Service
125      * @param floatingIPListener     -  Floating IP Listener
126      * @param fibRpcService          - FIB RPC Service
127      * @param config                 - Nat Service Config
128      * @param elanManager            - Elan Manager
129      * @param interfaceManager       - Interface Manager
130      * @param natOverVxlanUtils      - Nat Over Vxlan Utility
131      */
132     @Inject
133     public NatTunnelInterfaceStateListener(final DataBroker dataBroker,
134                                            final IBgpManager bgpManager,
135                                            final IFibManager fibManager,
136                                            final SNATDefaultRouteProgrammer defaultRouteProgrammer,
137                                            final NaptSwitchHA naptSwitchHA,
138                                            final IMdsalApiManager mdsalManager,
139                                            final IdManagerService idManager,
140                                            final ExternalRoutersListener externalRouterListner,
141                                            final SnatServiceManager natServiceManager,
142                                            final OdlInterfaceRpcService interfaceService,
143                                            final FloatingIPListener floatingIPListener,
144                                            final FibRpcService fibRpcService,
145                                            final NatserviceConfig config,
146                                            final IElanService elanManager,
147                                            final IInterfaceManager interfaceManager,
148                                            final NatOverVxlanUtil natOverVxlanUtils) {
149         super(dataBroker, LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.create(TunnelsState.class)
150                 .child(StateTunnelList.class),
151                 Executors.newListeningSingleThreadExecutor("NatTunnelInterfaceStateListener", LOG));
152         this.dataBroker = dataBroker;
153         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
154         this.bgpManager = bgpManager;
155         this.fibManager = fibManager;
156         this.defaultRouteProgrammer = defaultRouteProgrammer;
157         this.naptSwitchHA = naptSwitchHA;
158         this.mdsalManager = mdsalManager;
159         this.idManager = idManager;
160         this.externalRouterListner = externalRouterListner;
161         this.natServiceManager = natServiceManager;
162         this.interfaceService = interfaceService;
163         this.floatingIPListener = floatingIPListener;
164         this.fibRpcService = fibRpcService;
165         this.elanManager = elanManager;
166         this.interfaceManager = interfaceManager;
167         this.natOverVxlanUtil = natOverVxlanUtils;
168         if (config != null) {
169             this.natMode = config.getNatMode();
170         } else {
171             this.natMode = NatMode.Controller;
172         }
173     }
174
175     public void init() {
176         LOG.info("{} init", getClass().getSimpleName());
177     }
178
179     @Override
180     @PreDestroy
181     public void close() {
182         super.close();
183         Executors.shutdownAndAwaitTermination(getExecutorService());
184     }
185
186     @Override
187     public void add(InstanceIdentifier<StateTunnelList> instanceIdentifier, StateTunnelList add) {
188         LOG.trace("add : TEP addtion---- {}", add);
189         hndlTepEvntsForDpn(add, TunnelAction.TUNNEL_EP_ADD);
190     }
191
192     @Override
193     public void remove(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList del) {
194         LOG.trace("remove : TEP deletion---- {}", del);
195         // Moved the remove implementation logic to NatTepChangeLister.remove()
196     }
197
198     @Override
199     public void update(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList original,
200                           StateTunnelList update) {
201         LOG.trace("update : Tunnel updation---- {}", update);
202         //UPDATE IS A SEQUENCE OF DELETE AND ADD EVENTS . DELETE MIGHT HAVE CHANGED THE PRIMARY AND ADVERTISED. SO
203         // NOTHING TO HANDLE
204     }
205
206     private int getTunnelType(StateTunnelList stateTunnelList) {
207         int tunTypeVal = 0;
208         if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeInternal.class) {
209             tunTypeVal = NatConstants.ITMTunnelLocType.Internal.getValue();
210         } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeExternal.class) {
211             tunTypeVal = NatConstants.ITMTunnelLocType.External.getValue();
212         } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeHwvtep.class) {
213             tunTypeVal = NatConstants.ITMTunnelLocType.Hwvtep.getValue();
214         } else {
215             tunTypeVal = NatConstants.ITMTunnelLocType.Invalid.getValue();
216         }
217         return tunTypeVal;
218     }
219
220     private void hndlTepEvntsForDpn(StateTunnelList stateTunnelList, TunnelAction tunnelAction) {
221         LOG.trace("hndlTepEvntsForDpn : stateTunnelList {}", stateTunnelList);
222         final Uint64 srcDpnId = stateTunnelList.getSrcInfo() != null
223                 ? Uint64.valueOf(stateTunnelList.getSrcInfo().getTepDeviceId()) : Uint64.ZERO;
224         final String srcTepIp = stateTunnelList.getSrcInfo() != null
225                 ? stateTunnelList.getSrcInfo().getTepIp().stringValue() : null;
226         final String destTepIp = stateTunnelList.getDstInfo() != null
227                 ? stateTunnelList.getDstInfo().getTepIp().stringValue() : null;
228         LOG.trace("hndlTepEvntsForDpn : Handle tunnel event for srcDpn {} SrcTepIp {} DestTepIp {} ",
229                 srcDpnId, srcTepIp, destTepIp);
230         if (srcDpnId == Uint64.ZERO || srcTepIp == null || destTepIp == null) {
231             LOG.error("hndlTepEvntsForDpn invalid srcDpnId {}, srcTepIp {}, destTepIp {}",
232                     srcDpnId, srcTepIp, destTepIp);
233             return;
234         }
235         int tunTypeVal = getTunnelType(stateTunnelList);
236         LOG.trace("hndlTepEvntsForDpn : tunTypeVal is {}", tunTypeVal);
237         String srcTepId = stateTunnelList.getSrcInfo().getTepDeviceId() != null
238                 ? stateTunnelList.getSrcInfo().getTepDeviceId() : "0";
239         String tunnelType = stateTunnelList.getTransportType() != null
240                 ? stateTunnelList.getTransportType().toString() : null;
241         String tunnelName = stateTunnelList.getTunnelInterfaceName();
242
243         if (tunTypeVal == NatConstants.ITMTunnelLocType.Invalid.getValue() || srcDpnId.equals(Uint64.ZERO)
244                 || srcTepIp == null || destTepIp == null) {
245             LOG.warn("hndlTepEvntsForDpn : Ignoring TEP event {} for the DPN {} "
246                     + "since its a INVALID TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and " + "TUNNEL NAME {} ",
247                 tunnelAction, srcTepId, tunnelType, srcTepIp, destTepIp, tunnelName);
248             return;
249         }
250
251         switch (tunnelAction) {
252             case TUNNEL_EP_ADD:
253                 try {
254                     txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
255                         if (isTunnelInLogicalGroup(stateTunnelList)
256                                 || !hndlTepAddForAllRtrs(srcDpnId, tunnelType, tunnelName, srcTepIp, destTepIp,
257                                 tx)) {
258                             LOG.debug("hndlTepEvntsForDpn : Unable to process TEP ADD");
259                         }
260                     }).get();
261                 } catch (InterruptedException | ExecutionException e) {
262                     LOG.error("Error processing tunnel endpoint addition", e);
263                 }
264                 break;
265             case TUNNEL_EP_DELETE:
266                 // Moved the current implementation logic to NatTepChangeListener.remove()
267                 break;
268             case TUNNEL_EP_UPDATE:
269                 break;
270             default:
271                 LOG.warn("hndlTepEvntsForDpn: unknown tunnelAction: {}", tunnelAction);
272                 break;
273         }
274     }
275
276     private boolean hndlTepAddForAllRtrs(Uint64 srcDpnId, String tunnelType, String tunnelName, String srcTepIp,
277                                          String destTepIp, TypedReadWriteTransaction<Configuration> writeFlowInvTx)
278             throws ExecutionException, InterruptedException {
279         LOG.trace("hndlTepAddForAllRtrs: TEP ADD ----- for EXTERNAL/HWVTEP ITM Tunnel, TYPE {} ,State is UP b/w SRC IP"
280             + " : {} and DEST IP: {}", fibManager.getTransportTypeStr(tunnelType), srcTepIp, destTepIp);
281
282         InstanceIdentifier<DpnRoutersList> dpnRoutersListId = NatUtil.getDpnRoutersId(srcDpnId);
283         Optional<DpnRoutersList> optionalRouterDpnList =
284                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
285                         LogicalDatastoreType.OPERATIONAL, dpnRoutersListId);
286         if (!optionalRouterDpnList.isPresent()) {
287             LOG.info("hndlTepAddForAllRtrs : RouterDpnList model is empty for DPN {}. Hence ignoring TEP add event "
288                     + "for the ITM TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and TUNNEL NAME {} ",
289                 srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
290             return false;
291         }
292
293         List<RoutersList> routersList = optionalRouterDpnList.get().getRoutersList();
294         if (routersList == null) {
295             LOG.debug("hndlTepAddForAllRtrs : Ignoring TEP add for the DPN {} since no routers are associated"
296                 + " for the DPN having the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and"
297                 + "TUNNEL NAME {} ", srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
298             return false;
299         }
300
301         String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, srcDpnId);
302         for (RoutersList router : routersList) {
303             String routerName = router.getRouter();
304             Uint32 routerId = NatUtil.getVpnId(dataBroker, routerName);
305             if (routerId == NatConstants.INVALID_ID) {
306                 LOG.error("hndlTepAddForAllRtrs :Invalid ROUTER-ID {} returned for routerName {}",
307                         routerId, routerName);
308                 return false;
309             }
310             LOG.debug("hndlTepAddForAllRtrs : TEP ADD : DNAT -> Advertising routes for router {} ", routerName);
311             Uuid externalNetworkId = NatUtil.getNetworkIdFromRouterName(dataBroker,routerName);
312             ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
313                     routerName, externalNetworkId);
314             if (extNwProvType == null) {
315                 return false;
316             }
317             hndlTepAddForDnatInEachRtr(router, routerId, nextHopIp, srcDpnId, extNwProvType, writeFlowInvTx);
318
319             LOG.debug("hndlTepAddForAllRtrs : TEP ADD : SNAT -> Advertising routes for router {} ", routerName);
320             hndlTepAddForSnatInEachRtr(router, routerId, srcDpnId, tunnelType, srcTepIp, destTepIp,
321                 tunnelName, nextHopIp, extNwProvType, writeFlowInvTx);
322         }
323         return true;
324     }
325
326     private void hndlTepAddForSnatInEachRtr(RoutersList router, Uint32 routerId, final Uint64 srcDpnId,
327             String tunnelType, String srcTepIp, String destTepIp, String tunnelName, String nextHopIp,
328             ProviderTypes extNwProvType, TypedReadWriteTransaction<Configuration> writeFlowInvTx)
329             throws ExecutionException, InterruptedException {
330
331         /*SNAT : Remove the old routes to the external IP having the old TEP IP as the next hop IP
332                  Advertise to the BGP about the new route to the external IP having the new TEP IP
333                   added as the next hop IP
334          */
335         String routerName = router.getRouter();
336
337         // Check if this is externalRouter else ignore
338         InstanceIdentifier<Routers> extRoutersId = NatUtil.buildRouterIdentifier(routerName);
339         Optional<Routers> routerData;
340         try {
341             routerData = writeFlowInvTx.read(extRoutersId).get();
342         } catch (InterruptedException | ExecutionException e) {
343             LOG.error("Error reading router data for {}", extRoutersId, e);
344             routerData = Optional.empty();
345         }
346         if (!routerData.isPresent()) {
347             LOG.warn("hndlTepAddForSnatInEachRtr : SNAT->Ignoring TEP add for router {} since its not External Router",
348                     routerName);
349             return;
350         }
351
352         Uint64 naptId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
353         if (naptId == null || naptId.equals(Uint64.ZERO)) {
354             LOG.warn("hndlTepAddForSnatInEachRtr : SNAT -> Ignoring TEP add for the DPN {} having the router {} since"
355                     + " the router is not part of the NAT service  - the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and"
356                     + "TUNNEL NAME {} ", srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
357             return;
358         }
359         if (natMode == NatMode.Conntrack) {
360             Routers extRouter = routerData.get();
361             natServiceManager.notify(writeFlowInvTx, extRouter, null, naptId, srcDpnId,
362                     SnatServiceManager.Action.CNT_ROUTER_ALL_SWITCH_ENBL);
363             if (extRouter.isEnableSnat()) {
364                 natServiceManager.notify(writeFlowInvTx, extRouter, null, naptId, srcDpnId,
365                         SnatServiceManager.Action.SNAT_ROUTER_ENBL);
366             }
367         } else {
368             Uuid bgpVpnUuId = NatUtil.getVpnForRouter(dataBroker, routerName);
369             //Check if the DPN having the router is the NAPT switch
370             if (!naptId.equals(srcDpnId)) {
371                 /*
372             1) Install default NAT rule from table 21 to 26
373             2) Install the group which forward packet to the tunnel port for the NAPT switch.
374             3) Install the flow 26 which forwards the packet to the group.
375                  */
376                 if (!hndlTepAddOnNonNaptSwitch(srcDpnId, naptId, tunnelType, srcTepIp, destTepIp, tunnelName,
377                         routerName, routerId, bgpVpnUuId, writeFlowInvTx)) {
378                     LOG.error("hndlTepAddForSnatInEachRtr : Unable to process the TEP add event on NON-NAPT switch {}",
379                             srcDpnId);
380                     return;
381                 }
382                 return;
383             }
384             if (!hndlTepAddOnNaptSwitch(srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName, routerId,
385                     routerData, nextHopIp, bgpVpnUuId, extNwProvType, writeFlowInvTx)) {
386                 LOG.debug("hndlTepAddForSnatInEachRtr : Unable to process the TEP add event on NAPT switch {}",
387                         srcDpnId);
388                 return;
389             }
390         }
391         return;
392     }
393
394     private boolean hndlTepAddOnNonNaptSwitch(Uint64 srcDpnId, Uint64 primaryDpnId, String tunnelType,
395         String srcTepIp, String destTepIp, String tunnelName, String routerName, Uint32 routerId, Uuid vpnName,
396         TypedWriteTransaction<Configuration> confTx) {
397
398         /*
399         1) Install default NAT rule from table 21 to 26
400         2) Install the group which forward packet to the tunnel port for the NAPT switch.
401         3) Install the flow 26 which forwards the packet to the group.
402         */
403         LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Processing TEP add for the DPN {} having the router {} since "
404                 + "its THE NON NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} "
405                 + "and TUNNEL NAME {} ",
406             srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
407         LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Install default NAT rule from table 21 to 26");
408         Uint32 vpnId;
409         if (vpnName == null) {
410             LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Internal VPN associated to router {}", routerId);
411             vpnId = routerId;
412             if (vpnId == NatConstants.INVALID_ID) {
413                 LOG.error("hndlTepAddOnNonNaptSwitch : SNAT -> Invalid Internal VPN ID returned for routerName {}",
414                         routerId);
415                 return false;
416             }
417             LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerName);
418             //Install default entry in FIB to SNAT table
419             LOG.debug("hndlTepAddOnNonNaptSwitch : Installing default route in FIB on DPN {} for router {} with"
420                 + " vpn {}...", srcDpnId, routerName, vpnId);
421             defaultRouteProgrammer.installDefNATRouteInDPN(srcDpnId, vpnId, confTx);
422
423             LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Install the group which forward packet to the tunnel port "
424                 + "for the NAPT switch {} and the flow 26 which forwards to group", primaryDpnId);
425             externalRouterListner.handleSwitches(srcDpnId, routerName, routerId, primaryDpnId);
426         } else {
427             LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> External BGP VPN (Private BGP) associated to router {}",
428                     routerId);
429             vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
430             if (vpnId == NatConstants.INVALID_ID) {
431                 LOG.error("hndlTepAddOnNonNaptSwitch : SNAT -> Invalid Private BGP VPN ID returned for routerName {}",
432                         routerId);
433                 return false;
434             }
435             if (routerId == NatConstants.INVALID_ID) {
436                 LOG.error("hndlTepAddOnNonNaptSwitch : SNAT -> Invalid routId returned for routerName {}", routerId);
437                 return false;
438             }
439             LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerId);
440             //Install default entry in FIB to SNAT table
441             LOG.debug("hndlTepAddOnNonNaptSwitch : Installing default route in FIB on dpn {} for routerId {} "
442                 + "with vpnId {}...", srcDpnId, routerId, vpnId);
443             defaultRouteProgrammer.installDefNATRouteInDPN(srcDpnId, vpnId, routerId, confTx);
444
445             LOG.debug("hndlTepAddOnNonNaptSwitch : Install group in non NAPT switch {} for router {}",
446                     srcDpnId, routerName);
447             List<BucketInfo> bucketInfoForNonNaptSwitches =
448                 externalRouterListner.getBucketInfoForNonNaptSwitches(srcDpnId, primaryDpnId, routerName, routerId);
449             Uint32 groupId = NatUtil.getUniqueId(idManager, NatConstants.SNAT_IDPOOL_NAME,
450                 NatUtil.getGroupIdKey(routerName));
451             if (groupId != NatConstants.INVALID_ID) {
452                 externalRouterListner.installGroup(srcDpnId, routerName, groupId, bucketInfoForNonNaptSwitches);
453                 LOG.debug("hndlTepAddOnNonNaptSwitch : SNAT -> in the SNAT miss entry pointing to group {} "
454                         + "in the non NAPT switch {}", groupId, srcDpnId);
455                 FlowEntity flowEntity =
456                     externalRouterListner.buildSnatFlowEntityWithUpdatedVpnId(srcDpnId, routerName, groupId, vpnId);
457                 mdsalManager.addFlow(confTx, flowEntity);
458             } else {
459                 LOG.error("hndlTepAddOnNonNaptSwitch: Unable to obtain group ID for Key: {}", routerName);
460             }
461         }
462         return true;
463     }
464
465     private boolean hndlTepAddOnNaptSwitch(Uint64 srcDpnId, String tunnelType, String srcTepIp,
466                                            String destTepIp, String tunnelName, Uint32 routerId,
467                                            Optional<Routers> routerData, String nextHopIp, Uuid vpnName,
468                                            ProviderTypes extNwProvType, TypedWriteTransaction<Configuration> confTx) {
469         if (!routerData.isPresent()) {
470             LOG.warn("hndlTepAddOnNaptSwitch: routerData is not present");
471             return false;
472         }
473         Routers router = routerData.get();
474         String routerName = router.getRouterName();
475         LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Processing TEP add for the DPN {} having the router {} since "
476             + "its THE NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} "
477             + "and TUNNEL NAME {} ", srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
478
479         Uuid networkId = router.getNetworkId();
480         if (networkId == null) {
481             LOG.warn("hndlTepAddOnNaptSwitch : SNAT -> Ignoring TEP add since the router {} is not associated to the "
482                 + "external network", routerName);
483             return false;
484         }
485
486         LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Router {} is associated with Ext nw {}", routerId, networkId);
487         Uint32 vpnId;
488         if (vpnName == null) {
489             LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Internal VPN associated to router {}", routerId);
490             vpnId = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
491             if (vpnId == NatConstants.INVALID_ID) {
492                 LOG.error("hndlTepAddOnNaptSwitch : Invalid External VPN-ID returned for routerName {}", routerName);
493                 return false;
494             }
495             LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Retrieved External VPN-ID {} for router {}", vpnId, routerId);
496         } else {
497             LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Private BGP VPN associated to router {}", routerId);
498             vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
499             if (vpnId == NatConstants.INVALID_ID) {
500                 LOG.error("hndlTepAddOnNaptSwitch : Invalid vpnId returned for routerName {}", routerName);
501                 return false;
502             }
503             LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerId);
504         }
505
506         /*1) Withdraw the old route to the external IP from the BGP which was having the
507              next hop as the old TEP IP.
508           2) Advertise to the BGP about the new route to the external IP having the
509           new TEP IP as the next hop.
510           3) Populate a new FIB entry with the next hop IP as the new TEP IP using the
511           FIB manager.
512         */
513
514         //Withdraw the old route to the external IP from the BGP which was having the
515         //next hop as the old TEP IP.
516         final String externalVpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
517         if (externalVpnName == null) {
518             LOG.error("hndlTepAddOnNaptSwitch :  SNAT -> No VPN associated with ext nw {} in router {}",
519                 networkId, routerId);
520             return false;
521         }
522         Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
523         LOG.debug("hndlTepAddOnNaptSwitch : Clearing the FIB entries but not the BGP routes");
524         for (String externalIp : externalIps) {
525             String rd = NatUtil.getVpnRd(dataBroker, externalVpnName);
526             LOG.debug("hndlTepAddOnNaptSwitch : Removing Fib entry rd {} prefix {}", rd, externalIp);
527             fibManager.removeFibEntry(rd, externalIp, null, null);
528         }
529
530         /*
531         Advertise to the BGP about the new route to the external IP having the
532         new TEP IP as the next hop.
533         Populate a new FIB entry with the next hop IP as the new TEP IP using the
534         FIB manager.
535         */
536         String rd = NatUtil.getVpnRd(dataBroker, externalVpnName);
537         if (extNwProvType == null) {
538             return false;
539         }
540         String gwMacAddress = null;
541         Uint32 l3Vni = Uint32.ZERO;
542         if (extNwProvType == ProviderTypes.VXLAN) {
543             // Get the External Gateway MAC Address which is Router gateway MAC address for SNAT
544             gwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
545             if (gwMacAddress != null) {
546                 LOG.debug("hndlTepAddOnNaptSwitch : External Gateway MAC address {} found for External Router ID {}",
547                         gwMacAddress, routerId);
548             } else {
549                 LOG.error("hndlTepAddOnNaptSwitch : No External Gateway MAC address found for External Router ID {}",
550                         routerId);
551                 return false;
552             }
553             //get l3Vni value for external VPN
554             l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
555             if (l3Vni == NatConstants.DEFAULT_L3VNI_VALUE) {
556                 LOG.debug("hndlTepAddOnNaptSwitch : L3VNI value is not configured in Internet VPN {} and RD {} "
557                         + "Carve-out L3VNI value from OpenDaylight VXLAN VNI Pool and continue to installing "
558                         + "NAT flows", vpnName, rd);
559                 l3Vni = natOverVxlanUtil.getInternetVpnVni(externalVpnName, routerId);
560             }
561         }
562
563         for (final String externalIp : externalIps) {
564             Uint32 serviceId = null;
565             String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
566             if (extNwProvType == ProviderTypes.VXLAN) {
567                 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Advertise the route to the externalIp {} "
568                         + "having nextHopIp {}", externalIp, nextHopIp);
569                 NatEvpnUtil.addRoutesForVxLanProvType(dataBroker, bgpManager, fibManager, externalVpnName, rd,
570                         externalIp, nextHopIp, l3Vni, tunnelName, gwMacAddress, confTx, RouteOrigin.STATIC,
571                         srcDpnId, networkId);
572                 serviceId = l3Vni;
573             } else {
574
575                 serviceId = externalRouterListner.checkExternalIpLabel(routerId,
576                         externalIp);
577                 if (serviceId == null || serviceId == NatConstants.INVALID_ID) {
578                     LOG.error("hndlTepAddOnNaptSwitch : SNAT->Unable to advertise to the DC GW "
579                             + "since label is invalid");
580                     return false;
581                 }
582                 LOG.debug("hndlTepAddOnNaptSwitch : SNAT -> Advertise the route to the externalIp {} "
583                         + "having nextHopIp {}", externalIp, nextHopIp);
584                 Uint32 l3vni = Uint32.ZERO;
585                 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
586                     l3vni = natOverVxlanUtil.getInternetVpnVni(externalVpnName, l3vni);
587                 }
588                 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, externalVpnName, rd,
589                     fibExternalIp, nextHopIp, networkId.getValue(), null /* mac-address */, serviceId, l3vni,
590                         RouteOrigin.STATIC, srcDpnId);
591             }
592
593             LOG.debug("hndlTepAddOnNaptSwitch: SNAT -> Install custom FIB routes "
594                     + "(Table 21 -> Push MPLS label to Tunnel port");
595             List<Instruction> customInstructions = new ArrayList<>();
596             int customInstructionIndex = 0;
597             Uint32 externalSubnetVpnId = NatUtil.getExternalSubnetVpnIdForRouterExternalIp(dataBroker, externalIp,
598                     router);
599             if (externalSubnetVpnId != NatConstants.INVALID_ID) {
600                 LOG.debug("hndlTepAddOnNaptSwitch : Will install custom FIB router with external subnet VPN ID {}",
601                         externalSubnetVpnId);
602                 Uint64 subnetIdMetaData = MetaDataUtil.getVpnIdMetadata(externalSubnetVpnId.longValue());
603                 customInstructions.add(new InstructionWriteMetadata(subnetIdMetaData,
604                         MetaDataUtil.METADATA_MASK_VRFID).buildInstruction(customInstructionIndex));
605                 customInstructionIndex++;
606             }
607             customInstructions.add(new InstructionGotoTable(NwConstants.INBOUND_NAPT_TABLE)
608                     .buildInstruction(customInstructionIndex));
609             CreateFibEntryInput input =
610                     new CreateFibEntryInputBuilder().setVpnName(externalVpnName).setSourceDpid(srcDpnId)
611                     .setInstruction(customInstructions).setIpAddress(fibExternalIp)
612                     .setIpAddressSource(FibEntryInputs.IpAddressSource.ExternalFixedIP)
613                     .setServiceId(serviceId).setInstruction(customInstructions).build();
614             ListenableFuture<RpcResult<CreateFibEntryOutput>> listenableFuture = fibRpcService.createFibEntry(input);
615
616             Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<CreateFibEntryOutput>>() {
617
618                 @Override
619                 public void onFailure(@NonNull Throwable error) {
620                     LOG.error("hndlTepAddOnNaptSwitch : SNAT->Error in generate label or fib install process",
621                             error);
622                 }
623
624                 @Override
625                 public void onSuccess(@NonNull RpcResult<CreateFibEntryOutput> result) {
626                     if (result.isSuccessful()) {
627                         LOG.info("hndlTepAddOnNaptSwitch : SNAT -> Successfully installed custom FIB routes "
628                                 + "for prefix {}", externalIp);
629                     } else {
630                         LOG.error("hndlTepAddOnNaptSwitch : SNAT -> Error in rpc call to create custom Fib entries "
631                                 + "for prefix {} in DPN {}, {}", externalIp, srcDpnId, result.getErrors());
632                     }
633                 }
634             }, MoreExecutors.directExecutor());
635         }
636
637         return true;
638     }
639
640     private void hndlTepAddForDnatInEachRtr(RoutersList router, Uint32 routerId, String nextHopIp,
641             Uint64 tepAddedDpnId, ProviderTypes extNwProvType, TypedWriteTransaction<Configuration> confTx) {
642         //DNAT : Advertise the new route to the floating IP having the new TEP IP as the next hop IP
643         final String routerName = router.getRouter();
644
645         InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerName);
646         Optional<RouterPorts> optRouterPorts;
647         try {
648             optRouterPorts = SingleTransactionDataBroker.syncReadOptional(dataBroker,
649                     LogicalDatastoreType.CONFIGURATION, routerPortsId);
650         } catch (ExecutionException | InterruptedException e) {
651             LOG.error("hndlTepAddForDnatInEachRtr: Exception while reading RouterPorts DS for the router {}",
652                     routerName, e);
653             return;
654         }
655         if (!optRouterPorts.isPresent()) {
656             LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> Could not read Router Ports data object with id: {} "
657                     + "from DNAT FloatinIpInfo", routerName);
658             return;
659         }
660         RouterPorts routerPorts = optRouterPorts.get();
661         Uuid extNwId = routerPorts.getExternalNetworkId();
662         final String vpnName = NatUtil.getAssociatedVPN(dataBroker, extNwId);
663         if (vpnName == null) {
664             LOG.info("hndlTepAddForDnatInEachRtr : DNAT -> No External VPN associated with ext nw {} for router {}",
665                 extNwId, routerName);
666             return;
667         }
668
669         String rd = NatUtil.getVpnRd(dataBroker, vpnName);
670         if (extNwProvType == null) {
671             return;
672         }
673         String gwMacAddress = null;
674         Uint32 l3Vni = Uint32.ZERO;
675         if (extNwProvType == ProviderTypes.VXLAN) {
676             // Get the External Gateway MAC Address which is Router gateway MAC address for SNAT
677             gwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
678             if (gwMacAddress != null) {
679                 LOG.debug("hndlTepAddForDnatInEachRtr : External GwMAC address {} found for External Router ID {}",
680                         gwMacAddress, routerId);
681             } else {
682                 LOG.error("hndlTepAddForDnatInEachRtr : No External GwMAC address found for External Router ID {}",
683                         routerId);
684                 return;
685             }
686             //get l3Vni value for external VPN
687             l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
688             if (l3Vni == NatConstants.DEFAULT_L3VNI_VALUE) {
689                 LOG.debug("hndlTepAddForDnatInEachRtr : L3VNI value is not configured in Internet VPN {} and RD {} "
690                         + "Carve-out L3VNI value from OpenDaylight VXLAN VNI Pool and continue to installing "
691                         + "NAT flows", vpnName, rd);
692                 l3Vni = natOverVxlanUtil.getInternetVpnVni(vpnName, routerId);
693             }
694         }
695         for (Ports port : routerPorts.nonnullPorts()) {
696             //Get the DPN on which this interface resides
697             final String interfaceName = port.getPortName();
698             final Uint64 fipCfgdDpnId = NatUtil.getDpnForInterface(interfaceService, interfaceName);
699             if (fipCfgdDpnId.equals(Uint64.ZERO)) {
700                 LOG.info("hndlTepAddForDnatInEachRtr : DNAT->Skip processing Floating ip configuration for the port {},"
701                     + "since no DPN present for it", interfaceName);
702                 continue;
703             }
704             if (!fipCfgdDpnId.equals(tepAddedDpnId)) {
705                 LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> TEP added DPN {} is not the DPN {} which has the "
706                     + "floating IP configured for the port: {}",
707                     tepAddedDpnId, fipCfgdDpnId, interfaceName);
708                 continue;
709             }
710             for (InternalToExternalPortMap intExtPortMap : port.nonnullInternalToExternalPortMap()) {
711                 final String internalIp = intExtPortMap.getInternalIp();
712                 final String externalIp = intExtPortMap.getExternalIp();
713                 LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> Advertising the FIB route to the floating IP {} "
714                         + "configured for the port: {}", externalIp, interfaceName);
715                 Uint32 serviceId = null;
716                 String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
717
718                 if (extNwProvType == ProviderTypes.VXLAN) {
719                     LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> Advertise the route to the externalIp {} "
720                             + "having nextHopIp {}", externalIp, nextHopIp);
721                     NatEvpnUtil.addRoutesForVxLanProvType(dataBroker, bgpManager, fibManager, vpnName, rd,
722                         externalIp, nextHopIp, l3Vni, interfaceName, gwMacAddress, confTx, RouteOrigin.STATIC,
723                         fipCfgdDpnId, extNwId);
724                     serviceId = l3Vni;
725                 } else {
726                     serviceId = floatingIPListener.getOperationalIpMapping(routerName, interfaceName, internalIp);
727                     if (serviceId == null || serviceId == NatConstants.INVALID_ID) {
728                         LOG.error("hndlTepAddForDnatInEachRtr : DNAT -> Unable to advertise to the DC GW since label "
729                                 + "is invalid");
730                         return;
731                     }
732                     LOG.debug("hndlTepAddForDnatInEachRtr : DNAT -> Advertise the route to the externalIp {} "
733                             + "having nextHopIp {}", externalIp, nextHopIp);
734                     Uint32 l3vni = Uint32.ZERO;
735                     if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
736                         l3vni = natOverVxlanUtil.getInternetVpnVni(vpnName, l3vni);
737                     }
738                     NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, vpnName, rd,
739                         fibExternalIp, nextHopIp, null, null, serviceId, l3vni,
740                             RouteOrigin.STATIC, fipCfgdDpnId);
741                 }
742
743                 //Install custom FIB routes (Table 21 -> Push MPLS label to Tunnel port
744                 List<Instruction> customInstructions = new ArrayList<>();
745                 customInstructions.add(new InstructionGotoTable(NwConstants.PDNAT_TABLE).buildInstruction(0));
746                 CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName)
747                     .setSourceDpid(fipCfgdDpnId).setInstruction(customInstructions)
748                     .setIpAddressSource(FibEntryInputs.IpAddressSource.FloatingIP)
749                     .setIpAddress(fibExternalIp).setServiceId(serviceId).setInstruction(customInstructions)
750                         .build();
751                 ListenableFuture<RpcResult<CreateFibEntryOutput>> listenableFuture =
752                         fibRpcService.createFibEntry(input);
753
754                 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<CreateFibEntryOutput>>() {
755
756                     @Override
757                     public void onFailure(@NonNull Throwable error) {
758                         LOG.error("hndlTepAddForDnatInEachRtr : DNAT -> Error in generate label or fib install process",
759                                 error);
760                     }
761
762                     @Override
763                     public void onSuccess(@NonNull RpcResult<CreateFibEntryOutput> result) {
764                         if (result.isSuccessful()) {
765                             LOG.info("hndlTepAddForDnatInEachRtr : DNAT -> Successfully installed custom FIB routes "
766                                     + "for prefix {}", externalIp);
767                         } else {
768                             LOG.error("hndlTepAddForDnatInEachRtr : DNAT -> Error in rpc call to create custom Fib "
769                                 + "entries for prefix {} in DPN {}, {}", externalIp, fipCfgdDpnId, result.getErrors());
770                         }
771                     }
772                 }, MoreExecutors.directExecutor());
773             }
774         }
775     }
776
777     protected boolean isTunnelInLogicalGroup(StateTunnelList stateTunnelList) {
778         String ifaceName = stateTunnelList.getTunnelInterfaceName();
779         if (getTunnelType(stateTunnelList) == NatConstants.ITMTunnelLocType.Internal.getValue()) {
780             Interface configIface = interfaceManager.getInterfaceInfoFromConfigDataStore(ifaceName);
781             IfTunnel ifTunnel = configIface != null ? configIface.augmentation(IfTunnel.class) : null;
782             if (ifTunnel != null && ifTunnel.getTunnelInterfaceType().isAssignableFrom(TunnelTypeVxlan.class)) {
783                 ParentRefs refs = configIface.augmentation(ParentRefs.class);
784                 if (refs != null && !Strings.isNullOrEmpty(refs.getParentInterface())) {
785                     return true; //multiple VxLAN tunnels enabled, i.e. only logical tunnel should be treated
786                 }
787             }
788         }
789         LOG.trace("isTunnelInLogicalGroup: ignoring the tunnel event for {}", ifaceName);
790         return false;
791     }
792 }