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