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