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