6e03e31361d7e70717a5fcafcb93c9c138753774
[netvirt.git] / vpnservice / natservice / natservice-impl / src / main / java / org / opendaylight / netvirt / natservice / internal / NaptSwitchHA.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 package org.opendaylight.netvirt.natservice.internal;
9
10 import com.google.common.base.Optional;
11 import com.google.common.collect.Sets;
12
13 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
14 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
15 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
16 import org.opendaylight.genius.mdsalutil.*;
17 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
18 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCase;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushVlanActionCase;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetFieldCase;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeGre;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceInputBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceOutput;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInputBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameOutput;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.*;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.RoutersKey;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.Networks;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.NetworksKey;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.IpMapping;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.IpMappingKey;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMapping;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMappingKey;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolType;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMap;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.ip.port.map.IpPortExternal;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitch;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.VpnRpcService;
57 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
58 import org.opendaylight.yangtools.yang.common.RpcResult;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
61
62 import java.math.BigInteger;
63 import java.util.ArrayList;
64 import java.util.List;
65 import java.util.Set;
66 import java.util.concurrent.ExecutionException;
67 import java.util.concurrent.Future;
68 import java.util.HashMap;
69
70 public class NaptSwitchHA {
71     private static final Logger LOG = LoggerFactory.getLogger(NaptSwitchHA.class);
72     private final DataBroker dataBroker;
73     private IMdsalApiManager mdsalManager;
74     private ItmRpcService itmManager;
75     private OdlInterfaceRpcService interfaceManager;
76     private IdManagerService idManager;
77     private NAPTSwitchSelector naptSwitchSelector;
78     private ExternalRoutersListener externalRouterListener;
79     private IBgpManager bgpManager;
80     private VpnRpcService vpnService;
81     private FibRpcService fibService;
82
83     private List<String> externalIpsCache;
84     private HashMap<String,Long> externalIpsLabel;
85     public NaptSwitchHA(DataBroker broker,NAPTSwitchSelector selector){
86         dataBroker = broker;
87         naptSwitchSelector = selector;
88     }
89
90     public void setItmManager(ItmRpcService itmManager) {
91         this.itmManager = itmManager;
92     }
93
94     public void setMdsalManager(IMdsalApiManager mdsalManager) {
95         this.mdsalManager = mdsalManager;
96     }
97
98     public void setInterfaceManager(OdlInterfaceRpcService interfaceManager) {
99         this.interfaceManager = interfaceManager;
100     }
101
102     public void setIdManager(IdManagerService idManager) {
103         this.idManager = idManager;
104     }
105
106     void setExternalRoutersListener(ExternalRoutersListener externalRoutersListener) {
107         this.externalRouterListener = externalRoutersListener;
108     }
109
110     public void setBgpManager(IBgpManager bgpManager) {
111         this.bgpManager = bgpManager;
112     }
113
114     public void setVpnService(VpnRpcService vpnService) {
115         this.vpnService = vpnService;
116     }
117
118     public void setFibService(FibRpcService fibService) {
119         this.fibService = fibService;
120     }
121
122     /* This method checks the switch that gone down is a NaptSwitch for a router.
123        If it is a NaptSwitch
124           1) selects new NAPT switch
125           2) installs nat flows in new NAPT switch
126           table 21(FIB)->26(PSNAT)->group(resubmit/napttunnel)->36(Terminating)->46(outbound)->47(resubmit)->21
127           3) modify the group and miss entry flow in other vSwitches pointing to newNaptSwitch
128           4) Remove nat flows in oldNaptSwitch
129      */
130     /*public void handleNaptSwitchDown(BigInteger dpnId){
131
132         LOG.debug("handleNaptSwitchDown method is called with dpnId {}",dpnId);
133         BigInteger naptSwitch;
134         try {
135             NaptSwitches naptSwitches = NatUtil.getNaptSwitch(dataBroker);
136             if (naptSwitches == null || naptSwitches.getRouterToNaptSwitch() == null || naptSwitches.getRouterToNaptSwitch().isEmpty()) {
137                 LOG.debug("NaptSwitchDown: NaptSwitch is not allocated for none of the routers");
138                 return;
139             }
140             for (RouterToNaptSwitch routerToNaptSwitch : naptSwitches.getRouterToNaptSwitch()) {
141                 String routerName = routerToNaptSwitch.getRouterName();
142                 naptSwitch = routerToNaptSwitch.getPrimarySwitchId();
143                 boolean naptStatus = isNaptSwitchDown(routerName,dpnId,naptSwitch);
144                 if (!naptStatus) {
145                     LOG.debug("NaptSwitchDown: Switch with DpnId {} is not naptSwitch for router {}",
146                             dpnId, routerName);
147                 } else {
148                     removeSnatFlowsInOldNaptSwitch(routerName,naptSwitch);
149                     return;
150                 }
151             }
152         } catch (Exception ex) {
153             LOG.error("Exception in handleNaptSwitchDown method {}",ex);
154         }
155     }*/
156
157     protected void removeSnatFlowsInOldNaptSwitch(String routerName, BigInteger naptSwitch,HashMap<String,Long> externalIpmap) {
158         externalIpsLabel = externalIpmap;
159         //remove SNAT flows in old NAPT SWITCH
160         Long routerId = NatUtil.getVpnId(dataBroker, routerName);
161         if (routerId == NatConstants.INVALID_ID) {
162             LOG.error("Invalid routerId returned for routerName {}",routerName);
163             return;
164         }
165
166         //Remove the Terminating Service table entry which forwards the packet to Outbound NAPT Table
167         String tsFlowRef = externalRouterListener.getFlowRefTs(naptSwitch, NatConstants.TERMINATING_SERVICE_TABLE, routerId);
168         FlowEntity tsNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NatConstants.TERMINATING_SERVICE_TABLE, tsFlowRef);
169
170         LOG.info("Remove the flow in table {} for the old napt switch with the DPN ID {} and router ID {}"
171                 ,NatConstants.TERMINATING_SERVICE_TABLE, naptSwitch, routerId);
172         mdsalManager.removeFlow(tsNatFlowEntity);
173
174         //Remove the Outbound flow entry which forwards the packet to Outbound NAPT Table
175         String outboundNatFlowRef = externalRouterListener.getFlowRefOutbound(naptSwitch, NatConstants.OUTBOUND_NAPT_TABLE, routerId);
176         FlowEntity outboundNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch,
177                 NatConstants.OUTBOUND_NAPT_TABLE, outboundNatFlowRef);
178         LOG.info("Remove the flow in table {} for the old napt switch with the DPN ID {} and router ID {}"
179                 ,NatConstants.OUTBOUND_NAPT_TABLE, naptSwitch, routerId);
180         mdsalManager.removeFlow(outboundNatFlowEntity);
181
182         //Remove the NAPT_PFIB_TABLE(47) flow entry forwards the packet to Fib Table for inbound traffic matching on the router ID.
183         String naptPFibflowRef = externalRouterListener.getFlowRefTs(naptSwitch, NatConstants.NAPT_PFIB_TABLE, routerId);
184         FlowEntity naptPFibFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NatConstants.NAPT_PFIB_TABLE,naptPFibflowRef);
185         LOG.info("Remove the flow in table {} for the old napt switch with the DPN ID {} and router ID {}",
186                 NatConstants.NAPT_PFIB_TABLE, naptSwitch, routerId);
187         mdsalManager.removeFlow(naptPFibFlowEntity);
188
189         //Remove the NAPT_PFIB_TABLE(47) flow entry forwards the packet to Fib Table for outbound traffic matching on the vpn ID.
190         boolean switchSharedByRouters = false;
191         Uuid extNetworkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
192         if (extNetworkId != null) {
193             List<String> routerNamesAssociated = getRouterIdsForExtNetwork(extNetworkId);
194             if (routerNamesAssociated != null) {
195                 for (String routerNameAssociated : routerNamesAssociated) {
196                     if (!routerNameAssociated.equals(routerName)) {
197                         Long routerIdAssociated = NatUtil.getVpnId(dataBroker,routerNameAssociated);
198                         BigInteger naptDpn = NatUtil.getPrimaryNaptfromRouterId(dataBroker,routerIdAssociated);
199                         if (naptDpn != null && naptDpn.equals(naptSwitch)) {
200                             LOG.debug("Napt switch {} is also acting as primary for router {}",routerIdAssociated);
201                             switchSharedByRouters = true;
202                             break;
203                         }
204                     }
205                 }
206                 if (!switchSharedByRouters) {
207                     Long vpnId = getVpnIdForRouter(routerId);
208                     if (vpnId != NatConstants.INVALID_ID) {
209                         String naptFibflowRef = externalRouterListener.getFlowRefTs(naptSwitch, NatConstants.NAPT_PFIB_TABLE, vpnId);
210                         FlowEntity naptFibFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NatConstants.NAPT_PFIB_TABLE,naptFibflowRef);
211                         LOG.info("Remove the flow in table {} for the old napt switch with the DPN ID {} and vpnId {}",
212                                 NatConstants.NAPT_PFIB_TABLE, naptSwitch, vpnId);
213                         mdsalManager.removeFlow(naptFibFlowEntity);
214                     } else {
215                         LOG.error("Invalid vpnId retrieved for routerId {}",routerId);
216                         return;
217                     }
218                 }
219             }
220         }
221
222         //Remove Fib entries,tables 20->44 ,36-> 44
223         String vpnName = getExtNetworkVpnName(routerId);
224         if (vpnName == null) {
225             LOG.debug("Vpn is not associated to externalN/w of router {}",routerName);
226         } else {
227             if (externalIpsLabel != null) {
228                 for (String externalIp : externalIpsLabel.keySet()) {
229                     Long label = externalIpsLabel.get(externalIp);
230                     externalRouterListener.delFibTsAndReverseTraffic(naptSwitch, routerId, externalIp, vpnName,label);
231                     LOG.debug("Successfully removed fib entries in old naptswitch {} for router {} and externalIps {} label {}",
232                             naptSwitch, routerId,externalIp,label);
233                 }
234             } else {
235                 List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker,routerId);
236                 if (externalIps != null) {
237                     Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
238                     if (networkId != null) {
239                         externalRouterListener.clearFibTsAndReverseTraffic(naptSwitch, routerId, networkId, externalIps, null);
240                         LOG.debug("Successfully removed fib entries in old naptswitch {} for router {} with networkId {} and externalIps {}",
241                                     naptSwitch,routerId,networkId,externalIps);
242                     } else {
243                         LOG.debug("External network not associated to router {}", routerId);
244                     }
245                 } else {
246                     LOG.debug("ExternalIps not found for router {}",routerName);
247                 }
248             }
249         }
250
251         //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
252         IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
253         if (ipPortMapping == null || ipPortMapping.getIntextIpProtocolType() == null || ipPortMapping.getIntextIpProtocolType().isEmpty()) {
254             LOG.debug("No Internal Ip Port mapping associated to router {}, no flows need to be removed in" +
255                     "oldNaptSwitch {}", routerId, naptSwitch);
256             return;
257         }
258         BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
259         List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
260         for(IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
261             if (intextIpProtocolType.getIpPortMap() == null || intextIpProtocolType.getIpPortMap().isEmpty()) {
262                 LOG.debug("No {} session associated to router {},no flows need to be removed in oldNaptSwitch {}",
263                         intextIpProtocolType.getProtocol(),routerId,naptSwitch);
264                 break;
265             }
266             List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
267             for(IpPortMap ipPortMap : ipPortMaps) {
268                 String ipPortInternal = ipPortMap.getIpPortInternal();
269                 String[] ipPortParts = ipPortInternal.split(":");
270                 if(ipPortParts.length != 2) {
271                     LOG.error("Unable to retrieve the Internal IP and port");
272                     continue;
273                 }
274                 String internalIp = ipPortParts[0];
275                 String internalPort = ipPortParts[1];
276
277                 //Build and remove flow in outbound NAPT table
278                 String switchFlowRef = NatUtil.getNaptFlowRef(naptSwitch, NatConstants.OUTBOUND_NAPT_TABLE, String.valueOf(routerId),
279                         internalIp, Integer.valueOf(internalPort));
280                 FlowEntity outboundNaptFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NatConstants.OUTBOUND_NAPT_TABLE,
281                         cookieSnatFlow, switchFlowRef);
282
283                 LOG.info("Remove the flow in table {} for old napt switch with the DPN ID {} and router ID {}",
284                         NatConstants.OUTBOUND_NAPT_TABLE,naptSwitch, routerId);
285                 mdsalManager.removeFlow(outboundNaptFlowEntity);
286
287                 IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
288                 if (ipPortExternal == null) {
289                     LOG.debug("External Ipport mapping not found for internalIp {} with port {} for router", internalIp,
290                             internalPort, routerId);
291                     continue;
292                 }
293                 String externalIp = ipPortExternal.getIpAddress();
294                 int externalPort = ipPortExternal.getPortNum();
295
296                 //Build and remove flow in  inbound NAPT table
297                 switchFlowRef = NatUtil.getNaptFlowRef(naptSwitch, NatConstants.INBOUND_NAPT_TABLE, String.valueOf(routerId),
298                         externalIp, externalPort);
299                 FlowEntity inboundNaptFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NatConstants.INBOUND_NAPT_TABLE,
300                         cookieSnatFlow, switchFlowRef);
301
302                 LOG.info("Remove the flow in table {} for old napt switch with the DPN ID {} and router ID {}",
303                         NatConstants.INBOUND_NAPT_TABLE,naptSwitch, routerId);
304                 mdsalManager.removeFlow(inboundNaptFlowEntity);
305             }
306         }
307
308     }
309
310     private List<String> getRouterIdsForExtNetwork(Uuid extNetworkId) {
311         List<String> routerUuidsAsString = new ArrayList<>();
312         InstanceIdentifier<Networks> extNetwork = InstanceIdentifier.builder(ExternalNetworks.class).child
313                 (Networks.class, new NetworksKey(extNetworkId)).build();
314         Optional<Networks> extNetworkData = NatUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, extNetwork);
315         if (extNetworkData.isPresent()) {
316             List<Uuid> routerUuids= extNetworkData.get().getRouterIds();
317             if (routerUuids != null){
318                 for(Uuid routerUuid : routerUuids){
319                     routerUuidsAsString.add(routerUuid.getValue());
320                 }
321             }
322         }
323         return routerUuidsAsString;
324     }
325
326     public boolean isNaptSwitchDown(String routerName, BigInteger dpnId , BigInteger naptSwitch,Long routerVpnId,List<String> externalIpCache) {
327         externalIpsCache = externalIpCache;
328         if (!naptSwitch.equals(dpnId)) {
329             LOG.debug("DpnId {} is not a naptSwitch {} for Router {}",dpnId, naptSwitch, routerName);
330             return false;
331         }
332         LOG.debug("NaptSwitch {} is down for Router {}", naptSwitch, routerName);
333         Long routerId = NatUtil.getVpnId(dataBroker, routerName);
334         if (routerId == NatConstants.INVALID_ID) {
335             LOG.error("Invalid routerId returned for routerName {}", routerName);
336             return true;
337         }
338         //elect a new NaptSwitch
339         naptSwitch = naptSwitchSelector.selectNewNAPTSwitch(routerName);
340         if (naptSwitch.equals(BigInteger.ZERO)) {
341             LOG.info("No napt switch is elected since all the switches for router {} are down",routerName);
342             boolean naptUpdatedStatus = updateNaptSwitch(routerName,naptSwitch);
343             if(!naptUpdatedStatus) {
344                 LOG.debug("Failed to update naptSwitch {} for router {} in ds", naptSwitch,routerName);
345             }
346             //clearBgpRoutes
347             if (externalIpsCache != null) {
348                 String vpnName = getExtNetworkVpnName(routerId);
349                 if (vpnName != null) {
350                     //List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
351                     //if (externalIps != null) {
352                     for (String externalIp : externalIpsCache) {
353                         externalRouterListener.clearBgpRoutes(externalIp, vpnName);
354                     }
355                 } else {
356                     LOG.debug("vpn is not associated to extn/w for router {}", routerName);
357                 }
358             } else {
359                 LOG.debug("No ExternalIps found for subnets under router {}, no bgp routes need to be cleared",routerName);
360             }
361             return true;
362         }
363         //checking elected switch health status
364         if (!getSwitchStatus(naptSwitch)) {
365             LOG.error("Newly elected Napt switch {} for router {} is down", naptSwitch, routerName);
366             return true;
367         }
368         LOG.debug("New NaptSwitch {} is up for Router {} and can proceed for flow installation",naptSwitch, routerName);
369         //update napt model for new napt switch
370         boolean naptUpdated = updateNaptSwitch(routerName, naptSwitch);
371         if (naptUpdated) {
372             //update group of ordinary switch point to naptSwitch tunnel port
373             updateNaptSwitchBucketStatus(routerName, naptSwitch);
374         } else {
375             LOG.error("Failed to update naptSwitch model for newNaptSwitch {} for router {}",naptSwitch, routerName);
376         }
377
378         //update table26 forward packets to table46(outbound napt table)
379         FlowEntity flowEntity = buildSnatFlowEntityForNaptSwitch(naptSwitch, routerName, routerVpnId, NatConstants.ADD_FLOW);
380         if (flowEntity == null) {
381             LOG.debug("Failed to populate flowentity for router {} in naptSwitch {}", routerName, naptSwitch);
382         } else {
383             LOG.debug("Successfully installed flow in naptSwitch {} for router {}", naptSwitch, routerName);
384             mdsalManager.installFlow(flowEntity);
385         }
386
387         installSnatFlows(routerName,routerId,naptSwitch,routerVpnId);
388
389         boolean flowInstalledStatus = handleNatFlowsInNewNaptSwitch(routerId, dpnId, naptSwitch,routerVpnId);
390         if (flowInstalledStatus) {
391             LOG.debug("Installed all active session flows in newNaptSwitch {} for routerName {}", naptSwitch, routerName);
392         } else {
393             LOG.error("Failed to install flows in newNaptSwitch {} for routerId {}", naptSwitch, routerId);
394         }
395
396         //remove group in new naptswitch, coz this switch acted previously as ordinary switch
397         long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
398         GroupEntity groupEntity = null;
399         try {
400             groupEntity = MDSALUtil.buildGroupEntity(naptSwitch, groupId, routerName,
401                     GroupTypes.GroupAll, null);
402             LOG.info("NAT Service : Removing NAPT Group in new naptSwitch {}", naptSwitch);
403             mdsalManager.removeGroup(groupEntity);
404         } catch (Exception ex) {
405             LOG.debug("NAT Service : Failed to remove group in new naptSwitch {} : {}",groupEntity,ex);
406         }
407         return true;
408     }
409
410     private String getExtNetworkVpnName(long routerId) {
411         Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
412         if(networkId == null) {
413             LOG.error("networkId is null for the router ID {}", routerId);
414         } else {
415             final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
416             if (vpnName != null) {
417                 LOG.debug("retrieved vpn name {} associated with ext nw {} in router {}",
418                         vpnName,networkId,routerId);
419                 return vpnName;
420             } else {
421                 LOG.error("No VPN associated with ext nw {} belonging to routerId {}",
422                         networkId, routerId);
423             }
424         }
425         return null;
426     }
427
428     public void updateNaptSwitchBucketStatus(String routerName, BigInteger naptSwitch) {
429         LOG.debug("updateNaptSwitchBucketStatus method is called");
430
431         List<BigInteger> dpnList = naptSwitchSelector.getDpnsForVpn(routerName);
432         //List<BigInteger> dpnList = getDpnListForRouter(routerName);
433         if (dpnList == null || dpnList.isEmpty()) {
434             LOG.debug("No switches found for router {}",routerName);
435             return;
436         }
437         for (BigInteger dpn : dpnList) {
438             if (!dpn.equals(naptSwitch)) {
439                 LOG.debug("Updating SNAT_TABLE missentry for DpnId {} which is not naptSwitch for router {}",dpn,routerName);
440                 List<BucketInfo> bucketInfoList = handleGroupInNeighborSwitches(dpn, routerName, naptSwitch);
441                 if (bucketInfoList == null) {
442                     LOG.debug("Failed to populate bucketInfo for orinaryswitch {} whose naptSwitch {} for router {} ",
443                             dpn,naptSwitch,routerName);
444                     return;
445                 }
446                 modifySnatGroupEntry(dpn, bucketInfoList, routerName);
447             }
448         }
449     }
450
451     private boolean handleNatFlowsInNewNaptSwitch(Long routerId,BigInteger oldNaptSwitch, BigInteger newNaptSwitch,Long routerVpnId) {
452         LOG.debug("Proceeding to install flows in newNaptSwitch {} for routerId {}", newNaptSwitch,routerId);
453         IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker,routerId);
454         if (ipPortMapping == null || ipPortMapping.getIntextIpProtocolType() == null || ipPortMapping.getIntextIpProtocolType().isEmpty()) {
455             LOG.debug("No Internal Ip Port mapping associated to router {}, no flows need to be installed in" +
456                     "newNaptSwitch {}", routerId, newNaptSwitch);
457             return true;
458         }
459         //getvpnId
460         Long vpnId = getVpnIdForRouter(routerId);
461         if (vpnId == NatConstants.INVALID_ID) {
462             LOG.error("Invalid vpnId for routerId {}",routerId);
463             return false;
464         }
465         Long bgpVpnId;
466         if(routerId.equals(routerVpnId)) {
467             bgpVpnId = NatConstants.INVALID_ID;
468         } else {
469             bgpVpnId = routerVpnId;
470         }
471         LOG.debug("retrieved bgpVpnId {} for router {}",bgpVpnId,routerId);
472         for (IntextIpProtocolType protocolType : ipPortMapping.getIntextIpProtocolType()) {
473             if (protocolType.getIpPortMap() == null || protocolType.getIpPortMap().isEmpty()) {
474                 LOG.debug("No {} session associated to router {}", protocolType.getProtocol(), routerId);
475                 return true;
476             }
477             for (IpPortMap intIpPortMap : protocolType.getIpPortMap()) {
478                 String internalIpAddress = intIpPortMap.getIpPortInternal().split(":")[0];
479                 String intportnum = intIpPortMap.getIpPortInternal().split(":")[1];
480
481                 //Get the external IP address and the port from the model
482                 NAPTEntryEvent.Protocol proto = protocolType.getProtocol().toString().equals(ProtocolTypes.TCP.toString())
483                         ? NAPTEntryEvent.Protocol.TCP : NAPTEntryEvent.Protocol.UDP;
484                 IpPortExternal ipPortExternal = NatUtil.getExternalIpPortMap(dataBroker, routerId,
485                         internalIpAddress, intportnum, proto);
486                 if (ipPortExternal == null) {
487                     LOG.debug("External Ipport mapping is not found for internalIp {} with port {}", internalIpAddress, intportnum);
488                     continue;
489                 }
490                 String externalIpAddress = ipPortExternal.getIpAddress();
491                 Integer extportNumber = ipPortExternal.getPortNum();
492                 LOG.debug("ExternalIPport {}:{} mapping for internal ipport {}:{}",externalIpAddress,extportNumber,
493                         internalIpAddress,intportnum);
494
495                 SessionAddress sourceAddress = new SessionAddress(internalIpAddress,Integer.valueOf(intportnum));
496                 SessionAddress externalAddress = new SessionAddress(externalIpAddress,extportNumber);
497
498                 //checking naptSwitch status before installing flows
499                 if(getSwitchStatus(newNaptSwitch)) {
500                     //Install the flow in newNaptSwitch Outbound NAPT table.
501                     try {
502                         NaptEventHandler.buildAndInstallNatFlows(newNaptSwitch, NatConstants.OUTBOUND_NAPT_TABLE,
503                                 vpnId,  routerId, bgpVpnId, sourceAddress, externalAddress, proto);
504                     } catch (Exception ex) {
505                         LOG.error("Failed to add flow in OUTBOUND_NAPT_TABLE for routerid {} dpnId {} ipport {}:{} proto {}" +
506                                 "extIpport {}:{} BgpVpnId {} - {}", routerId, newNaptSwitch, internalIpAddress
507                                 , intportnum, proto, externalAddress, extportNumber,bgpVpnId,ex);
508                         return false;
509                     }
510                     LOG.debug("Successfully installed a flow in SecondarySwitch {} Outbound NAPT table for router {} " +
511                             "ipport {}:{} proto {} extIpport {}:{} BgpVpnId {}", newNaptSwitch,routerId, internalIpAddress
512                             , intportnum, proto, externalAddress, extportNumber,bgpVpnId);
513                     //Install the flow in newNaptSwitch Inbound NAPT table.
514                     try {
515                         NaptEventHandler.buildAndInstallNatFlows(newNaptSwitch, NatConstants.INBOUND_NAPT_TABLE,
516                                 vpnId, routerId, bgpVpnId, externalAddress, sourceAddress, proto);
517                     } catch (Exception ex) {
518                         LOG.error("Failed to add flow in INBOUND_NAPT_TABLE for routerid {} dpnId {} extIpport{}:{} proto {} " +
519                                         "ipport {}:{} BgpVpnId {}", routerId, newNaptSwitch, externalAddress, extportNumber, proto,
520                                 internalIpAddress, intportnum,bgpVpnId);
521                         return false;
522                     }
523                     LOG.debug("Successfully installed a flow in SecondarySwitch {} Inbound NAPT table for router {} " +
524                             "ipport {}:{} proto {} extIpport {}:{} BgpVpnId {}", newNaptSwitch,routerId, internalIpAddress
525                             , intportnum, proto, externalAddress, extportNumber,bgpVpnId);
526
527                 } else {
528                     LOG.error("NewNaptSwitch {} gone down while installing flows from oldNaptswitch {}",
529                             newNaptSwitch,oldNaptSwitch);
530                     return false;
531                 }
532             }
533         }
534         return true;
535     }
536
537     private Long getVpnIdForRouter(Long routerId) {
538         try {
539             //getvpnId
540             Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
541             if (networkId == null) {
542                 LOG.debug("network is not associated to router {}", routerId);
543             } else {
544                 Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
545                 if (vpnUuid == null) {
546                     LOG.debug("vpn is not associated for network {} in router {}", networkId, routerId);
547                 } else {
548                     Long vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
549                     if (vpnId > 0) {
550                         LOG.debug("retrieved vpnId {} for router {}",vpnId,routerId);
551                         return vpnId;
552                     } else {
553                         LOG.debug("retrieved invalid vpn Id");
554                     }
555                 }
556             }
557         } catch (Exception ex){
558             LOG.debug("Exception while retrieving vpnId for router {} - {}", routerId, ex);
559         }
560         return NatConstants.INVALID_ID;
561     }
562
563     public boolean getSwitchStatus(BigInteger switchId){
564         NodeId nodeId = new NodeId("openflow:" + switchId);
565         LOG.debug("Querying switch with dpnId {} is up/down", nodeId);
566         InstanceIdentifier<Node> nodeInstanceId = InstanceIdentifier.builder(Nodes.class)
567                 .child(Node.class, new NodeKey(nodeId)).build();
568         Optional<Node> nodeOptional = NatUtil.read(dataBroker,LogicalDatastoreType.OPERATIONAL,nodeInstanceId);
569         if (nodeOptional.isPresent()) {
570             LOG.debug("Switch {} is up", nodeId);
571             return true;
572         }
573         LOG.debug("Switch {} is down", nodeId);
574         return false;
575     }
576
577     public List<BucketInfo> handleGroupInPrimarySwitch() {
578         List<BucketInfo> listBucketInfo = new ArrayList<>();
579         List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
580         listActionInfoPrimary.add(new ActionInfo(ActionType.nx_resubmit,
581                 new String[]{String.valueOf(NatConstants.TERMINATING_SERVICE_TABLE)}));
582         BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
583         listBucketInfo.add(bucketPrimary);
584         return listBucketInfo;
585     }
586
587     public List<BucketInfo> handleGroupInNeighborSwitches(BigInteger dpnId, String routerName, BigInteger naptSwitch) {
588         List<BucketInfo> listBucketInfo = new ArrayList<>();
589         String ifNamePrimary;
590         Long routerId = NatUtil.getVpnId(dataBroker, routerName);
591         if (routerId == NatConstants.INVALID_ID) {
592             LOG.error("Invalid routerId returned for routerName {}",routerName);
593             return listBucketInfo;
594         }
595         ifNamePrimary = getTunnelInterfaceName(dpnId, naptSwitch);
596         if (ifNamePrimary != null) {
597             LOG.debug("TunnelInterface {} between ordinary switch {} and naptSwitch {}",ifNamePrimary,dpnId,naptSwitch);
598             List<ActionInfo> listActionInfoPrimary = getEgressActionsForInterface(ifNamePrimary, routerId);
599             BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
600             listBucketInfo.add(bucketPrimary);
601         } else {
602             LOG.debug("No TunnelInterface between ordinary switch {} and naptSwitch {}",dpnId,naptSwitch);
603         }
604         return listBucketInfo;
605     }
606
607     protected void installSnatGroupEntry(BigInteger dpnId, List<BucketInfo> bucketInfo, String routerName) {
608         GroupEntity groupEntity = null;
609         try {
610             long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
611             LOG.debug("install SnatMissEntry for groupId {} for dpnId {} for router {}", groupId, dpnId,routerName);
612             groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
613                     GroupTypes.GroupAll, bucketInfo);
614             mdsalManager.installGroup(groupEntity);
615             LOG.debug("installed the SNAT to NAPT GroupEntity:{}", groupEntity);
616         } catch (Exception ex) {
617             LOG.error("Failed to install group for groupEntity {} : {}",groupEntity,ex);
618         }
619     }
620
621     private void modifySnatGroupEntry(BigInteger dpnId, List<BucketInfo> bucketInfo, String routerName) {
622         installSnatGroupEntry(dpnId,bucketInfo,routerName);
623         LOG.debug("modified SnatMissEntry for dpnId {} of router {}",dpnId,routerName);
624     }
625
626     protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
627         Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
628         RpcResult<GetTunnelInterfaceNameOutput> rpcResult;
629
630         try {
631             Future<RpcResult<GetTunnelInterfaceNameOutput>> result = itmManager.getTunnelInterfaceName(
632                     new GetTunnelInterfaceNameInputBuilder().setSourceDpid(srcDpId).setDestinationDpid(dstDpId)
633                             .setTunnelType(tunType).build());
634             rpcResult = result.get();
635             if(!rpcResult.isSuccessful()) {
636                 tunType = TunnelTypeGre.class;
637                 result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
638                         .setSourceDpid(srcDpId)
639                         .setDestinationDpid(dstDpId)
640                         .setTunnelType(tunType)
641                         .build());
642                 rpcResult = result.get();
643                 if(!rpcResult.isSuccessful()) {
644                     LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
645                 } else {
646                     return rpcResult.getResult().getInterfaceName();
647                 }
648                 LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
649             } else {
650                 return rpcResult.getResult().getInterfaceName();
651             }
652         } catch (InterruptedException | ExecutionException e) {
653             LOG.warn("Exception when getting tunnel interface Id for tunnel between {} and  {} : {}",
654                     srcDpId, dstDpId, e);
655         }
656
657         return null;
658     }
659
660     protected List<ActionInfo> getEgressActionsForInterface(String ifName, long routerId) {
661         LOG.debug("getEgressActionsForInterface called for interface {}", ifName);
662         List<ActionInfo> listActionInfo = new ArrayList<>();
663         try {
664             Future<RpcResult<GetEgressActionsForInterfaceOutput>> result =
665                     interfaceManager.getEgressActionsForInterface(
666                             new GetEgressActionsForInterfaceInputBuilder().setIntfName(ifName).setTunnelKey(routerId).build());
667             RpcResult<GetEgressActionsForInterfaceOutput> rpcResult = result.get();
668             if(!rpcResult.isSuccessful()) {
669                 LOG.warn("RPC Call to Get egress actions for interface {} returned with Errors {}"
670                         , ifName, rpcResult.getErrors());
671             } else {
672                 List<Action> actions =
673                         rpcResult.getResult().getAction();
674                 for (Action action : actions) {
675                     org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action actionClass = action.getAction();
676                     if (actionClass instanceof OutputActionCase) {
677                         listActionInfo.add(new ActionInfo(ActionType.output,
678                                 new String[] {((OutputActionCase)actionClass).getOutputAction()
679                                         .getOutputNodeConnector().getValue()}));
680                     } else if (actionClass instanceof PushVlanActionCase) {
681                         listActionInfo.add(new ActionInfo(ActionType.push_vlan, new String[] {}));
682                     } else if (actionClass instanceof SetFieldCase) {
683                         if (((SetFieldCase)actionClass).getSetField().getVlanMatch() != null) {
684                             int vlanVid = ((SetFieldCase)actionClass).getSetField().getVlanMatch()
685                                     .getVlanId().getVlanId().getValue();
686                             listActionInfo.add(new ActionInfo(ActionType.set_field_vlan_vid,
687                                     new String[] { Long.toString(vlanVid) }));
688                         }
689                     }
690                 }
691             }
692         } catch (InterruptedException | ExecutionException e) {
693             LOG.warn("Exception when egress actions for interface {}", ifName, e);
694         }
695         return listActionInfo;
696     }
697
698     public boolean updateNaptSwitch(String routerName, BigInteger naptSwitchId) {
699         RouterToNaptSwitch naptSwitch = new RouterToNaptSwitchBuilder().setKey(new RouterToNaptSwitchKey(routerName))
700                 .setPrimarySwitchId(naptSwitchId).build();
701         try {
702             MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
703                     NatUtil.buildNaptSwitchRouterIdentifier(routerName), naptSwitch);
704         } catch (Exception ex) {
705             LOG.error("Failed to write naptSwitch {} for router {} in ds",
706                     naptSwitchId,routerName);
707             return false;
708         }
709         LOG.debug("Successfully updated naptSwitch {} for router {} in ds",
710                 naptSwitchId,routerName);
711         return true;
712     }
713
714     public FlowEntity buildSnatFlowEntity(BigInteger dpId, String routerName, long groupId, long routerVpnId, int addordel) {
715
716         FlowEntity flowEntity;
717         List<MatchInfo> matches = new ArrayList<MatchInfo>();
718         matches.add(new MatchInfo(MatchFieldType.eth_type,
719                 new long[]{ 0x0800L }));
720         matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
721                 BigInteger.valueOf(routerVpnId), MetaDataUtil.METADATA_MASK_VRFID }));
722
723         String flowRef = getFlowRefSnat(dpId, NatConstants.PSNAT_TABLE, routerName);
724
725         if (addordel == NatConstants.ADD_FLOW) {
726             List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
727             List<ActionInfo> actionsInfo = new ArrayList<ActionInfo>();
728
729             ActionInfo actionSetField = new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {
730                     BigInteger.valueOf(routerVpnId)}) ;
731             actionsInfo.add(actionSetField);
732             LOG.debug("Setting the tunnel to the list of action infos {}", actionsInfo);
733             actionsInfo.add(new ActionInfo(ActionType.group, new String[] {String.valueOf(groupId)}));
734             instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfo));
735
736             flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PSNAT_TABLE, flowRef,
737                     NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
738                     NatConstants.COOKIE_SNAT_TABLE, matches, instructions);
739         } else {
740             flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PSNAT_TABLE, flowRef,
741                     NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
742                     NatConstants.COOKIE_SNAT_TABLE, matches, null);
743         }
744         return flowEntity;
745     }
746
747     public FlowEntity buildSnatFlowEntityForNaptSwitch(BigInteger dpId, String routerName, long routerVpnId, int addordel) {
748
749         FlowEntity flowEntity;
750         List<MatchInfo> matches = new ArrayList<>();
751         matches.add(new MatchInfo(MatchFieldType.eth_type,
752                 new long[]{ 0x0800L }));
753         matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
754                 BigInteger.valueOf(routerVpnId), MetaDataUtil.METADATA_MASK_VRFID }));
755
756         String flowRef = getFlowRefSnat(dpId, NatConstants.PSNAT_TABLE, routerName);
757
758         if (addordel == NatConstants.ADD_FLOW) {
759             List<InstructionInfo> instructions = new ArrayList<>();
760
761             instructions.add(new InstructionInfo(InstructionType.goto_table, new long[]
762                     { NatConstants.OUTBOUND_NAPT_TABLE }));
763
764             flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PSNAT_TABLE, flowRef,
765                     NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
766                     NatConstants.COOKIE_SNAT_TABLE, matches, instructions);
767         } else {
768             flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PSNAT_TABLE, flowRef,
769                     NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
770                     NatConstants.COOKIE_SNAT_TABLE, matches, null);
771         }
772         return flowEntity;
773     }
774
775     private String getFlowRefSnat(BigInteger dpnId, short tableId, String routerID) {
776         return new StringBuilder().append(NatConstants.SNAT_FLOWID_PREFIX).append(dpnId).append(NatConstants.FLOWID_SEPARATOR).
777                 append(tableId).append(NatConstants.FLOWID_SEPARATOR).append(routerID).toString();
778     }
779
780     protected void installSnatFlows(String routerName,Long routerId,BigInteger naptSwitch,Long routerVpnId) {
781
782         if(routerId.equals(routerVpnId)) {
783             LOG.debug("Installing flows for router with internalvpnId");
784             //36 -> 46 ..Install flow forwarding packet to table46 from table36
785             LOG.debug("installTerminatingServiceTblEntry in naptswitch with dpnId {} for routerName {} with routerId {}",
786                     naptSwitch, routerName,routerId);
787             externalRouterListener.installTerminatingServiceTblEntry(naptSwitch, routerName);
788
789             //Install default flows punting to controller in table 46(OutBoundNapt table)
790             LOG.debug("installOutboundMissEntry in naptswitch with dpnId {} for routerName {} with routerId {}",
791                     naptSwitch, routerName, routerId);
792             externalRouterListener.createOutboundTblEntry(naptSwitch, routerId);
793
794             //Table 47 point to table 21 for inbound traffic
795             LOG.debug("installNaptPfibEntry in naptswitch with dpnId {} for router {}", naptSwitch, routerId);
796             externalRouterListener.installNaptPfibEntry(naptSwitch, routerId);
797         } else {
798             //36 -> 46 ..Install flow forwarding packet to table46 from table36
799             LOG.debug("installTerminatingServiceTblEntry in naptswitch with dpnId {} for routerName {} with BgpVpnId {}",
800                     naptSwitch, routerName, routerVpnId);
801             externalRouterListener.installTerminatingServiceTblEntryWithUpdatedVpnId(naptSwitch, routerName, routerVpnId);
802
803             //Install default flows punting to controller in table 46(OutBoundNapt table)
804             LOG.debug("installOutboundMissEntry in naptswitch with dpnId {} for routerName {} with BgpVpnId {}",
805                     naptSwitch, routerName, routerVpnId);
806             externalRouterListener.createOutboundTblEntryWithBgpVpn(naptSwitch, routerId, routerVpnId);
807
808             //Table 47 point to table 21 for inbound traffic
809             LOG.debug("installNaptPfibEntry in naptswitch with dpnId {} for router {} with BgpVpnId {}",
810                     naptSwitch, routerId, routerVpnId);
811             externalRouterListener.installNaptPfibEntryWithBgpVpn(naptSwitch, routerId, routerVpnId);
812         }
813
814         String vpnName = getExtNetworkVpnName(routerId);
815         if(vpnName != null) {
816             //Table 47 point to table 21 for outbound traffic
817             long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
818             if(vpnId > 0) {
819                 LOG.debug("installNaptPfibEntry fin naptswitch with dpnId {} for BgpVpnId {}", naptSwitch, vpnId);
820                 externalRouterListener.installNaptPfibEntry(naptSwitch, vpnId);
821             } else {
822                 LOG.debug("Associated BgpvpnId not found for router {}",routerId);
823             }
824
825             //Install Fib entries for ExternalIps & program 36 -> 44
826             List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker,routerId);
827             if (externalIps != null) {
828                 for (String externalIp : externalIps) {
829                     LOG.debug("advToBgpAndInstallFibAndTsFlows in naptswitch id {} with vpnName {} and externalIp {}",
830                             naptSwitch, vpnName, externalIp);
831                     externalRouterListener.advToBgpAndInstallFibAndTsFlows(naptSwitch, NatConstants.INBOUND_NAPT_TABLE,
832                             vpnName, routerId, externalIp, vpnService, fibService, bgpManager, dataBroker, LOG);
833                     LOG.debug("Successfully added fib entries in naptswitch {} for router {} with external IP {}", naptSwitch,
834                             routerId, externalIp);
835                 }
836             } else {
837                 LOG.debug("External Ip not found for routerId {}",routerId);
838             }
839         } else {
840             LOG.debug("Associated vpnName not found for router {}",routerId);
841         }
842     }
843
844     protected void bestEffortDeletion(long routerId,String routerName,HashMap<String,Long> externalIpLabel) {
845         List<String> newExternalIps = NatUtil.getExternalIpsForRouter(dataBroker,routerId);
846         if (newExternalIps != null && externalIpsCache != null) {
847             Set<String> originalSubnetIds = Sets.newHashSet(externalIpsCache);
848             Set<String> updatedSubnetIds = Sets.newHashSet(newExternalIps);
849             Sets.SetView<String> removeExternalIp = Sets.difference(originalSubnetIds, updatedSubnetIds);
850             if (removeExternalIp.isEmpty()) {
851                 LOG.debug("No external Ip needed to be removed in bestEffortDeletion method for router {}",routerName);
852                 return;
853             }
854             String vpnName = getExtNetworkVpnName(routerId);
855             if (vpnName == null) {
856                 LOG.debug("Vpn is not associated to externalN/w of router {}",routerName);
857                 return;
858             }
859             if (externalIpLabel == null || externalIpLabel.size() == 0) {
860                 LOG.debug("ExternalIpLabel map is empty for router {}",routerName);
861                 return;
862             }
863             BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
864             if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
865                 LOG.debug("No naptSwitch is selected for router {}", routerName);
866                 return;
867             }
868             Long label;
869             for (String externalIp : removeExternalIp) {
870                 if (externalIpLabel.containsKey(externalIp)) {
871                     label = externalIpLabel.get(externalIp);
872                     LOG.debug("Label {} for ExternalIp {} for router {}",label,externalIp,routerName);
873                 } else {
874                     LOG.debug("Label for ExternalIp {} is not found for router {}",externalIp,routerName);
875                     continue;
876                 }
877                 externalRouterListener.clearBgpRoutes(externalIp, vpnName);
878                 externalRouterListener.delFibTsAndReverseTraffic(naptSwitch, routerId, externalIp, vpnName,label);
879                 LOG.debug("Successfully removed fib entries in switch {} for router {} and externalIps {}",
880                             naptSwitch, routerId, externalIp);
881             }
882         } else {
883             LOG.debug("No external IP found for router {}",routerId);
884         }
885     }
886 }