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