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