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