natservice dead code removal
[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.HashSet;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.Map.Entry;
18 import java.util.Set;
19 import java.util.concurrent.ExecutionException;
20 import java.util.concurrent.Future;
21 import javax.inject.Inject;
22 import javax.inject.Singleton;
23 import org.eclipse.jdt.annotation.NonNull;
24 import org.eclipse.jdt.annotation.Nullable;
25 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
26 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
27 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
28 import org.opendaylight.genius.infra.Datastore.Configuration;
29 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
30 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
31 import org.opendaylight.genius.mdsalutil.ActionInfo;
32 import org.opendaylight.genius.mdsalutil.BucketInfo;
33 import org.opendaylight.genius.mdsalutil.FlowEntity;
34 import org.opendaylight.genius.mdsalutil.GroupEntity;
35 import org.opendaylight.genius.mdsalutil.InstructionInfo;
36 import org.opendaylight.genius.mdsalutil.MDSALUtil;
37 import org.opendaylight.genius.mdsalutil.MatchInfo;
38 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
39 import org.opendaylight.genius.mdsalutil.NwConstants;
40 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
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.netvirt.fibmanager.rev150330.FibEntries;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig.NatMode;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalNetworks;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProtocolTypes;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.Networks;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.NetworksKey;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMapping;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolType;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMap;
76 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;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitch;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchBuilder;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
80 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
81 import org.opendaylight.yangtools.yang.common.RpcResult;
82 import org.slf4j.Logger;
83 import org.slf4j.LoggerFactory;
84
85 @Singleton
86 public class NaptSwitchHA {
87     private static final Logger LOG = LoggerFactory.getLogger(NaptSwitchHA.class);
88     private final DataBroker dataBroker;
89     private final IMdsalApiManager mdsalManager;
90     private final ItmRpcService itmManager;
91     private final OdlInterfaceRpcService odlInterfaceRpcService;
92     private final IdManagerService idManager;
93     private final NAPTSwitchSelector naptSwitchSelector;
94     private final ExternalRoutersListener externalRouterListener;
95     private final NaptEventHandler naptEventHandler;
96     private final IFibManager fibManager;
97     private final IElanService elanManager;
98     private final EvpnNaptSwitchHA evpnNaptSwitchHA;
99     private final SnatServiceManager natServiceManager;
100     private final NatMode natMode;
101     private final IInterfaceManager interfaceManager;
102     private final NatOverVxlanUtil natOverVxlanUtil;
103
104     private volatile Collection<String> externalIpsCache;
105
106     @Inject
107     public NaptSwitchHA(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
108                         final ExternalRoutersListener externalRouterListener,
109                         final ItmRpcService itmManager,
110                         final OdlInterfaceRpcService odlInterfaceRpcService,
111                         final IdManagerService idManager,
112                         final NAPTSwitchSelector naptSwitchSelector,
113                         final IFibManager fibManager,
114                         final EvpnNaptSwitchHA evpnNaptSwitchHA,
115                         final IElanService elanManager,
116                         final SnatServiceManager natServiceManager,
117                         final NatserviceConfig config,
118                         final NaptEventHandler naptEventHandler,
119                         final IInterfaceManager interfaceManager,
120                         final NatOverVxlanUtil natOverVxlanUtil) {
121         this.dataBroker = dataBroker;
122         this.mdsalManager = mdsalManager;
123         this.externalRouterListener = externalRouterListener;
124         this.itmManager = itmManager;
125         this.odlInterfaceRpcService = odlInterfaceRpcService;
126         this.idManager = idManager;
127         this.naptSwitchSelector = naptSwitchSelector;
128         this.naptEventHandler = naptEventHandler;
129         this.fibManager = fibManager;
130         this.evpnNaptSwitchHA = evpnNaptSwitchHA;
131         this.elanManager = elanManager;
132         this.natServiceManager = natServiceManager;
133         this.interfaceManager = interfaceManager;
134         if (config != null) {
135             this.natMode = config.getNatMode();
136         } else {
137             this.natMode = NatMode.Controller;
138         }
139         this.natOverVxlanUtil = natOverVxlanUtil;
140     }
141
142     protected void removeSnatFlowsInOldNaptSwitch(String routerName, Long routerId, BigInteger naptSwitch,
143                                                   @Nullable Map<String, Long> externalIpmap,
144                                                   TypedReadWriteTransaction<Configuration> confTx)
145             throws ExecutionException, InterruptedException {
146
147         //remove SNAT flows in old NAPT SWITCH
148         Uuid networkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
149         String vpnName = getExtNetworkVpnName(routerName, networkId);
150         if (vpnName == null) {
151             LOG.error("removeSnatFlowsInOldNaptSwitch : Vpn is not associated to externalN/w of router {}",
152                 routerName);
153             return;
154         }
155         ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, networkId);
156         if (extNwProvType == null) {
157             LOG.error("removeSnatFlowsInOldNaptSwitch : Unable to retrieve the External Network Provider Type "
158                 + "for Router {}", routerName);
159             return;
160         }
161         if (extNwProvType == ProviderTypes.VXLAN) {
162             evpnNaptSwitchHA.evpnRemoveSnatFlowsInOldNaptSwitch(routerName, routerId, vpnName, naptSwitch, confTx);
163         } else {
164             //Remove the Terminating Service table entry which forwards the packet to Outbound NAPT Table
165             long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, natOverVxlanUtil, elanManager,
166                     idManager, routerId, routerName);
167             String tsFlowRef = externalRouterListener.getFlowRefTs(naptSwitch, NwConstants.INTERNAL_TUNNEL_TABLE,
168                 tunnelId);
169             FlowEntity tsNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.INTERNAL_TUNNEL_TABLE,
170                 tsFlowRef);
171
172             LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for the old napt switch "
173                 + "with the DPN ID {} and router ID {}", NwConstants.INTERNAL_TUNNEL_TABLE, naptSwitch, routerId);
174             mdsalManager.removeFlow(confTx, tsNatFlowEntity);
175         }
176         if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
177             //Remove the flow table 25->44 If there is no FIP Match on table 25 (PDNAT_TABLE)
178             NatUtil.removePreDnatToSnatTableEntry(confTx, mdsalManager, naptSwitch);
179         }
180         //Remove the Outbound flow entry which forwards the packet to Outbound NAPT Table
181         LOG.info("Remove the flow in table {} for the old napt switch with the DPN ID {} and router ID {}",
182             NwConstants.OUTBOUND_NAPT_TABLE, naptSwitch, routerId);
183
184         String outboundTcpNatFlowRef = externalRouterListener.getFlowRefOutbound(naptSwitch,
185             NwConstants.OUTBOUND_NAPT_TABLE, routerId, NwConstants.IP_PROT_TCP);
186         FlowEntity outboundTcpNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch,
187             NwConstants.OUTBOUND_NAPT_TABLE, outboundTcpNatFlowRef);
188         mdsalManager.removeFlow(confTx, outboundTcpNatFlowEntity);
189
190         String outboundUdpNatFlowRef = externalRouterListener.getFlowRefOutbound(naptSwitch,
191             NwConstants.OUTBOUND_NAPT_TABLE, routerId, NwConstants.IP_PROT_UDP);
192         FlowEntity outboundUdpNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch,
193             NwConstants.OUTBOUND_NAPT_TABLE, outboundUdpNatFlowRef);
194         mdsalManager.removeFlow(confTx, outboundUdpNatFlowEntity);
195
196         String icmpDropFlowRef = externalRouterListener.getFlowRefOutbound(naptSwitch,
197             NwConstants.OUTBOUND_NAPT_TABLE, routerId, NwConstants.IP_PROT_ICMP);
198         FlowEntity icmpDropFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE,
199             icmpDropFlowRef);
200         mdsalManager.removeFlow(confTx, icmpDropFlowEntity);
201
202         //Remove the NAPT PFIB TABLE (47->21) which forwards the incoming packet to FIB Table matching on the
203         // External Subnet Vpn Id.
204         Collection<Uuid> externalSubnetIdsForRouter = NatUtil.getExternalSubnetIdsForRouter(dataBroker,
205             routerName);
206         for (Uuid externalSubnetId : externalSubnetIdsForRouter) {
207             long subnetVpnId = NatUtil.getVpnId(dataBroker, externalSubnetId.getValue());
208             if (subnetVpnId != -1 && !NatUtil.checkForRoutersWithSameExtSubnetAndNaptSwitch(
209                 dataBroker, externalSubnetId, routerName, naptSwitch)) {
210                 String natPfibSubnetFlowRef = externalRouterListener.getFlowRefTs(naptSwitch,
211                     NwConstants.NAPT_PFIB_TABLE, subnetVpnId);
212                 FlowEntity natPfibFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.NAPT_PFIB_TABLE,
213                     natPfibSubnetFlowRef);
214                 mdsalManager.removeFlow(confTx, natPfibFlowEntity);
215                 LOG.debug("removeSnatFlowsInOldNaptSwitch : Removed the flow in table {} with external subnet "
216                           + "Vpn Id {} as metadata on Napt Switch {}", NwConstants.NAPT_PFIB_TABLE,
217                     subnetVpnId, naptSwitch);
218             }
219         }
220
221         // Remove the NAPT_PFIB_TABLE(47) flow entry forwards the packet to Fib Table for inbound traffic
222         // matching on the router ID.
223         String naptPFibflowRef =
224             externalRouterListener.getFlowRefTs(naptSwitch, NwConstants.NAPT_PFIB_TABLE, routerId);
225         FlowEntity naptPFibFlowEntity =
226             NatUtil.buildFlowEntity(naptSwitch, NwConstants.NAPT_PFIB_TABLE, naptPFibflowRef);
227         LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for the old napt switch "
228             + "with the DPN ID {} and router ID {}", NwConstants.NAPT_PFIB_TABLE, naptSwitch, routerId);
229         mdsalManager.removeFlow(confTx, naptPFibFlowEntity);
230
231         // Remove the NAPT_PFIB_TABLE(47) flow entry forwards the packet to Fib Table for outbound traffic
232         // matching on the vpn ID.
233         boolean switchSharedByRouters = false;
234         Uuid extNetworkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
235         if (extNetworkId != null && !NatUtil.checkForRoutersWithSameExtNetAndNaptSwitch(
236             dataBroker, networkId, routerName, naptSwitch)) {
237             List<String> routerNamesAssociated = getRouterIdsForExtNetwork(extNetworkId);
238             for (String routerNameAssociated : routerNamesAssociated) {
239                 if (!routerNameAssociated.equals(routerName)) {
240                     Long routerIdAssociated = NatUtil.getVpnId(dataBroker, routerNameAssociated);
241                     BigInteger naptDpn = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerNameAssociated);
242                     if (naptDpn != null && naptDpn.equals(naptSwitch)) {
243                         LOG.debug("removeSnatFlowsInOldNaptSwitch : Napt switch {} is also acting as primary "
244                             + "for router {}", naptSwitch, routerIdAssociated);
245                         switchSharedByRouters = true;
246                         break;
247                     }
248                 }
249             }
250             if (!switchSharedByRouters) {
251                 Long vpnId = getVpnIdForRouter(routerId, extNetworkId);
252                 if (vpnId != NatConstants.INVALID_ID) {
253                     String naptFibflowRef =
254                         externalRouterListener.getFlowRefTs(naptSwitch, NwConstants.NAPT_PFIB_TABLE, vpnId);
255                     FlowEntity naptFibFlowEntity =
256                         NatUtil.buildFlowEntity(naptSwitch, NwConstants.NAPT_PFIB_TABLE, naptFibflowRef);
257                     LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for the old napt switch"
258                         + " with the DPN ID {} and vpnId {}", NwConstants.NAPT_PFIB_TABLE, naptSwitch, vpnId);
259                     mdsalManager.removeFlow(confTx, naptFibFlowEntity);
260                 } else {
261                     LOG.error("removeSnatFlowsInOldNaptSwitch : Invalid vpnId retrieved for routerId {}",
262                         routerId);
263                     return;
264                 }
265             }
266         }
267
268         //Remove Fib entries,tables 20->44 ,36-> 44
269         String gwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
270         if (externalIpmap != null && !externalIpmap.isEmpty()) {
271             for (Entry<String, Long> entry : externalIpmap.entrySet()) {
272                 String externalIp = entry.getKey();
273                 Long label = entry.getValue();
274                 externalRouterListener.delFibTsAndReverseTraffic(naptSwitch, routerName, routerId, externalIp, vpnName,
275                     extNetworkId, label, gwMacAddress, true, confTx);
276                 LOG.debug("removeSnatFlowsInOldNaptSwitch : Successfully removed fib entries in old naptswitch {} "
277                     + "for router {} and externalIps {} label {}", naptSwitch, routerId, externalIp, label);
278             }
279         } else {
280             List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerName);
281             if (networkId != null) {
282                 externalRouterListener.clearFibTsAndReverseTraffic(naptSwitch, routerId, networkId,
283                     externalIps, null, gwMacAddress, confTx);
284                 LOG.debug(
285                     "removeSnatFlowsInOldNaptSwitch : Successfully removed fib entries in old naptswitch {} for "
286                         + "router {} with networkId {} and externalIps {}", naptSwitch, routerId, networkId,
287                     externalIps);
288             } else {
289                 LOG.debug("removeSnatFlowsInOldNaptSwitch : External network not associated to router {}",
290                     routerId);
291             }
292             externalRouterListener.removeNaptFibExternalOutputFlows(routerId, naptSwitch, extNetworkId,
293                 externalIps, confTx);
294         }
295
296         //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
297         IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
298         if (ipPortMapping == null || ipPortMapping.getIntextIpProtocolType() == null
299             || ipPortMapping.getIntextIpProtocolType().isEmpty()) {
300             LOG.warn("removeSnatFlowsInOldNaptSwitch : No Internal Ip Port mapping associated to router {}, "
301                 + "no flows need to be removed in oldNaptSwitch {}", routerId, naptSwitch);
302             return;
303         }
304         BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
305         List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
306         for (IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
307             if (intextIpProtocolType.getIpPortMap() == null || intextIpProtocolType.getIpPortMap().isEmpty()) {
308                 LOG.debug("removeSnatFlowsInOldNaptSwitch : No {} session associated to router {},"
309                         + "no flows need to be removed in oldNaptSwitch {}",
310                     intextIpProtocolType.getProtocol(), routerId, naptSwitch);
311                 break;
312             }
313             List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
314             for (IpPortMap ipPortMap : ipPortMaps) {
315                 String ipPortInternal = ipPortMap.getIpPortInternal();
316                 String[] ipPortParts = ipPortInternal.split(":");
317                 if (ipPortParts.length != 2) {
318                     LOG.error("removeSnatFlowsInOldNaptSwitch : Unable to retrieve the Internal IP and port");
319                     continue;
320                 }
321                 String internalIp = ipPortParts[0];
322                 String internalPort = ipPortParts[1];
323
324                 //Build and remove flow in outbound NAPT table
325                 String switchFlowRef =
326                     NatUtil.getNaptFlowRef(naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE, String.valueOf(routerId),
327                         internalIp, Integer.parseInt(internalPort));
328                 FlowEntity outboundNaptFlowEntity =
329                     NatUtil.buildFlowEntity(naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE,
330                         cookieSnatFlow, switchFlowRef);
331
332                 LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for old napt switch "
333                     + "with the DPN ID {} and router ID {}", NwConstants.OUTBOUND_NAPT_TABLE, naptSwitch, routerId);
334                 mdsalManager.removeFlow(confTx, outboundNaptFlowEntity);
335
336                 IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
337                 if (ipPortExternal == null) {
338                     LOG.debug(
339                         "removeSnatFlowsInOldNaptSwitch : External Ipport mapping not found for internalIp {} "
340                             + "with port {} for router {}", internalIp, internalPort, routerId);
341                     continue;
342                 }
343                 String externalIp = ipPortExternal.getIpAddress();
344                 int externalPort = ipPortExternal.getPortNum();
345
346                 //Build and remove flow in  inbound NAPT table
347                 switchFlowRef =
348                     NatUtil.getNaptFlowRef(naptSwitch, NwConstants.INBOUND_NAPT_TABLE, String.valueOf(routerId),
349                         externalIp, externalPort);
350                 FlowEntity inboundNaptFlowEntity =
351                     NatUtil.buildFlowEntity(naptSwitch, NwConstants.INBOUND_NAPT_TABLE,
352                         cookieSnatFlow, switchFlowRef);
353
354                 LOG.info(
355                     "removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for old napt switch with the "
356                         + "DPN ID {} and router ID {}", NwConstants.INBOUND_NAPT_TABLE, naptSwitch, routerId);
357                 mdsalManager.removeFlow(confTx, inboundNaptFlowEntity);
358             }
359         }
360     }
361
362     @NonNull
363     private List<String> getRouterIdsForExtNetwork(Uuid extNetworkId) {
364         List<String> routerUuidsAsString = new ArrayList<>();
365         InstanceIdentifier<Networks> extNetwork = InstanceIdentifier.builder(ExternalNetworks.class)
366             .child(Networks.class, new NetworksKey(extNetworkId)).build();
367         Optional<Networks> extNetworkData =
368                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
369                         LogicalDatastoreType.CONFIGURATION, extNetwork);
370         if (extNetworkData.isPresent()) {
371             List<Uuid> routerUuids = extNetworkData.get().getRouterIds();
372             if (routerUuids != null) {
373                 for (Uuid routerUuid : routerUuids) {
374                     routerUuidsAsString.add(routerUuid.getValue());
375                 }
376             }
377         }
378         return routerUuidsAsString;
379     }
380
381     public boolean isNaptSwitchDown(String routerName, Long routerId, BigInteger dpnId, BigInteger naptSwitch,
382                                     Long routerVpnId, Collection<String> externalIpCache,
383                                     TypedReadWriteTransaction<Configuration> confTx)
384             throws ExecutionException, InterruptedException {
385         return isNaptSwitchDown(routerName, routerId, dpnId, naptSwitch, routerVpnId, externalIpCache, true,
386                 confTx);
387     }
388
389     // TODO Clean up the exception handling
390     @SuppressWarnings("checkstyle:IllegalCatch")
391     public boolean isNaptSwitchDown(String routerName, Long routerId, BigInteger dpnId, BigInteger naptSwitch,
392                                     Long routerVpnId, Collection<String> externalIpCache, boolean isClearBgpRts,
393                                     TypedReadWriteTransaction<Configuration> confTx)
394             throws ExecutionException, InterruptedException {
395         externalIpsCache = externalIpCache;
396         if (!naptSwitch.equals(dpnId)) {
397             LOG.debug("isNaptSwitchDown : DpnId {} is not a naptSwitch {} for Router {}",
398                     dpnId, naptSwitch, routerName);
399             return false;
400         }
401         LOG.debug("NaptSwitch {} is down for Router {}", naptSwitch, routerName);
402         if (routerId == NatConstants.INVALID_ID) {
403             LOG.error("isNaptSwitchDown : Invalid routerId returned for routerName {}", routerName);
404             return true;
405         }
406         Uuid networkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
407         String vpnName = getExtNetworkVpnName(routerName, networkId);
408         //elect a new NaptSwitch
409         naptSwitch = naptSwitchSelector.selectNewNAPTSwitch(routerName);
410         if (natMode == NatMode.Conntrack) {
411             Routers extRouters = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
412             natServiceManager.notify(confTx, extRouters, null, dpnId, dpnId,
413                     SnatServiceManager.Action.CNT_ROUTER_ALL_SWITCH_DISBL);
414             if (extRouters.isEnableSnat()) {
415                 natServiceManager.notify(confTx, extRouters, null, dpnId, dpnId,
416                         SnatServiceManager.Action.SNAT_ALL_SWITCH_DISBL);
417             }
418             natServiceManager.notify(confTx, extRouters, null, naptSwitch, naptSwitch,
419                     SnatServiceManager.Action.CNT_ROUTER_ALL_SWITCH_ENBL);
420             if (extRouters.isEnableSnat()) {
421                 natServiceManager.notify(confTx, extRouters, null, naptSwitch, naptSwitch,
422                         SnatServiceManager.Action.SNAT_ALL_SWITCH_ENBL);
423             }
424         } else {
425             if (naptSwitch.equals(BigInteger.ZERO)) {
426                 LOG.warn("isNaptSwitchDown : No napt switch is elected since all the switches for router {}"
427                         + " are down. SNAT IS NOT SUPPORTED FOR ROUTER {}", routerName, routerName);
428                 boolean naptUpdatedStatus = updateNaptSwitch(routerName, naptSwitch);
429                 if (!naptUpdatedStatus) {
430                     LOG.debug("isNaptSwitchDown : Failed to update naptSwitch {} for router {} in ds",
431                             naptSwitch, routerName);
432                 }
433                 //clearBgpRoutes
434                 if (externalIpsCache != null) {
435                     if (vpnName != null) {
436                         //List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
437                         //if (externalIps != null) {
438                         if (isClearBgpRts) {
439                             LOG.debug("isNaptSwitchDown : Clearing both FIB entries and the BGP routes");
440                             for (String externalIp : externalIpsCache) {
441                                 externalRouterListener.clearBgpRoutes(externalIp, vpnName);
442                             }
443                         } else {
444                             LOG.debug("isNaptSwitchDown : Clearing the FIB entries but not the BGP routes");
445                             String rd = NatUtil.getVpnRd(dataBroker, vpnName);
446                             for (String externalIp : externalIpsCache) {
447                                 LOG.debug("isNaptSwitchDown : Removing Fib entry rd {} prefix {}", rd, externalIp);
448                                 fibManager.removeFibEntry(rd, externalIp, null);
449                             }
450                         }
451                     } else {
452                         LOG.debug("isNaptSwitchDown : vpn is not associated to extn/w for router {}", routerName);
453                     }
454                 } else {
455                     LOG.debug("isNaptSwitchDown : No ExternalIps found for subnets under router {}, "
456                             + "no bgp routes need to be cleared", routerName);
457                 }
458                 return true;
459             }
460             //checking elected switch health status
461             if (!NatUtil.getSwitchStatus(dataBroker, naptSwitch)) {
462                 LOG.error("isNaptSwitchDown : Newly elected Napt switch {} for router {} is down",
463                         naptSwitch, routerName);
464                 return true;
465             }
466             LOG.debug("isNaptSwitchDown : New NaptSwitch {} is up for Router {} and can proceed for flow installation",
467                     naptSwitch, routerName);
468             //update napt model for new napt switch
469             boolean naptUpdated = updateNaptSwitch(routerName, naptSwitch);
470             if (naptUpdated) {
471                 //update group of ordinary switch point to naptSwitch tunnel port
472                 updateNaptSwitchBucketStatus(routerName, routerId, naptSwitch);
473             } else {
474                 LOG.error("isNaptSwitchDown : Failed to update naptSwitch model for newNaptSwitch {} for router {}",
475                         naptSwitch, routerName);
476             }
477
478             //update table26 forward packets to table46(outbound napt table)
479             FlowEntity flowEntity =
480                     buildSnatFlowEntityForNaptSwitch(naptSwitch, routerName, routerVpnId, NatConstants.ADD_FLOW);
481             if (flowEntity == null) {
482                 LOG.error("isNaptSwitchDown : Failed to populate flowentity for router {} in naptSwitch {}",
483                         routerName, naptSwitch);
484             } else {
485                 LOG.debug("isNaptSwitchDown : Successfully installed flow in naptSwitch {} for router {}",
486                         naptSwitch, routerName);
487                 mdsalManager.addFlow(confTx, flowEntity);
488             }
489
490             installSnatFlows(routerName, routerId, naptSwitch, routerVpnId, confTx);
491
492             boolean flowInstalledStatus = handleNatFlowsInNewNaptSwitch(routerName, routerId, dpnId, naptSwitch,
493                     routerVpnId, networkId);
494             if (flowInstalledStatus) {
495                 LOG.debug("isNaptSwitchDown :Installed all active session flows in newNaptSwitch {} for routerName {}",
496                         naptSwitch, routerName);
497             } else {
498                 LOG.error("isNaptSwitchDown : Failed to install flows in newNaptSwitch {} for routerId {}",
499                         naptSwitch, routerId);
500             }
501
502             //remove group in new naptswitch, coz this switch acted previously as ordinary switch
503             long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
504             try {
505                 LOG.info("isNaptSwitchDown : Removing NAPT Group in new naptSwitch {}", naptSwitch);
506                 mdsalManager.removeGroup(confTx, naptSwitch, groupId);
507             } catch (Exception ex) {
508                 LOG.error("isNaptSwitchDown : Failed to remove group in new naptSwitch {}", naptSwitch, ex);
509             }
510         }
511         return true;
512     }
513
514     @Nullable
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 (NatUtil.getSwitchStatus(dataBroker, 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     @NonNull
689     public List<BucketInfo> handleGroupInNeighborSwitches(BigInteger dpnId, String routerName, long routerId,
690             BigInteger naptSwitch) {
691         List<BucketInfo> listBucketInfo = new ArrayList<>();
692         String ifNamePrimary;
693         if (routerId == NatConstants.INVALID_ID) {
694             LOG.error("handleGroupInNeighborSwitches : Invalid routerId returned for routerName {}", routerName);
695             return listBucketInfo;
696         }
697         ifNamePrimary = getTunnelInterfaceName(dpnId, naptSwitch);
698         if (ifNamePrimary != null) {
699             LOG.debug("handleGroupInNeighborSwitches : TunnelInterface {} between ordinary switch {} and naptSwitch {}",
700                 ifNamePrimary, dpnId, naptSwitch);
701             List<ActionInfo> listActionInfoPrimary =
702                 NatUtil.getEgressActionsForInterface(odlInterfaceRpcService, itmManager, interfaceManager,
703                         ifNamePrimary, routerId, true);
704             BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
705             listBucketInfo.add(bucketPrimary);
706         } else {
707             LOG.debug("handleGroupInNeighborSwitches : No TunnelInterface between ordinary switch {} and naptSwitch {}",
708                     dpnId, naptSwitch);
709         }
710         return listBucketInfo;
711     }
712
713     // TODO Clean up the exception handling
714     @SuppressWarnings("checkstyle:IllegalCatch")
715     protected void installSnatGroupEntry(BigInteger dpnId, List<BucketInfo> bucketInfo, String routerName) {
716         GroupEntity groupEntity = null;
717         try {
718             long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
719             LOG.debug("installSnatGroupEntry : install SnatMissEntry for groupId {} for dpnId {} for router {}",
720                     groupId, dpnId, routerName);
721             groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
722                 GroupTypes.GroupAll, bucketInfo);
723             mdsalManager.syncInstallGroup(groupEntity);
724             LOG.debug("installSnatGroupEntry : installed the SNAT to NAPT GroupEntity:{}", groupEntity);
725         } catch (Exception ex) {
726             LOG.error("installSnatGroupEntry : Failed to install group for groupEntity {}", groupEntity, ex);
727         }
728     }
729
730     private void modifySnatGroupEntry(BigInteger dpnId, List<BucketInfo> bucketInfo, String routerName) {
731         installSnatGroupEntry(dpnId, bucketInfo, routerName);
732         LOG.debug("modifySnatGroupEntry : modified SnatMissEntry for dpnId {} of router {}", dpnId, routerName);
733     }
734
735     @Nullable
736     protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
737         Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
738         RpcResult<GetTunnelInterfaceNameOutput> rpcResult;
739
740         try {
741             Future<RpcResult<GetTunnelInterfaceNameOutput>> result = itmManager.getTunnelInterfaceName(
742                 new GetTunnelInterfaceNameInputBuilder().setSourceDpid(srcDpId).setDestinationDpid(dstDpId)
743                     .setTunnelType(tunType).build());
744             rpcResult = result.get();
745             if (!rpcResult.isSuccessful()) {
746                 tunType = TunnelTypeGre.class;
747                 result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
748                     .setSourceDpid(srcDpId)
749                     .setDestinationDpid(dstDpId)
750                     .setTunnelType(tunType)
751                     .build());
752                 rpcResult = result.get();
753                 if (!rpcResult.isSuccessful()) {
754                     LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
755                             rpcResult.getErrors());
756                 } else {
757                     return rpcResult.getResult().getInterfaceName();
758                 }
759                 LOG.warn("getTunnelInterfaceName : RPC Call to getTunnelInterfaceId returned with Errors {}",
760                         rpcResult.getErrors());
761             } else {
762                 return rpcResult.getResult().getInterfaceName();
763             }
764         } catch (InterruptedException | ExecutionException e) {
765             LOG.error("getTunnelInterfaceName :Exception when getting tunnel interface Id for tunnel between {} and {}",
766                 srcDpId, dstDpId, e);
767         }
768         LOG.error("getTunnelInterfaceName : Tunnel missing between dpn {}:{}", srcDpId, dstDpId);
769         return null;
770     }
771
772     // TODO Clean up the exception handling
773     @SuppressWarnings("checkstyle:IllegalCatch")
774     public boolean updateNaptSwitch(String routerName, BigInteger naptSwitchId) {
775         RouterToNaptSwitch naptSwitch = new RouterToNaptSwitchBuilder().withKey(new RouterToNaptSwitchKey(routerName))
776             .setPrimarySwitchId(naptSwitchId).build();
777         try {
778             MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
779                 NatUtil.buildNaptSwitchRouterIdentifier(routerName), naptSwitch);
780         } catch (Exception ex) {
781             LOG.error("updateNaptSwitch : Failed to write naptSwitch {} for router {} in ds",
782                 naptSwitchId, routerName);
783             return false;
784         }
785         LOG.debug("updateNaptSwitch : Successfully updated naptSwitch {} for router {} in ds",
786             naptSwitchId, routerName);
787         return true;
788     }
789
790     public FlowEntity buildSnatFlowEntity(BigInteger dpId, String routerName, long groupId,
791                                           long routerVpnId, int addordel) {
792         FlowEntity flowEntity;
793         List<MatchInfo> matches = new ArrayList<>();
794         matches.add(MatchEthernetType.IPV4);
795         matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerVpnId), MetaDataUtil.METADATA_MASK_VRFID));
796
797         String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
798
799         if (addordel == NatConstants.ADD_FLOW) {
800             List<ActionInfo> actionsInfo = new ArrayList<>();
801             long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, natOverVxlanUtil, elanManager,
802                     idManager, routerVpnId, routerName);
803             actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(tunnelId)));
804             LOG.debug("buildSnatFlowEntity : Setting the tunnel to the list of action infos {}", actionsInfo);
805             actionsInfo.add(new ActionGroup(groupId));
806             List<InstructionInfo> instructions = new ArrayList<>();
807             instructions.add(new InstructionApplyActions(actionsInfo));
808
809             flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
810                     NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
811                     NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
812         } else {
813             flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
814                 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
815                 NwConstants.COOKIE_SNAT_TABLE, matches, null);
816         }
817         return flowEntity;
818     }
819
820     public FlowEntity buildSnatFlowEntityForNaptSwitch(BigInteger dpId, String routerName,
821                                                        long routerVpnId, int addordel) {
822         FlowEntity flowEntity;
823         List<MatchInfo> matches = new ArrayList<>();
824         matches.add(MatchEthernetType.IPV4);
825         matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerVpnId), MetaDataUtil.METADATA_MASK_VRFID));
826
827         String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
828
829         if (addordel == NatConstants.ADD_FLOW) {
830             List<InstructionInfo> instructions = new ArrayList<>();
831
832             instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
833
834             flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
835                 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
836                 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
837         } else {
838             flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
839                 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
840                 NwConstants.COOKIE_SNAT_TABLE, matches, null);
841         }
842         return flowEntity;
843     }
844
845     private String getFlowRefSnat(BigInteger dpnId, short tableId, String routerID) {
846         return NatConstants.SNAT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
847                 .FLOWID_SEPARATOR + routerID;
848     }
849
850     protected void installSnatFlows(String routerName, Long routerId, BigInteger naptSwitch, Long routerVpnId,
851                                     TypedReadWriteTransaction<Configuration> confTx) {
852
853         if (routerId.equals(routerVpnId)) {
854             LOG.debug("installSnatFlows : Installing flows for router with internalvpnId");
855             //36 -> 46 ..Install flow forwarding packet to table46 from table36
856             LOG.debug("installSnatFlows : installTerminatingServiceTblEntry in naptswitch with dpnId {} for "
857                 + "routerName {} with routerId {}", naptSwitch, routerName, routerId);
858             externalRouterListener.installTerminatingServiceTblEntry(naptSwitch, routerName, routerId, confTx);
859
860             //Install default flows punting to controller in table 46(OutBoundNapt table)
861             LOG.debug("installSnatFlows : installOutboundMissEntry in naptswitch with dpnId {} for "
862                 + "routerName {} with routerId {}", naptSwitch, routerName, routerId);
863             externalRouterListener.createOutboundTblEntry(naptSwitch, routerId, confTx);
864
865             //Table 47 point to table 21 for inbound traffic
866             LOG.debug("installSnatFlows : installNaptPfibEntry in naptswitch with dpnId {} for router {}",
867                 naptSwitch, routerId);
868             externalRouterListener.installNaptPfibEntry(naptSwitch, routerId, confTx);
869
870             //Table 47 point to group
871             LOG.debug("installSnatFlows : installNaptPfibExternalOutputFlow in naptswitch with dpnId {} for router {}",
872                 naptSwitch, routerId);
873             externalRouterListener.installNaptPfibExternalOutputFlow(routerName, routerId, naptSwitch, confTx);
874         } else {
875             Uuid extNetworkUuid = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
876             if (extNetworkUuid == null) {
877                 LOG.error("onRouterAssociatedToVpn : Unable to retrieve external network Uuid for router {}",
878                         routerName);
879                 return;
880             }
881             ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName,
882                     extNetworkUuid);
883             if (extNwProvType == null) {
884                 LOG.error("onRouterAssociatedToVpn : External Network Provider Type missing");
885                 return;
886             }
887             //36 -> 46 ..Install flow forwarding packet to table46 from table36
888             LOG.debug("installSnatFlows : installTerminatingServiceTblEntry in naptswitch with dpnId {} for "
889                 + "routerName {} with BgpVpnId {}", naptSwitch, routerName, routerVpnId);
890             externalRouterListener
891                 .installTerminatingServiceTblEntryWithUpdatedVpnId(naptSwitch, routerName, routerId,
892                         routerVpnId, confTx, extNwProvType);
893
894             //Install default flows punting to controller in table 46(OutBoundNapt table)
895             LOG.debug("installSnatFlows : installOutboundMissEntry in naptswitch with dpnId {} for "
896                 + "routerName {} with BgpVpnId {}", naptSwitch, routerName, routerVpnId);
897             externalRouterListener.createOutboundTblEntryWithBgpVpn(naptSwitch, routerId, routerVpnId, confTx);
898
899             //Table 47 point to table 21 for inbound traffic
900             LOG.debug("installSnatFlows : installNaptPfibEntry in naptswitch with dpnId {} for router {} "
901                     + "with BgpVpnId {}", naptSwitch, routerId, routerVpnId);
902             externalRouterListener.installNaptPfibEntryWithBgpVpn(naptSwitch, routerId, routerVpnId, confTx);
903         }
904
905         Uuid networkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
906         String vpnName = getExtNetworkVpnName(routerName, networkId);
907         if (vpnName != null) {
908             //NAPT PFIB point to FIB table for outbound traffic
909             long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
910             boolean shouldInstallNaptPfibWithExtNetworkVpnId = true;
911             Collection<Uuid> externalSubnetIds = NatUtil.getExternalSubnetIdsForRouter(dataBroker, routerName);
912             if (!externalSubnetIds.isEmpty()) {
913                 //NAPT PFIB point to FIB table for outbound traffic - using external subnetID as vpnID.
914                 for (Uuid externalSubnetId : externalSubnetIds) {
915                     long externalSubnetVpnId = NatUtil.getExternalSubnetVpnId(dataBroker, externalSubnetId);
916                     if (externalSubnetVpnId != NatConstants.INVALID_ID) {
917                         shouldInstallNaptPfibWithExtNetworkVpnId = false;
918                         LOG.debug("installSnatFlows : installNaptPfibEntry fin naptswitch with dpnId {} for "
919                                 + "BgpVpnId {}", naptSwitch, externalSubnetVpnId);
920                         externalRouterListener.installNaptPfibEntry(naptSwitch, externalSubnetVpnId, confTx);
921                     }
922                 }
923             }
924             if (vpnId != NatConstants.INVALID_ID && shouldInstallNaptPfibWithExtNetworkVpnId) {
925                 //NAPT PFIB table point to FIB table for outbound traffic - using external networkID as vpnID.
926                 LOG.debug("installSnatFlows : installNaptPfibEntry fin naptswitch with dpnId {} for "
927                     + "BgpVpnId {}", naptSwitch, vpnId);
928                 externalRouterListener.installNaptPfibEntry(naptSwitch, vpnId, confTx);
929             } else if (vpnId != NatConstants.INVALID_ID) {
930                 LOG.debug("installSnatFlows : Associated BgpvpnId not found for router {}", routerId);
931             }
932
933             //Install Fib entries for ExternalIps & program 36 -> 44
934             Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
935             String rd = NatUtil.getVpnRd(dataBroker, vpnName);
936             for (String externalIp : externalIps) {
937                 removeFibEntry(rd, externalIp);
938                 LOG.debug("installSnatFlows : advToBgpAndInstallFibAndTsFlows in naptswitch id {} "
939                     + "with vpnName {} and externalIp {}", naptSwitch, vpnName, externalIp);
940                 externalRouterListener.advToBgpAndInstallFibAndTsFlows(naptSwitch, NwConstants.INBOUND_NAPT_TABLE,
941                     vpnName, routerId, routerName, externalIp, networkId, null /* external-router */, confTx);
942                 LOG.debug("installSnatFlows : Successfully added fib entries in naptswitch {} for "
943                     + "router {} with external IP {}", naptSwitch, routerId, externalIp);
944             }
945         } else {
946             LOG.debug("installSnatFlows : Associated vpnName not found for router {}", routerId);
947         }
948     }
949
950     protected void bestEffortDeletion(long routerId, String routerName, Map<String, Long> externalIpLabel,
951                                       TypedReadWriteTransaction<Configuration> confTx)
952             throws ExecutionException, InterruptedException {
953         Collection<String> newExternalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
954         if (externalIpsCache != null) {
955             Set<String> removedExternalIps = new HashSet<>(externalIpsCache);
956             removedExternalIps.removeAll(newExternalIps);
957             if (removedExternalIps.isEmpty()) {
958                 LOG.info("bestEffortDeletion : No external Ip needed to be removed in bestEffortDeletion "
959                         + "method for router {}", routerName);
960                 return;
961             }
962             Uuid networkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
963             String vpnName = getExtNetworkVpnName(routerName, networkId);
964             if (vpnName == null) {
965                 LOG.error("bestEffortDeletion : Vpn is not associated to externalN/w of router {}", routerName);
966                 return;
967             }
968             BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
969             if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
970                 LOG.error("bestEffortDeletion : No naptSwitch is selected for router {}", routerName);
971                 return;
972             }
973             ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,routerName, networkId);
974             if (extNwProvType == null) {
975                 return;
976             }
977             String gwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
978             if (gwMacAddress != null) {
979                 LOG.debug("bestEffortDeletion : External Gateway MAC address {} found for External Router ID {}",
980                         gwMacAddress, routerId);
981             } else {
982                 LOG.error("bestEffortDeletion : No External Gateway MAC address found for External Router ID {}",
983                         routerId);
984                 return;
985             }
986             if (extNwProvType == ProviderTypes.VXLAN) {
987                 for (String externalIp : removedExternalIps) {
988                     externalRouterListener.clearBgpRoutes(externalIp, vpnName);
989                     externalRouterListener.delFibTsAndReverseTraffic(naptSwitch, routerName, routerId, externalIp,
990                         vpnName, networkId, NatConstants.DEFAULT_LABEL_VALUE, gwMacAddress, true, confTx);
991                     LOG.debug("bestEffortDeletion : Successfully removed fib entry for externalIp {} for routerId {} "
992                                     + "on NAPT switch {} ", externalIp, routerId, naptSwitch);
993                 }
994             } else {
995                 if (externalIpLabel == null || externalIpLabel.isEmpty()) {
996                     LOG.error("bestEffortDeletion : ExternalIpLabel map is empty for router {}", routerName);
997                     return;
998                 }
999                 Long label;
1000                 for (String externalIp : removedExternalIps) {
1001                     if (externalIpLabel.containsKey(externalIp)) {
1002                         label = externalIpLabel.get(externalIp);
1003                         LOG.debug("bestEffortDeletion : Label {} for ExternalIp {} for router {}",
1004                                 label, externalIp, routerName);
1005                     } else {
1006                         LOG.debug("bestEffortDeletion : Label for ExternalIp {} is not found for router {}",
1007                                 externalIp, routerName);
1008                         continue;
1009                     }
1010                     externalRouterListener.clearBgpRoutes(externalIp, vpnName);
1011                     externalRouterListener.delFibTsAndReverseTraffic(naptSwitch, routerName, routerId, externalIp,
1012                             vpnName, networkId, label, gwMacAddress, true, confTx);
1013                     LOG.debug("bestEffortDeletion : Successfully removed fib entries in switch {} for router {} "
1014                             + "and externalIps {}", naptSwitch, routerId, externalIp);
1015                 }
1016             }
1017         } else {
1018             LOG.debug("bestEffortDeletion : No external IP found for router {}", routerId);
1019         }
1020     }
1021
1022     private void removeFibEntry(String rd, String prefix) {
1023         InstanceIdentifier.InstanceIdentifierBuilder<VrfEntry> idBuilder =
1024             InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd))
1025                 .child(VrfEntry.class, new VrfEntryKey(prefix));
1026         InstanceIdentifier<VrfEntry> vrfEntryId = idBuilder.build();
1027         Optional<VrfEntry> ent = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
1028         if (ent.isPresent()) {
1029             LOG.debug("removeFibEntry : Removing Fib entry rd {} prefix {}", rd, prefix);
1030             fibManager.removeFibEntry(rd, prefix, null);
1031         }
1032     }
1033
1034     protected void subnetRegisterMapping(Routers routerEntry, Long segmentId) {
1035         externalRouterListener.subnetRegisterMapping(routerEntry, segmentId);
1036     }
1037 }