Bug 7120 : NAT Support For GRE TEP add/del is missing
[netvirt.git] / vpnservice / natservice / natservice-impl / src / main / java / org / opendaylight / netvirt / natservice / internal / NatTunnelInterfaceStateListener.java
1 /*
2  * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.netvirt.natservice.internal;
10
11 import com.google.common.base.Optional;
12 import com.google.common.util.concurrent.FutureCallback;
13 import com.google.common.util.concurrent.Futures;
14 import com.google.common.util.concurrent.JdkFutureAdapters;
15 import com.google.common.util.concurrent.ListenableFuture;
16 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
17 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
18 import org.opendaylight.genius.mdsalutil.*;
19 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
20 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
21 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
22 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
23 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.DpnRoutersList;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.DpnRoutersListKey;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.dpn.routers.list.RoutersList;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.*;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.*;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPorts;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.Ports;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.IpMapping;
38 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
40 import org.opendaylight.yangtools.yang.common.RpcResult;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44 import java.math.BigInteger;
45 import java.util.ArrayList;
46 import java.util.HashMap;
47 import java.util.List;
48 import java.util.concurrent.Future;
49
50 public class NatTunnelInterfaceStateListener extends AsyncDataTreeChangeListenerBase<StateTunnelList, NatTunnelInterfaceStateListener> implements
51         AutoCloseable{
52     private static final Logger LOG = LoggerFactory.getLogger(NatTunnelInterfaceStateListener.class);
53     private final DataBroker dataBroker;
54     private IFibManager fibManager;
55     private SNATDefaultRouteProgrammer defaultRouteProgrammer;
56     private NaptSwitchHA naptSwitchHA;
57     private IMdsalApiManager mdsalManager;
58     private IdManagerService idManager;
59     private IBgpManager bgpManager;
60     private ExternalRoutersListener externalRouterListner;
61     private OdlInterfaceRpcService interfaceService;
62     private FloatingIPListener floatingIPListener;
63     private FibRpcService fibRpcService;
64
65     protected  enum TunnelAction {
66         TUNNEL_EP_ADD,
67         TUNNEL_EP_DELETE,
68         TUNNEL_EP_UPDATE
69     }
70
71     /**
72      * Responsible for listening to tunnel interface state change
73      *
74      * @param dataBroker - dataBroker service reference
75      * @param bgpManager Used to advertise routes to the BGP Router
76      * @param fibManager - FIB Manager
77      * @param defaultRouteProgrammer - Default Route Programmer
78      * @param naptSwitchHA - NAPT Switch HA
79      * @param mdsalManager - MDSAL Manager
80      * @param idManager - ID manager
81      * @param externalRouterListner - External Router Listner
82      * @param interfaceService - Interface Service
83      * @param floatingIPListener -  Floating IP Listner
84      * @param fibRpcService - FIB RPC Service
85      */
86     public NatTunnelInterfaceStateListener(final DataBroker dataBroker,
87                                            final IBgpManager bgpManager,
88                                            final IFibManager fibManager,
89                                            final SNATDefaultRouteProgrammer defaultRouteProgrammer,
90                                            final NaptSwitchHA naptSwitchHA,
91                                            final IMdsalApiManager mdsalManager,
92                                            final IdManagerService idManager,
93                                            final ExternalRoutersListener externalRouterListner,
94                                            final OdlInterfaceRpcService interfaceService,
95                                            final FloatingIPListener floatingIPListener,
96                                            final FibRpcService fibRpcService) {
97         super(StateTunnelList.class, NatTunnelInterfaceStateListener.class);
98         this.dataBroker = dataBroker;
99         this.bgpManager = bgpManager;
100         this.fibManager = fibManager;
101         this.defaultRouteProgrammer = defaultRouteProgrammer;
102         this.naptSwitchHA = naptSwitchHA;
103         this.mdsalManager = mdsalManager;
104         this.idManager = idManager;
105         this.externalRouterListner = externalRouterListner;
106         this.interfaceService = interfaceService;
107         this.floatingIPListener = floatingIPListener;
108         this.fibRpcService = fibRpcService;
109     }
110
111     @Override
112     public void init() {
113         LOG.info("{} init", getClass().getSimpleName());
114         registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
115     }
116
117     @Override
118     protected InstanceIdentifier<StateTunnelList> getWildCardPath() {
119         return InstanceIdentifier.create(TunnelsState.class).child(StateTunnelList.class);
120     }
121
122     @Override
123     protected NatTunnelInterfaceStateListener getDataTreeChangeListener() {
124         return NatTunnelInterfaceStateListener.this;
125     }
126
127     @Override
128     protected void add(InstanceIdentifier<StateTunnelList> instanceIdentifier, StateTunnelList add) {
129         LOG.trace("NAT Service : TEP addtion---- {}", add);
130         hndlTepEvntsForDpn(add, TunnelAction.TUNNEL_EP_ADD);
131     }
132
133     @Override
134     protected void remove(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList del) {
135         LOG.trace("NAT Service : TEP deletion---- {}", del);
136         hndlTepEvntsForDpn(del, TunnelAction.TUNNEL_EP_DELETE);
137     }
138
139     @Override
140     protected void update(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList original, StateTunnelList update) {
141         LOG.trace("NAT Service : Tunnel updation---- {}", update);
142         //UPDATE IS A SEQUENCE OF DELETE AND ADD EVENTS . DELETE MIGHT HAVE CHANGED THE PRIMARY AND ADVERTISED. SO
143         // NOTHING TO HANDLE
144     }
145
146     private int getTunnelType (StateTunnelList stateTunnelList) {
147         int tunTypeVal = 0;
148         if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeInternal.class) {
149             tunTypeVal = NatConstants.ITMTunnelLocType.Internal.getValue();
150         } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeExternal.class) {
151             tunTypeVal = NatConstants.ITMTunnelLocType.External.getValue();
152         } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeHwvtep.class) {
153             tunTypeVal = NatConstants.ITMTunnelLocType.Hwvtep.getValue();
154         } else {
155             tunTypeVal = NatConstants.ITMTunnelLocType.Invalid.getValue();
156         }
157         return tunTypeVal;
158     }
159
160     void removeSNATFromDPN(BigInteger dpnId, String routerName, long routerVpnId, Uuid networkId) {
161         //irrespective of naptswitch or non-naptswitch, SNAT default miss entry need to be removed
162         //remove miss entry to NAPT switch
163         //if naptswitch elect new switch and install Snat flows and remove those flows in oldnaptswitch
164
165         //get ExternalIpIn prior
166         List<String> externalIpCache;
167         //HashMap Label
168         HashMap<String,Long> externalIpLabel;
169         Long routerId = NatUtil.getVpnId(dataBroker, routerName);
170         if (routerId == NatConstants.INVALID_ID) {
171             LOG.error("NAT Service : SNAT -> Invalid routerId returned for routerName {}",routerName);
172             return;
173         }
174         externalIpCache = NatUtil.getExternalIpsForRouter(dataBroker,routerId);
175         externalIpLabel = NatUtil.getExternalIpsLabelForRouter(dataBroker,routerId);
176         try {
177             final String externalVpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
178             if (externalVpnName == null) {
179                 LOG.error("NAT Service : SNAT -> No VPN associated with ext nw {} in router {}",
180                         networkId, routerId);
181                 return;
182             }
183
184             BigInteger naptSwitch = dpnId;
185             boolean naptStatus = naptSwitchHA.isNaptSwitchDown(routerName,dpnId,naptSwitch,routerVpnId,externalIpCache,false);
186             if (!naptStatus) {
187                 LOG.debug("NAT Service : SNAT -> NaptSwitchDown: Switch with DpnId {} is not naptSwitch for router {}",
188                         dpnId, routerName);
189                 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
190                 FlowEntity flowEntity = null;
191                 try {
192                     flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId, routerVpnId, NatConstants.DEL_FLOW);
193                     if (flowEntity == null) {
194                         LOG.debug("NAT Service : SNAT -> Failed to populate flowentity for router {} with dpnId {} groupIs {}",routerName,dpnId,groupId);
195                         return;
196                     }
197                     LOG.debug("NAT Service : SNAT -> Removing default SNAT miss entry flow entity {}",flowEntity);
198                     mdsalManager.removeFlow(flowEntity);
199
200                 } catch (Exception ex) {
201                     LOG.debug("NAT Service : SNAT -> Failed to remove default SNAT miss entry flow entity {} : {}",flowEntity,ex);
202                     return;
203                 }
204                 LOG.debug("NAT Service : SNAT -> Removed default SNAT miss entry flow for dpnID {} with routername {}", dpnId, routerName);
205
206                 //remove group
207                 GroupEntity groupEntity = null;
208                 try {
209                     groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
210                             GroupTypes.GroupAll, null);
211                     LOG.info("NAT Service : SNAT -> Removing NAPT GroupEntity:{}", groupEntity);
212                     mdsalManager.removeGroup(groupEntity);
213                 } catch (Exception ex) {
214                     LOG.debug("NAT Service : SNAT -> Failed to remove group entity {} : {}",groupEntity,ex);
215                     return;
216                 }
217                 LOG.debug("NAT Service : SNAT -> Removed default SNAT miss entry flow for dpnID {} with routerName {}", dpnId, routerName);
218             } else {
219                 naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, dpnId,externalIpLabel);
220                 //remove table 26 flow ppointing to table46
221                 FlowEntity flowEntity = null;
222                 try {
223                     flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName, routerVpnId, NatConstants.DEL_FLOW);
224                     if (flowEntity == null) {
225                         LOG.debug("NAT Service : SNAT -> Failed to populate flowentity for router {} with dpnId {}",routerName,dpnId);
226                         return;
227                     }
228                     LOG.debug("NAT Service : SNAT -> Removing default SNAT miss entry flow entity for router {} with dpnId {} in napt switch {}"
229                             ,routerName,dpnId,naptSwitch);
230                     mdsalManager.removeFlow(flowEntity);
231
232                 } catch (Exception ex) {
233                     LOG.debug("NAT Service : SNAT -> Failed to remove default SNAT miss entry flow entity {} : {}",flowEntity,ex);
234                     return;
235                 }
236                 LOG.debug("NAT Service : SNAT -> Removed default SNAT miss entry flow for dpnID {} with routername {}", dpnId, routerName);
237
238                 //best effort to check IntExt model
239                 naptSwitchHA.bestEffortDeletion(routerId,routerName,externalIpLabel);
240             }
241         } catch (Exception ex) {
242             LOG.debug("NAT Service : SNAT -> Exception while handling naptSwitch down for router {} : {}",routerName,ex);
243         }
244     }
245
246     private void hndlTepEvntsForDpn(StateTunnelList stateTunnelList, TunnelAction tunnelAction) {
247         final BigInteger srcDpnId = new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId());
248         final String srcTepIp = String.valueOf(stateTunnelList.getSrcInfo().getTepIp().getValue());
249         final String destTepIp = String.valueOf(stateTunnelList.getDstInfo().getTepIp().getValue());
250         LOG.trace("NAT Service : Handle tunnel event for srcDpn {} SrcTepIp {} DestTepIp {} ", srcDpnId, srcTepIp,
251                 destTepIp);
252         int tunTypeVal = getTunnelType(stateTunnelList);
253
254         LOG.trace("NAT Service : tunTypeVal is {}", tunTypeVal);
255
256         try {
257             String srcTepId = stateTunnelList.getSrcInfo().getTepDeviceId();
258             String tunnelType = stateTunnelList.getTransportType().toString();
259             String tunnelName = stateTunnelList.getTunnelInterfaceName();
260
261             if(tunTypeVal == NatConstants.ITMTunnelLocType.Internal.getValue()){
262                 LOG.debug("NAT Service : Ignoring TEP event {} for the DPN {} " +
263                         "since its a INTERNAL TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and " +
264                         "TUNNEL NAME {} ", tunnelAction, srcTepId, tunnelType, srcTepIp, destTepIp, tunnelName);
265                 return;
266             }else if(tunTypeVal == NatConstants.ITMTunnelLocType.Invalid.getValue()){
267                 LOG.warn("NAT Service : Ignoring TEP event {} for the DPN {} " +
268                         "since its a INVALID TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and " +
269                         "TUNNEL NAME {} ", tunnelAction, srcTepId, tunnelType, srcTepIp, destTepIp, tunnelName);
270                 return;
271             }
272
273             switch(tunnelAction){
274                 case TUNNEL_EP_ADD:
275                     if(!hndlTepAddForAllRtrs(srcDpnId, tunnelType, tunnelName, srcTepIp, destTepIp)){
276                         LOG.debug("NAT Service : Unable to process TEP ADD");
277                     }
278                     break;
279                 case TUNNEL_EP_DELETE:
280                     if(!handleTepDelForAllRtrs(srcDpnId, tunnelType, tunnelName, srcTepIp, destTepIp)){
281                         LOG.debug("NAT Service : Unable to process TEP DEL");
282                     }
283                     break;
284             }
285         } catch (Exception e) {
286             LOG.error("NAT Service : Unable to handle the TEP event.", e);
287             return;
288         }
289     }
290
291     private boolean hndlTepAddForAllRtrs(BigInteger srcDpnId, String tunnelType, String tunnelName, String srcTepIp,
292                                                String destTepIp) throws Exception{
293         LOG.trace("NAT Service: TEP ADD ----- for EXTERNAL/HWVTEP ITM Tunnel, TYPE {} ,State is UP b/w SRC IP" +
294                 " : {} and DEST IP: {}", fibManager.getTransportTypeStr(tunnelType), srcTepIp, destTepIp);
295
296         InstanceIdentifier<DpnRoutersList> dpnRoutersListId = NatUtil.getDpnRoutersId(srcDpnId);
297         Optional<DpnRoutersList> optionalRouterDpnList = NatUtil.read(dataBroker, LogicalDatastoreType
298                 .OPERATIONAL, dpnRoutersListId);
299         if (!optionalRouterDpnList.isPresent()) {
300             LOG.warn("NAT Service : RouterDpnList model is empty for DPN {}. Hence ignoring TEP add event for the ITM " +
301                             "TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and TUNNEL NAME {} ", srcDpnId,
302                     tunnelType, srcTepIp, destTepIp, tunnelName);
303             return false;
304         }
305
306         List<RoutersList> routersList = optionalRouterDpnList.get().getRoutersList();
307         if(routersList == null) {
308             LOG.debug("NAT Service : Ignoring TEP add for the DPN {} since no routers are associated" +
309                     " for the DPN having the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and" +
310                     "TUNNEL NAME {} ", srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
311             return false;
312         }
313
314         String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, srcDpnId);
315         for (RoutersList router : routersList) {
316
317             LOG.debug("NAT Service : TEP ADD : DNAT -> Advertising routes for router {} ", router.getRouter());
318             hndlTepAddForDnatInEachRtr(router, nextHopIp, srcDpnId);
319
320             LOG.debug("NAT Service : TEP ADD : SNAT -> Advertising routes for router {} ", router.getRouter());
321             hndlTepAddForSnatInEachRtr(router, srcDpnId, tunnelType, srcTepIp, destTepIp,
322                     tunnelName, nextHopIp);
323         }
324         return true;
325     }
326
327     private boolean handleTepDelForAllRtrs(BigInteger srcDpnId, String tunnelType, String tunnelName, String srcTepIp,
328                                                String destTepIp) throws Exception{
329
330         LOG.trace("NAT Service: TEP DEL ----- for EXTERNAL/HWVTEP ITM Tunnel, TYPE {} ,State is UP b/w SRC IP" +
331                 " : {} and DEST IP: {}", fibManager.getTransportTypeStr(tunnelType), srcTepIp, destTepIp);
332
333         // When tunnel EP is deleted on a DPN , VPN gets two deletion event.
334         // One for a DPN on which tunnel EP was deleted and another for other-end DPN.
335         // Handle only the DPN on which it was deleted , ignore other event.
336         // DPN on which TEP is deleted , endpoint IP will be null.
337         String endpointIpForDPN = null;
338         try {
339             endpointIpForDPN = NatUtil.getEndpointIpAddressForDPN(dataBroker, srcDpnId);
340         } catch (Exception e) {
341                 /* this dpn does not have the VTEP */
342             LOG.debug("NAT Service : DPN {} does not have the VTEP", srcDpnId);
343             endpointIpForDPN = null;
344         }
345
346         if (endpointIpForDPN != null) {
347             LOG.trace("NAT Service : Ignore TEP DELETE event received for DPN {} VTEP IP {} since its the other end DPN w.r.t the delted TEP", srcDpnId,
348                     srcTepIp);
349             return false;
350         }
351
352         List<RoutersList> routersList = null;
353         InstanceIdentifier<DpnRoutersList> dpnRoutersListId = NatUtil.getDpnRoutersId(srcDpnId);
354         Optional<DpnRoutersList> optionalRouterDpnList = NatUtil.read(dataBroker, LogicalDatastoreType
355                 .OPERATIONAL, dpnRoutersListId);
356         if (optionalRouterDpnList.isPresent()) {
357             routersList = optionalRouterDpnList.get().getRoutersList();
358         }else{
359             LOG.warn("NAT Service : RouterDpnList is empty for DPN {}. Hence ignoring TEP DEL event for the ITM " +
360                             "TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and TUNNEL NAME {} ", srcDpnId,
361                     tunnelType, srcTepIp, destTepIp, tunnelName);
362             return false;
363         }
364
365         if(routersList == null) {
366             LOG.debug("NAT Service : DPN {} does not have the Routers presence", srcDpnId);
367             return false;
368         }
369
370         for (RoutersList router : routersList) {
371             LOG.debug("NAT Service :  TEP DEL : DNAT -> Withdrawing routes for router {} ", router.getRouter());
372             hndlTepDelForDnatInEachRtr(router, srcDpnId);
373             LOG.debug("NAT Service :  TEP DEL : SNAT -> Withdrawing and Advertising routes for router {} ",
374                     router.getRouter());
375             hndlTepDelForSnatInEachRtr(router, srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
376         }
377         return true;
378     }
379
380     private void hndlTepAddForSnatInEachRtr(RoutersList router, final BigInteger srcDpnId, String tunnelType,
381                                         String srcTepIp, String destTepIp, String tunnelName, String nextHopIp){
382
383         /*SNAT : Remove the old routes to the external IP having the old TEP IP as the next hop IP
384                  Advertise to the BGP about the new route to the external IP having the new TEP IP
385                   added as the next hop IP
386          */
387         String routerName = router.getRouter();
388
389         // Check if this is externalRouter else ignore
390         InstanceIdentifier<Routers> extRoutersId = NatUtil.buildRouterIdentifier(routerName);
391         Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType
392                 .CONFIGURATION, extRoutersId);
393         if (!routerData.isPresent()) {
394             LOG.debug("NAT Service : SNAT -> Ignoring TEP add for router {} since its not External Router",
395                     routerName);
396             return;
397         }
398
399         long routerId = NatUtil.getVpnId(dataBroker, routerName);
400         BigInteger naptId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
401         if (naptId == null || naptId.equals(BigInteger.ZERO)) {
402             LOG.warn("NAT Service : SNAT -> Ignoring TEP add for the DPN {} having the router {} since" +
403                     " the router is not part of the NAT service  - the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and" +
404                     "TUNNEL NAME {} ", srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
405             return;
406         }
407
408         //Check if the DPN having the router is the NAPT switch
409         if( !naptId.equals(srcDpnId)){
410             /*
411             1) Install default NAT rule from table 21 to 26
412             2) Install the group which forward packet to the tunnel port for the NAPT switch.
413             3) Install the flow 26 which forwards the packet to the group.
414             */
415             if (!hndlTepAddOnNonNaptSwitch(srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName, routerName, routerId)){
416                 LOG.debug("NAT Service : Unable to process the TEP add event on NON-NAPT switch {}", srcDpnId);
417                 return;
418             }
419             return;
420         }
421         if (!hndlTepAddOnNaptSwitch(srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName, routerId, routerData, nextHopIp)){
422             LOG.debug("NAT Service : Unable to process the TEP add event on NAPT switch {}", srcDpnId);
423             return;
424         }
425         return;
426     }
427
428     private boolean hndlTepAddOnNonNaptSwitch(BigInteger srcDpnId, String tunnelType, String srcTepIp, String destTepIp,
429                                                 String tunnelName, String routerName, long routerId){
430
431         /*
432         1) Install default NAT rule from table 21 to 26
433         2) Install the group which forward packet to the tunnel port for the NAPT switch.
434         3) Install the flow 26 which forwards the packet to the group.
435         */
436         LOG.debug("NAT Service : SNAT -> Processing TEP add for the DPN {} having the router {} since " +
437                         "its THE NON NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} " + "and TUNNEL NAME {} ",
438                 srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
439         LOG.debug("NAT Service : SNAT -> Install default NAT rule from table 21 to 26");
440         Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerName);
441         Long vpnId;
442         if (vpnName == null) {
443             LOG.debug("NAT Service : SNAT -> Internal VPN associated to router {}",routerId);
444             vpnId = routerId;
445             if (vpnId == NatConstants.INVALID_ID) {
446                 LOG.error("NAT Service : SNAT -> Invalid Internal VPN ID returned for routerName {}",routerId);
447                 return false;
448             }
449             LOG.debug("NAT Service : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerName);
450             //Install default entry in FIB to SNAT table
451             LOG.debug("NAT Service : Installing default route in FIB on DPN {} for router {} with" +
452                     " vpn {}...", srcDpnId,routerName,vpnId);
453             defaultRouteProgrammer.installDefNATRouteInDPN(srcDpnId, vpnId);
454
455             LOG.debug("NAT Service : SNAT -> Install the group which forward packet to the tunnel port for the NAPT switch" +
456                     " and the flow 26 which forwards to group");
457             externalRouterListner.handleSwitches(srcDpnId, routerName, srcDpnId);
458         } else {
459             LOG.debug("NAT Service : SNAT -> External BGP VPN (Private BGP) associated to router {}",routerId);
460             vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
461             if (vpnId == NatConstants.INVALID_ID) {
462                 LOG.error("NAT Service : SNAT -> Invalid Private BGP VPN ID returned for routerName {}", routerId);
463                 return false;
464             }
465             if (routerId == NatConstants.INVALID_ID) {
466                 LOG.error("NAT Service : SNAT -> Invalid routId returned for routerName {}",routerId);
467                 return false;
468             }
469             LOG.debug("NAT Service : SNAT -> Retrieved vpnId {} for router {}",vpnId, routerId);
470             //Install default entry in FIB to SNAT table
471             LOG.debug("NAT Service : Installing default route in FIB on dpn {} for routerId {} " +
472                     "with vpnId {}...", srcDpnId,routerId,vpnId);
473             defaultRouteProgrammer.installDefNATRouteInDPN(srcDpnId, vpnId, routerId);
474
475             LOG.debug("NAT Service : Install group in non NAPT switch {}", srcDpnId);
476             List<BucketInfo> bucketInfoForNonNaptSwitches = externalRouterListner.getBucketInfoForNonNaptSwitches(srcDpnId, srcDpnId, routerName);
477             long groupId = externalRouterListner.installGroup(srcDpnId, routerName, bucketInfoForNonNaptSwitches);
478
479             LOG.debug("NAT Service : SNAT -> in the SNAT miss entry pointing to group {} in the non NAPT switch {}",
480                     vpnId, groupId, srcDpnId);
481             FlowEntity flowEntity = externalRouterListner.buildSnatFlowEntityWithUpdatedVpnId(srcDpnId, routerName, groupId, vpnId);
482             mdsalManager.installFlow(flowEntity);
483         }
484         return true;
485     }
486
487     private boolean hndlTepAddOnNaptSwitch(BigInteger srcDpnId, String tunnelType, String srcTepIp,
488                                              String destTepIp, String tunnelName, long routerId,
489                                              Optional<Routers> routerData, String nextHopIp){
490         String routerName = routerData.get().getRouterName();
491         LOG.debug("NAT Service : SNAT -> Processing TEP add for the DPN {} having the router {} since " +
492                 "its THE NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} " +
493                 "and TUNNEL NAME {} ", srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
494
495         Uuid networkId = routerData.get().getNetworkId();
496         if (networkId == null) {
497             LOG.warn("NAT Service : SNAT -> Ignoring TEP add since the router {} is not associated to the " +
498                     "external network", routerName);
499             return false;
500         }
501
502         LOG.debug("NAT Service : SNAT -> Router {} is associated with Ext nw {}", routerId, networkId);
503         Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerName);
504         Long vpnId;
505         if (vpnName == null) {
506             LOG.debug("NAT Service : SNAT -> Internal VPN associated to router {}", routerId);
507             vpnId = NatUtil.getVpnId(dataBroker, routerId);
508             if (vpnId == null || vpnId == NatConstants.INVALID_ID) {
509                 LOG.error("Invalid External VPN-ID returned for routerName {}", routerName);
510                 return false;
511             }
512             LOG.debug("NAT Service : SNAT -> Retrieved External VPN-ID {} for router {}", vpnId, routerId);
513         } else {
514             LOG.debug("NAT Service : SNAT -> Private BGP VPN associated to router {}", routerId);
515             vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
516             if (vpnId == null || vpnId == NatConstants.INVALID_ID) {
517                 LOG.error("NAT Service : Invalid vpnId returned for routerName {}", routerName);
518                 return false;
519             }
520             LOG.debug("NAT Service : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerId);
521         }
522
523         /*1) Withdraw the old route to the external IP from the BGP which was having the
524              next hop as the old TEP IP.
525           2) Advertise to the BGP about the new route to the external IP having the
526           new TEP IP as the next hop.
527           3) Populate a new FIB entry with the next hop IP as the new TEP IP using the
528           FIB manager.
529         */
530
531         //Withdraw the old route to the external IP from the BGP which was having the
532         //next hop as the old TEP IP.
533         final String externalVpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
534         if (externalVpnName == null) {
535             LOG.error("NAT Service :  SNAT -> No VPN associated with ext nw {} in router {}",
536                     networkId, routerId);
537             return false;
538         }
539         List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
540         if (externalIps != null) {
541             LOG.debug("NAT Service : Clearing the FIB entries but not the BGP routes");
542             for (String externalIp : externalIps) {
543                 String rd = NatUtil.getVpnRd(dataBroker, externalVpnName);
544                 LOG.debug("NAT Service : Removing Fib entry rd {} prefix {}", rd, externalIp);
545                 fibManager.removeFibEntry(dataBroker, rd, externalIp, null);
546             }
547         }
548
549         /*
550         Advertise to the BGP about the new route to the external IP having the
551         new TEP IP as the next hop.
552         Populate a new FIB entry with the next hop IP as the new TEP IP using the
553         FIB manager.
554         */
555         String rd = NatUtil.getVpnRd(dataBroker, externalVpnName);
556         if (externalIps != null) {
557             for (final String externalIp : externalIps) {
558                 Long label = externalRouterListner.checkExternalIpLabel(routerId,
559                         externalIp);
560                 if(label == null || label == NatConstants.INVALID_ID){
561                     LOG.debug("NAT Service : SNAT -> Unable to advertise to the DC GW since label is invalid" );
562                     return false;
563                 }
564
565                 LOG.debug("NAT Service : SNAT -> Advertise the route to the externalIp {} having nextHopIp {}", externalIp,
566                         nextHopIp);
567                 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, rd, externalIp, nextHopIp,
568                         label, LOG, RouteOrigin.STATIC);
569
570                 LOG.debug("NAT Service : SNAT -> Install custom FIB routes ( Table 21 -> Push MPLS label to Tunnel port");
571                 List<Instruction> customInstructions = new ArrayList<>();
572                 customInstructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.INBOUND_NAPT_TABLE }).
573                         buildInstruction(0));
574                 CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(externalVpnName).setSourceDpid(srcDpnId).
575                         setInstruction(customInstructions).setIpAddress(externalIp + "/32").setServiceId(label).setInstruction(customInstructions).build();
576                 Future<RpcResult<Void>> future = fibRpcService.createFibEntry(input);
577                 ListenableFuture<RpcResult<Void>> listenableFuture = JdkFutureAdapters.listenInPoolThread(future);
578
579                 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<Void>>() {
580
581                     @Override
582                     public void onFailure(Throwable error) {
583                         LOG.error("NAT Service : SNAT -> Error in generate label or fib install process", error);
584                     }
585
586                     @Override
587                     public void onSuccess(RpcResult<Void> result) {
588                         if(result.isSuccessful()) {
589                             LOG.info("NAT Service : SNAT -> Successfully installed custom FIB routes for prefix {}", externalIp);
590                         } else {
591                             LOG.error("NAT Service : SNAT -> Error in rpc call to create custom Fib entries for prefix {} in DPN {}, {}",
592                                     externalIp, srcDpnId, result.getErrors());
593                         }
594                     }
595                 });
596             }
597         }
598         return true;
599     }
600
601     private void hndlTepAddForDnatInEachRtr(RoutersList router, String nextHopIp, BigInteger tepAddedDpnId){
602         //DNAT : Advertise the new route to the floating IP having the new TEP IP as the next hop IP
603         final String routerName = router.getRouter();
604
605         InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerName);
606         Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType
607                 .CONFIGURATION, routerPortsId);
608         if (!optRouterPorts.isPresent()) {
609             LOG.debug("NAT Service : DNAT -> Could not read Router Ports data object with id: {} from DNAT " +
610                     "FloatinIpInfo", routerName);
611             return;
612         }
613         RouterPorts routerPorts = optRouterPorts.get();
614         List<Ports> interfaces = routerPorts.getPorts();
615
616         Uuid extNwId = routerPorts.getExternalNetworkId();
617         final String vpnName = NatUtil.getAssociatedVPN(dataBroker, extNwId, LOG);
618         if (vpnName == null) {
619             LOG.info("NAT Service : DNAT -> No External VPN associated with ext nw {} for router {}",
620                     extNwId, routerName);
621             return;
622         }
623
624         String rd = NatUtil.getVpnRd(dataBroker, vpnName);
625         for (Ports port : interfaces) {
626             //Get the DPN on which this interface resides
627             final String interfaceName = port.getPortName();
628             final BigInteger fipCfgdDpnId = NatUtil.getDpnForInterface(interfaceService, interfaceName);
629             if(fipCfgdDpnId.equals(BigInteger.ZERO)) {
630                 LOG.info("NAT Service : DNAT -> Skip processing Floating ip configuration for the port {}, since no DPN present for it", interfaceName);
631                 continue;
632             }
633             if(!fipCfgdDpnId.equals(tepAddedDpnId)) {
634                 LOG.debug("NAT Service : DNAT -> TEP added DPN {} is not the DPN {} which has the floating IP configured for the port: {}",
635                         tepAddedDpnId, fipCfgdDpnId, interfaceName);
636                 continue;
637             }
638             List<IpMapping> ipMapping = port.getIpMapping();
639             for (final IpMapping ipMap : ipMapping) {
640                 final String internalIp = ipMap.getInternalIp();
641                 final String externalIp = ipMap.getExternalIp();
642                 LOG.debug("NAT Service : DNAT -> Advertising the FIB route to the floating IP {} configured for the port: {}",
643                         externalIp, interfaceName);
644                 long label = floatingIPListener.getOperationalIpMapping(routerName, interfaceName, internalIp);
645                 if(label == NatConstants.INVALID_ID){
646                     LOG.debug("NAT Service : DNAT -> Unable to advertise to the DC GW since label is invalid" );
647                     return;
648                 }
649                 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, rd, externalIp + "/32", nextHopIp, label, LOG, RouteOrigin.STATIC);
650
651                 //Install custom FIB routes ( Table 21 -> Push MPLS label to Tunnel port
652                 List<Instruction> customInstructions = new ArrayList<>();
653                 customInstructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.PDNAT_TABLE }).buildInstruction(0));
654                 CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName).setSourceDpid(fipCfgdDpnId).setInstruction(customInstructions)
655                         .setIpAddress(externalIp + "/32").setServiceId(label).setInstruction(customInstructions).build();
656                 Future<RpcResult<Void>> future = fibRpcService.createFibEntry(input);
657                 ListenableFuture<RpcResult<Void>> listenableFuture = JdkFutureAdapters.listenInPoolThread(future);
658
659                 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<Void>>() {
660
661                     @Override
662                     public void onFailure(Throwable error) {
663                         LOG.error("NAT Service : DNAT -> Error in generate label or fib install process", error);
664                     }
665
666                     @Override
667                     public void onSuccess(RpcResult<Void> result) {
668                         if(result.isSuccessful()) {
669                             LOG.info("NAT Service : DNAT -> Successfully installed custom FIB routes for prefix {}", externalIp);
670                         } else {
671                             LOG.error("NAT Service : DNAT -> Error in rpc call to create custom Fib entries for prefix {} in DPN {}, {}", externalIp, fipCfgdDpnId, result.getErrors());
672                         }
673                     }
674                 });
675
676             }
677         }
678     }
679
680     private void hndlTepDelForSnatInEachRtr(RoutersList router, BigInteger dpnId, String tunnelType,
681                                               String srcTepIp, String destTepIp, String tunnelName){
682         /*SNAT :
683             1) Elect a new switch as the primary NAPT
684             2) Advertise the new routes to BGP for the newly elected TEP IP as the DPN IP
685             3) This will make sure old routes are withdrawn and new routes are advertised.
686          */
687
688         String routerName = router.getRouter();
689         LOG.debug("NAT Service : SNAT -> Trying to clear routes to the External fixed IP associated to the router" +
690                 " {}", routerName);
691
692         // Check if this is externalRouter else ignore
693         InstanceIdentifier<Routers> extRoutersId = NatUtil.buildRouterIdentifier(routerName);
694         Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType
695                 .CONFIGURATION, extRoutersId);
696         if (!routerData.isPresent()) {
697             LOG.debug("NAT Service : SNAT -> Ignoring TEP del for router {} since its not External Router",
698                     routerName);
699             return;
700         }
701
702         //Check if the router ID is valid
703         long routerId = NatUtil.getVpnId(dataBroker, routerName);
704         if (routerId == NatConstants.INVALID_ID) {
705             LOG.error("NAT Service : SNAT -> Invalid ROUTER-ID {} returned for routerName {}", routerId, routerName);
706             return;
707         }
708
709         //Check if the DPN having the router is the NAPT switch
710         BigInteger naptId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
711         if (naptId == null || naptId.equals(BigInteger.ZERO) || (!naptId.equals(dpnId))) {
712             LOG.warn("NAT Service : SNAT -> Ignoring TEP delete for the DPN {} since" +
713                     " its NOT a NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and" +
714                     "TUNNEL NAME {} ", dpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
715             return;
716         }
717
718         Uuid networkId = routerData.get().getNetworkId();
719         if(networkId == null) {
720             LOG.debug("NAT Service : SNAT -> Ignoring TEP delete for the DPN {} having the router {} " +
721                     "since the Router instance {} not found in ExtRouters model b/w SRC IP {} and DST IP {} " +
722                     "and TUNNEL NAME {} ", dpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
723             return;
724         }
725
726         LOG.debug("NAT Service : SNAT -> Router {} is associated with ext nw {}", routerId, networkId);
727         Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerName);
728         Long vpnId;
729         if (vpnName == null) {
730             LOG.debug("NAT Service : SNAT -> Internal VPN-ID {} associated to router {}", routerId, routerName);
731             vpnId = routerId;
732
733             //Install default entry in FIB to SNAT table
734             LOG.debug("NAT Service : Installing default route in FIB on DPN {} for router {} with" +
735                     " vpn {}...", dpnId,routerName,vpnId);
736             defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId);
737         } else {
738             vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
739             if (vpnId == NatConstants.INVALID_ID) {
740                 LOG.error("NAT Service : SNAT -> Invalid Private BGP VPN ID returned for routerName {}", routerName);
741                 return;
742             }
743             LOG.debug("NAT Service : SNAT -> External BGP VPN (Private BGP) {} associated to router {}", vpnId, routerName);
744             //Install default entry in FIB to SNAT table
745             LOG.debug("NAT Service : Installing default route in FIB on dpn {} for routerId {} " +
746                     "with vpnId {}...", dpnId, routerId, vpnId);
747             defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, routerId);
748         }
749
750         if (routerData.get().isEnableSnat()) {
751             LOG.info("NAT Service : SNAT enabled for router {}", routerId);
752
753             long routerVpnId = routerId;
754             long bgpVpnId = NatConstants.INVALID_ID;
755             Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
756             if (bgpVpnUuid != null) {
757                 bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
758             }
759             if (bgpVpnId != NatConstants.INVALID_ID){
760                 LOG.debug("NAT Service : SNAT -> Private BGP VPN ID (Internal BGP VPN ID) {} associated to the router {}", bgpVpnId, routerName);
761                 routerVpnId = bgpVpnId;
762             }else{
763                 LOG.debug("NAT Service : SNAT -> Internal L3 VPN ID (Router ID) {} associated to the router {}", routerVpnId, routerName);
764             }
765             //Re-elect the other available switch as the NAPT switch and program the NAT flows.
766             removeSNATFromDPN(dpnId, routerName ,routerVpnId, networkId);
767         } else {
768             LOG.info("NAT Service : SNAT is not enabled for router {} to handle addDPN event {}", routerId, dpnId);
769         }
770     }
771
772     private void hndlTepDelForDnatInEachRtr(RoutersList router, BigInteger tepDeletedDpnId){
773         //DNAT : Withdraw the routes from the BGP
774         String routerName = router.getRouter();
775         LOG.debug("NAT Service : DNAT -> Trying to clear routes to the Floating IP associated to the router {}",
776                 routerName);
777
778         InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerName);
779         Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType
780                 .CONFIGURATION, routerPortsId);
781         if(!optRouterPorts.isPresent()) {
782             LOG.debug("NAT Service : DNAT -> Could not read Router Ports data object with id: {} from DNAT " +
783                             "FloatingIpInfo",
784                     routerName);
785             return;
786         }
787         RouterPorts routerPorts = optRouterPorts.get();
788         List<Ports> interfaces = routerPorts.getPorts();
789         Uuid extNwId = routerPorts.getExternalNetworkId();
790         final String vpnName = NatUtil.getAssociatedVPN(dataBroker, extNwId, LOG);
791         if(vpnName == null) {
792             LOG.info("NAT Service : DNAT -> No External VPN associated with Ext N/W {} for Router {}",
793                     extNwId, routerName);
794             return;
795         }
796         String rd = NatUtil.getVpnRd(dataBroker, vpnName);
797         for(Ports port : interfaces) {
798             //Get the DPN on which this interface resides
799             String interfaceName = port.getPortName();
800             BigInteger fipCfgdDpnId = NatUtil.getDpnForInterface(interfaceService, interfaceName);
801             if(fipCfgdDpnId.equals(BigInteger.ZERO)) {
802                 LOG.info("NAT Service : DNAT -> Abort processing Floating ip configuration. No DPN for port : {}", interfaceName);
803                 continue;
804             }
805             if(!fipCfgdDpnId.equals(tepDeletedDpnId)) {
806                 LOG.info("NAT Service : DNAT -> TEP deleted DPN {} is not the DPN {} which has the floating IP configured for the port: {}",
807                         tepDeletedDpnId, fipCfgdDpnId, interfaceName);
808                 continue;
809             }
810             List<IpMapping> ipMapping = port.getIpMapping();
811             for(IpMapping ipMap : ipMapping) {
812                 String internalIp = ipMap.getInternalIp();
813                 String externalIp = ipMap.getExternalIp();
814                 LOG.debug("NAT Service : DNAT -> Withdrawing the FIB route to the floating IP {} configured for the port: {}",
815                         externalIp, interfaceName);
816                 NatUtil.removePrefixFromBGP(dataBroker, bgpManager, fibManager, rd, externalIp + "/32", LOG);
817                 long label = floatingIPListener.getOperationalIpMapping(routerName, interfaceName, internalIp);
818                 if(label == NatConstants.INVALID_ID){
819                     LOG.debug("NAT Service : DNAT -> Unable to remove the table 21 entry pushing the MPLS label to the tunnel since label is invalid" );
820                     return;
821                 }
822                 RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName).setSourceDpid(fipCfgdDpnId).setIpAddress(externalIp + "/32").setServiceId(label).build();
823                 Future<RpcResult<Void>> future = fibRpcService.removeFibEntry(input);
824                 ListenableFuture<RpcResult<Void>> listenableFuture = JdkFutureAdapters.listenInPoolThread(future);
825
826                 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<Void>>() {
827
828                     @Override
829                     public void onFailure(Throwable error) {
830                         LOG.error("NAT Service : DNAT -> Error in removing the table 21 entry pushing the MPLS label to the tunnel since label is invalid ", error);
831                     }
832
833                     @Override
834                     public void onSuccess(RpcResult<Void> result) {
835                         if(result.isSuccessful()) {
836                             LOG.info("NAT Service : DNAT -> Successfully removed the entry pushing the MPLS label to the tunnel");
837                         } else {
838                             LOG.error("NAT Service : DNAT -> Error in fib rpc call to remove the table 21 entry pushing the MPLS label to the tunnnel due to {}", result.getErrors());
839                         }
840                     }
841                 });
842
843             }
844         }
845     }
846 }