Merge "BUG-6070 dpid changes as ports added to bridge"
[netvirt.git] / vpnservice / natservice / natservice-impl / src / main / java / org / opendaylight / netvirt / natservice / internal / ExternalRoutersListener.java
1 /*
2  * Copyright (c) 2016 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
9 package org.opendaylight.netvirt.natservice.internal;
10
11 import java.math.BigInteger;
12 import java.util.*;
13 import java.util.concurrent.ExecutionException;
14 import java.util.concurrent.Future;
15
16 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalIpsCounter;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.IntextIpPortMap;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProtocolTypes;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.ExternalCounters;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.external.counters.ExternalIpCounter;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMappingKey;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchBuilder;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeGre;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.*;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.VpnRpcService;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMapping;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolType;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMap;
35 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;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelOutput;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelInput;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelInputBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInput;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInputBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInputBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelInput;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInput;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelInputBuilder;
45 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
46 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
47 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
48 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
49 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
50 import org.opendaylight.genius.mdsalutil.ActionInfo;
51 import org.opendaylight.genius.mdsalutil.ActionType;
52 import org.opendaylight.genius.mdsalutil.BucketInfo;
53 import org.opendaylight.genius.mdsalutil.FlowEntity;
54 import org.opendaylight.genius.mdsalutil.GroupEntity;
55 import org.opendaylight.genius.mdsalutil.InstructionInfo;
56 import org.opendaylight.genius.mdsalutil.InstructionType;
57 import org.opendaylight.genius.mdsalutil.MDSALUtil;
58 import org.opendaylight.genius.mdsalutil.MatchFieldType;
59 import org.opendaylight.genius.mdsalutil.MatchInfo;
60 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
61 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
62 import org.opendaylight.genius.mdsalutil.NwConstants;
63 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCase;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushVlanActionCase;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetFieldCase;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInput;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInputBuilder;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceInputBuilder;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceOutput;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInputBuilder;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameOutput;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExtRouters;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.NaptSwitches;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.RouterIdName;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.RoutersKey;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMapBuilder;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMapKey;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitch;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.router.id.name.RouterIds;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.router.id.name.RouterIdsBuilder;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.router.id.name.RouterIdsKey;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
99 import org.opendaylight.yangtools.concepts.ListenerRegistration;
100 import org.opendaylight.yangtools.yang.binding.DataObject;
101 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
102 import org.opendaylight.yangtools.yang.common.RpcResult;
103 import org.slf4j.Logger;
104 import org.slf4j.LoggerFactory;
105
106 import com.google.common.base.Optional;
107 import com.google.common.collect.Sets;
108 import com.google.common.collect.Sets.SetView;
109 import com.google.common.util.concurrent.AsyncFunction;
110 import com.google.common.util.concurrent.FutureCallback;
111 import com.google.common.util.concurrent.Futures;
112 import com.google.common.util.concurrent.JdkFutureAdapters;
113 import com.google.common.util.concurrent.ListenableFuture;
114
115 /**
116  * Created by EYUGSAR on 2/20/2016.
117  */
118
119 public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Routers, ExternalRoutersListener>{
120
121     private static final Logger LOG = LoggerFactory.getLogger( ExternalRoutersListener.class);
122     private static long label;
123     private ListenerRegistration<DataChangeListener> listenerRegistration;
124     private final DataBroker dataBroker;
125     private IMdsalApiManager mdsalManager;
126     private ItmRpcService itmManager;
127     private OdlInterfaceRpcService interfaceManager;
128     private IdManagerService idManager;
129     private NaptManager naptManager;
130     private NAPTSwitchSelector naptSwitchSelector;
131     private IBgpManager bgpManager;
132     private VpnRpcService vpnService;
133     private FibRpcService fibService;
134     private SNATDefaultRouteProgrammer defaultRouteProgrammer;
135     private static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
136     static final BigInteger COOKIE_VM_LFIB_TABLE = new BigInteger("8000022", 16);
137     private NaptEventHandler naptEventHandler;
138     private NaptPacketInHandler naptPacketInHandler;
139
140     public void setNaptEventHandler(NaptEventHandler naptEventHandler) {
141         this.naptEventHandler = naptEventHandler;
142     }
143
144     public void setNaptPacketInHandler(NaptPacketInHandler naptPacketInHandler) {
145         this.naptPacketInHandler = naptPacketInHandler;
146     }
147
148     public void setMdsalManager(IMdsalApiManager mdsalManager) {
149         this.mdsalManager = mdsalManager;
150     }
151
152     public void setItmManager(ItmRpcService itmManager) {
153         this.itmManager = itmManager;
154     }
155
156     public void setIdManager(IdManagerService idManager) {
157         this.idManager = idManager;
158         createGroupIdPool();
159     }
160
161     void setDefaultProgrammer(SNATDefaultRouteProgrammer defaultRouteProgrammer) {
162         this.defaultRouteProgrammer = defaultRouteProgrammer;
163     }
164
165
166     public void setInterfaceManager(OdlInterfaceRpcService interfaceManager) {
167         this.interfaceManager = interfaceManager;
168     }
169
170     public void setNaptManager(NaptManager naptManager) {
171         this.naptManager = naptManager;
172     }
173
174     public void setNaptSwitchSelector(NAPTSwitchSelector naptSwitchSelector) {
175         this.naptSwitchSelector = naptSwitchSelector;
176     }
177
178     public void setBgpManager(IBgpManager bgpManager) {
179         this.bgpManager = bgpManager;
180     }
181
182     public void setVpnService(VpnRpcService vpnService) {
183         this.vpnService = vpnService;
184     }
185
186     public void setFibService(FibRpcService fibService) {
187         this.fibService = fibService;
188     }
189
190     public ExternalRoutersListener(DataBroker dataBroker )
191     {
192         super( Routers.class, ExternalRoutersListener.class );
193         this.dataBroker = dataBroker;
194     }
195
196     @Override
197     protected void add(InstanceIdentifier<Routers> identifier, Routers routers) {
198
199         LOG.info("NAT Service : Add external router event for {}", routers.getRouterName());
200
201         // Populate the router-id-name container
202         String routerName = routers.getRouterName();
203         Long routerId = NatUtil.getVpnId(dataBroker, routerName);
204         RouterIds rtrs = new RouterIdsBuilder().setKey(new RouterIdsKey(routerId)).setRouterId(routerId).setRouterName(routerName).build();
205         MDSALUtil.syncWrite( dataBroker, LogicalDatastoreType.CONFIGURATION, getRoutersIdentifier(routerId), rtrs);
206
207         LOG.info("NAT Service : Installing NAT default route on all dpns part of router {}", routers.getRouterName());
208         try {
209             addOrDelDefFibRouteToSNAT(routers.getRouterName(), true);
210         } catch (Exception ex) {
211             LOG.debug("NAT Service : Exception {} while Installing NAT default route on all dpns part of router {}",ex,routers.getRouterName());
212         }
213
214         if( !routers.isEnableSnat()) {
215             LOG.info("NAT Service : SNAT is disabled for external router {} ", routers.getRouterName());
216             return;
217         }
218
219         handleEnableSnat(routers);
220     }
221
222     public void handleEnableSnat(Routers routers){
223         String routerName = routers.getRouterName();
224         LOG.info("NAT Service : Handling SNAT for router {}", routerName);
225
226         long segmentId = NatUtil.getVpnId(dataBroker, routerName);
227         naptManager.initialiseExternalCounter(routers, segmentId);
228
229         subnetRegisterMapping(routers,segmentId);
230
231         // Allocate Primary Napt Switch for this router
232         BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterId(dataBroker,segmentId);
233         if (primarySwitchId != null && !primarySwitchId.equals(BigInteger.ZERO)) {
234             LOG.debug("NAT Service : Primary NAPT switch with DPN ID {} is already elected for router",primarySwitchId,routerName);
235             return;
236         }
237         primarySwitchId = naptSwitchSelector.selectNewNAPTSwitch(routerName);
238         LOG.debug("NAT Service : Primary NAPT switch DPN ID {}", primarySwitchId);
239         if(primarySwitchId == null || primarySwitchId.equals(BigInteger.ZERO)){
240             LOG.error("NAT Service : Unable to to select the primary NAPT switch");
241             return;
242         }
243         LOG.debug("NAT Service : About to create and install outbound miss entry in Primary Switch {} for router {}", primarySwitchId, routerName);
244
245         long bgpVpnId = NatConstants.INVALID_ID;
246         Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
247         if (bgpVpnUuid != null) {
248             bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
249         }
250         if (bgpVpnId != NatConstants.INVALID_ID){           
251             installFlowsWithUpdatedVpnId(primarySwitchId, routerName, bgpVpnId, segmentId, false);
252         } else {
253             // write metadata and punt
254             installOutboundMissEntry(routerName, primarySwitchId);
255             // Now install entries in SNAT tables to point to Primary for each router
256             List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
257             if (switches != null) {
258                 for (BigInteger dpnId : switches) {
259                     // Handle switches and NAPT switches separately
260                     if (!dpnId.equals(primarySwitchId)) {
261                         LOG.debug("NAT Service : Handle Ordinary switch");
262                         handleSwitches(dpnId, routerName, primarySwitchId);
263                     } else {
264                         LOG.debug("NAT Service : Handle NAPT switch");
265                         handlePrimaryNaptSwitch(dpnId, routerName);
266                     }
267                 }
268             }
269         }
270
271         List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker,segmentId);
272         if (externalIps == null || externalIps.isEmpty()) {
273             LOG.debug("NAT Service : Internal External mapping found for router {}",routerName);
274             return;
275         } else {
276             for (String externalIpAddrPrefix : externalIps) {
277                 LOG.debug("NAT Service : Calling handleSnatReverseTraffic for primarySwitchId {}, routerName {} and externalIpAddPrefix {}", primarySwitchId, routerName, externalIpAddrPrefix);
278                 handleSnatReverseTraffic(primarySwitchId, segmentId, externalIpAddrPrefix);
279             }
280         }
281
282         /*// call registerMapping Api
283         LOG.debug("NAT Service : Preparing to call registerMapping for routerName {} and Id {}", routerName, segmentId);
284
285         List<Uuid> subnetList = null;
286         List<String> externalIps = null;
287
288         InstanceIdentifier<Routers> id = InstanceIdentifier
289                 .builder(ExtRouters.class)
290                 .child(Routers.class, new RoutersKey(routerName))
291                 .build();
292
293         Optional<Routers> extRouters = read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
294
295         if(extRouters.isPresent())
296         {
297             LOG.debug("NAT Service : Fetching values from extRouters model");
298             Routers routerEntry= extRouters.get();
299             subnetList = routerEntry.getSubnetIds();
300             externalIps = routerEntry.getExternalIps();
301             int counter = 0;
302             int extIpCounter = externalIps.size();
303             LOG.debug("NAT Service : counter values before looping counter {} and extIpCounter {}", counter, extIpCounter);
304             for(Uuid subnet : subnetList) {
305                   LOG.debug("NAT Service : Looping internal subnets for subnet {}", subnet);
306                   InstanceIdentifier<Subnetmap> subnetmapId = InstanceIdentifier
307                          .builder(Subnetmaps.class)
308                          .child(Subnetmap.class, new SubnetmapKey(subnet))
309                          .build();
310                   Optional<Subnetmap> sn = read(dataBroker, LogicalDatastoreType.CONFIGURATION, subnetmapId);
311                   if(sn.isPresent()){
312                       // subnets
313                       Subnetmap subnetmapEntry = sn.get();
314                       String subnetString = subnetmapEntry.getSubnetIp();
315                       String[] subnetSplit = subnetString.split("/");
316                       String subnetIp = subnetSplit[0];
317                       String subnetPrefix = "0";
318                       if(subnetSplit.length ==  2) {
319                           subnetPrefix = subnetSplit[1];
320                       }
321                       IPAddress subnetAddr = new IPAddress(subnetIp, Integer.parseInt(subnetPrefix));
322                       LOG.debug("NAT Service : subnetAddr is {} and subnetPrefix is {}", subnetAddr.getIpAddress(), subnetAddr.getPrefixLength());
323                       //externalIps
324                       LOG.debug("NAT Service : counter values counter {} and extIpCounter {}", counter, extIpCounter);
325                       if(extIpCounter != 0) {
326                             if(counter < extIpCounter) {
327                                    String[] IpSplit = externalIps.get(counter).split("/");
328                                    String externalIp = IpSplit[0];
329                                    String extPrefix = Short.toString(NatConstants.DEFAULT_PREFIX);
330                                    if(IpSplit.length==2) {
331                                        extPrefix = IpSplit[1];
332                                    }
333                                    IPAddress externalIpAddr = new IPAddress(externalIp, Integer.parseInt(extPrefix));
334                                    LOG.debug("NAT Service : externalIp is {} and extPrefix  is {}", externalIpAddr.getIpAddress(), externalIpAddr.getPrefixLength());
335                                    naptManager.registerMapping(segmentId, subnetAddr, externalIpAddr);
336                                    LOG.debug("NAT Service : Called registerMapping for subnetIp {}, prefix {}, externalIp {}. prefix {}", subnetIp, subnetPrefix,
337                                             externalIp, extPrefix);
338
339                                    String externalIpAddrPrefix = externalIpAddr.getIpAddress() + "/" + externalIpAddr.getPrefixLength();
340                                    LOG.debug("NAT Service : Calling handleSnatReverseTraffic for primarySwitchId {}, routerName {} and externalIpAddPrefix {}", primarySwitchId, routerName, externalIpAddrPrefix);
341                                    handleSnatReverseTraffic(primarySwitchId, segmentId, externalIpAddrPrefix);
342
343                             } else {
344                                    counter = 0;    //Reset the counter which runs on externalIps for round-robbin effect
345                                    LOG.debug("NAT Service : Counter on externalIps got reset");
346                                    String[] IpSplit = externalIps.get(counter).split("/");
347                                    String externalIp = IpSplit[0];
348                                    String extPrefix = Short.toString(NatConstants.DEFAULT_PREFIX);
349                                    if(IpSplit.length==2) {
350                                        extPrefix = IpSplit[1];
351                                    }
352                                    IPAddress externalIpAddr = new IPAddress(externalIp, Integer.parseInt(extPrefix));
353                                    LOG.debug("NAT Service : externalIp is {} and extPrefix  is {}", externalIpAddr.getIpAddress(), externalIpAddr.getPrefixLength());
354                                    naptManager.registerMapping(segmentId, subnetAddr, externalIpAddr);
355                                    LOG.debug("NAT Service : Called registerMapping for subnetIp {}, prefix {}, externalIp {}. prefix {}", subnetIp, subnetPrefix,
356                                             externalIp, extPrefix);
357
358                                    String externalIpAddrPrefix = externalIpAddr.getIpAddress() + "/" + externalIpAddr.getPrefixLength();
359                                    LOG.debug("NAT Service : Calling handleSnatReverseTraffic for primarySwitchId {}, routerName {} and externalIpAddPrefix {}", primarySwitchId, routerName, externalIpAddrPrefix);
360                                    handleSnatReverseTraffic(primarySwitchId, segmentId, externalIpAddrPrefix);
361
362                             }
363                       }
364                       counter++;
365                       LOG.debug("NAT Service : Counter on externalIps incremented to {}", counter);
366
367                   } else {
368                       LOG.warn("NAT Service : No internal subnets present in extRouters Model");
369                   }
370             }
371         }*/
372         LOG.info("NAT Service : handleEnableSnat() Exit");
373     }
374
375     private void subnetRegisterMapping(Routers routerEntry,Long segmentId) {
376         List<Uuid> subnetList = null;
377         List<String> externalIps = null;
378         LOG.debug("NAT Service : Fetching values from extRouters model");
379         subnetList = routerEntry.getSubnetIds();
380         externalIps = routerEntry.getExternalIps();
381         int counter = 0;
382         int extIpCounter = externalIps.size();
383         LOG.debug("NAT Service : counter values before looping counter {} and extIpCounter {}", counter, extIpCounter);
384         for(Uuid subnet : subnetList) {
385             LOG.debug("NAT Service : Looping internal subnets for subnet {}", subnet);
386             InstanceIdentifier<Subnetmap> subnetmapId = InstanceIdentifier
387                     .builder(Subnetmaps.class)
388                     .child(Subnetmap.class, new SubnetmapKey(subnet))
389                     .build();
390             Optional<Subnetmap> sn = read(dataBroker, LogicalDatastoreType.CONFIGURATION, subnetmapId);
391             if(sn.isPresent()){
392                 // subnets
393                 Subnetmap subnetmapEntry = sn.get();
394                 String subnetString = subnetmapEntry.getSubnetIp();
395                 String[] subnetSplit = subnetString.split("/");
396                 String subnetIp = subnetSplit[0];
397                 String subnetPrefix = "0";
398                 if(subnetSplit.length ==  2) {
399                     subnetPrefix = subnetSplit[1];
400                 }
401                 IPAddress subnetAddr = new IPAddress(subnetIp, Integer.parseInt(subnetPrefix));
402                 LOG.debug("NAT Service : subnetAddr is {} and subnetPrefix is {}", subnetAddr.getIpAddress(), subnetAddr.getPrefixLength());
403                 //externalIps
404                 LOG.debug("NAT Service : counter values counter {} and extIpCounter {}", counter, extIpCounter);
405                 if(extIpCounter != 0) {
406                     if(counter < extIpCounter) {
407                         String[] IpSplit = externalIps.get(counter).split("/");
408                         String externalIp = IpSplit[0];
409                         String extPrefix = Short.toString(NatConstants.DEFAULT_PREFIX);
410                         if(IpSplit.length==2) {
411                             extPrefix = IpSplit[1];
412                         }
413                         IPAddress externalIpAddr = new IPAddress(externalIp, Integer.parseInt(extPrefix));
414                         LOG.debug("NAT Service : externalIp is {} and extPrefix  is {}", externalIpAddr.getIpAddress(), externalIpAddr.getPrefixLength());
415                         naptManager.registerMapping(segmentId, subnetAddr, externalIpAddr);
416                         LOG.debug("NAT Service : Called registerMapping for subnetIp {}, prefix {}, externalIp {}. prefix {}", subnetIp, subnetPrefix,
417                                 externalIp, extPrefix);
418                     } else {
419                         counter = 0;    //Reset the counter which runs on externalIps for round-robbin effect
420                         LOG.debug("NAT Service : Counter on externalIps got reset");
421                         String[] IpSplit = externalIps.get(counter).split("/");
422                         String externalIp = IpSplit[0];
423                         String extPrefix = Short.toString(NatConstants.DEFAULT_PREFIX);
424                         if(IpSplit.length==2) {
425                             extPrefix = IpSplit[1];
426                         }
427                         IPAddress externalIpAddr = new IPAddress(externalIp, Integer.parseInt(extPrefix));
428                         LOG.debug("NAT Service : externalIp is {} and extPrefix  is {}", externalIpAddr.getIpAddress(), externalIpAddr.getPrefixLength());
429                         naptManager.registerMapping(segmentId, subnetAddr, externalIpAddr);
430                         LOG.debug("NAT Service : Called registerMapping for subnetIp {}, prefix {}, externalIp {}. prefix {}", subnetIp, subnetPrefix,
431                                 externalIp, extPrefix);
432                     }
433                 }
434                 counter++;
435                 LOG.debug("NAT Service : Counter on externalIps incremented to {}", counter);
436             } else {
437                 LOG.warn("NAT Service : No internal subnets present in extRouters Model");
438             }
439         }
440     }
441
442     private void addOrDelDefFibRouteToSNAT(String routerName, boolean create) {
443         //Check if BGP VPN exists. If exists then invoke the new method.
444         long bgpVpnId = NatUtil.getBgpVpnId(dataBroker, routerName);
445         if(bgpVpnId != NatConstants.INVALID_ID) {
446             Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
447             if (bgpVpnUuid != null) {
448                 String bgpVpnName = bgpVpnUuid.getValue();
449                 LOG.debug("Populate the router-id-name container with the mapping BGP VPN-ID {} -> BGP VPN-NAME {}", bgpVpnId, bgpVpnName);
450                 RouterIds rtrs = new RouterIdsBuilder().setKey(new RouterIdsKey(bgpVpnId)).setRouterId(bgpVpnId).setRouterName(bgpVpnName).build();
451                 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, getRoutersIdentifier(bgpVpnId), rtrs);
452             }
453             addOrDelDefaultFibRouteForSNATWIthBgpVpn(routerName, bgpVpnId, create);
454             return;
455         }
456
457         //Router ID is used as the internal VPN's name, hence the vrf-id in VpnInstance Op DataStore
458         addOrDelDefaultFibRouteForSNAT(routerName, create);
459     }
460
461     private void addOrDelDefaultFibRouteForSNAT(String routerName, boolean create) {
462         List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
463         if (switches == null || switches.isEmpty()) {
464             LOG.debug("No switches found for router {}",routerName);
465             return;
466         }
467         long routerId = NatUtil.readVpnId(dataBroker, routerName);
468         if (routerId == NatConstants.INVALID_ID) {
469             LOG.error("Could not retrieve router Id for {} to program default NAT route in FIB", routerName);
470             return;
471         }
472         for (BigInteger dpnId : switches) {
473             if (create) {
474                 LOG.debug("NAT Service : installing default NAT route for router {} in dpn {} for the internal vpn",routerId,dpnId);
475                 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, routerId);
476             } else {
477                 LOG.debug("NAT Service : removing default NAT route for router {} in dpn {} for the internal vpn",routerId,dpnId);
478                 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, routerId);
479             }
480         }
481     }
482
483     private void addOrDelDefaultFibRouteForSNATWIthBgpVpn(String routerName, long bgpVpnId, boolean create) {
484         List<BigInteger> dpnIds = NatUtil.getDpnsForRouter(dataBroker, routerName);
485         if(dpnIds == null || dpnIds.isEmpty()) {
486             LOG.debug("NAT Service : Current no dpns part of router {} to program default NAT route", routerName);
487             return;
488         }
489         long routerId = NatUtil.getVpnId(dataBroker, routerName);
490         for (BigInteger dpnId : dpnIds) {
491             if (create) {
492                 if (bgpVpnId != NatConstants.INVALID_ID) {
493                     LOG.debug("NAT Service : installing default NAT route for router {} in dpn {} for the BGP vpnID {}",routerId,dpnId,bgpVpnId);
494                     defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, bgpVpnId, routerId);
495                 } else {
496                     LOG.debug("NAT Service : installing default NAT route for router {} in dpn {} for the internal vpn",routerId,dpnId);
497                     defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, routerId);
498                 }
499             } else {
500                 if (bgpVpnId != NatConstants.INVALID_ID) {
501                     LOG.debug("NAT Service : removing default NAT route for router {} in dpn {} for the BGP vpnID {}",routerId,dpnId,bgpVpnId);
502                     defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, bgpVpnId, routerId);
503                 } else {
504                     LOG.debug("NAT Service : removing default NAT route for router {} in dpn {} for the internal vpn",routerId,dpnId);
505                     defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, routerId);
506                 }
507             }
508         }
509     }
510
511     public static <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier<T> path)
512     {
513         ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
514
515         Optional<T> result = Optional.absent();
516         try
517         {
518             result = tx.read(datastoreType, path).get();
519         }
520         catch (Exception e)
521         {
522             throw new RuntimeException(e);
523         }
524
525         return result;
526     }
527
528     public void close() throws Exception
529     {
530         if (listenerRegistration != null)
531         {
532             try
533             {
534                 listenerRegistration.close();
535             }
536             catch (final Exception e)
537             {
538                 LOG.error("Error when cleaning up ExternalRoutersListener.", e);
539             }
540
541             listenerRegistration = null;
542         }
543         LOG.debug("ExternalRoutersListener Closed");
544     }
545
546     protected void installOutboundMissEntry(String routerName, BigInteger primarySwitchId) {
547         long routerId = NatUtil.getVpnId(dataBroker, routerName);
548         LOG.debug("NAT Service : Router ID from getVpnId {}", routerId);
549         if(routerId != NatConstants.INVALID_ID) {
550             LOG.debug("NAT Service : Creating miss entry on primary {}, for router {}", primarySwitchId, routerId);
551             createOutboundTblEntry(primarySwitchId, routerId);
552         } else {
553             LOG.error("NAT Service : Unable to fetch Router Id  for RouterName {}, failed to createAndInstallMissEntry", routerName);
554         }
555     }
556
557     public String getFlowRefOutbound(BigInteger dpnId, short tableId, long routerID) {
558         return new StringBuilder().append(NatConstants.NAPT_FLOWID_PREFIX).append(dpnId).append(NatConstants.FLOWID_SEPARATOR).
559                 append(tableId).append(NatConstants.FLOWID_SEPARATOR).append(routerID).toString();
560     }
561
562     public BigInteger getCookieOutboundFlow(long routerId) {
563         return NatConstants.COOKIE_OUTBOUND_NAPT_TABLE.add(new BigInteger("0110001", 16)).add(
564                 BigInteger.valueOf(routerId));
565     }
566
567     protected FlowEntity buildOutboundFlowEntity(BigInteger dpId, long routerId) {
568         LOG.debug("NAT Service : buildOutboundFlowEntity called for dpId {} and routerId{}", dpId, routerId);
569         List<MatchInfo> matches = new ArrayList<>();
570         matches.add(new MatchInfo(MatchFieldType.eth_type,
571                 new long[] { 0x0800L }));
572         matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
573                 BigInteger.valueOf(routerId), MetaDataUtil.METADATA_MASK_VRFID }));
574
575         List<InstructionInfo> instructions = new ArrayList<>();
576         List<ActionInfo> actionsInfos = new ArrayList<>();
577         actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[] {}));
578         instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
579         instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { BigInteger.valueOf(routerId), MetaDataUtil.METADATA_MASK_VRFID }));
580
581         String flowRef = getFlowRefOutbound(dpId, NatConstants.OUTBOUND_NAPT_TABLE, routerId);
582         BigInteger cookie = getCookieOutboundFlow(routerId);
583         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.OUTBOUND_NAPT_TABLE, flowRef,
584                 5, flowRef, 0, 0,
585                 cookie, matches, instructions);
586         LOG.debug("NAT Service : returning flowEntity {}", flowEntity);
587         return flowEntity;
588     }
589
590     public void createOutboundTblEntry(BigInteger dpnId, long routerId) {
591         LOG.debug("NAT Service : createOutboundTblEntry called for dpId {} and routerId {}", dpnId, routerId);
592         FlowEntity flowEntity = buildOutboundFlowEntity(dpnId, routerId);
593         LOG.debug("NAT Service : Installing flow {}", flowEntity);
594         mdsalManager.installFlow(flowEntity);
595     }
596
597     protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
598         Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
599         RpcResult<GetTunnelInterfaceNameOutput> rpcResult;
600         try {
601             Future<RpcResult<GetTunnelInterfaceNameOutput>> result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
602                                                                                  .setSourceDpid(srcDpId)
603                                                                                  .setDestinationDpid(dstDpId)
604                                                                                 .setTunnelType(tunType)
605                                                                                 .build());
606             rpcResult = result.get();
607             if(!rpcResult.isSuccessful()) {
608                 tunType = TunnelTypeGre.class ;
609                 result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
610                         .setSourceDpid(srcDpId)
611                         .setDestinationDpid(dstDpId)
612                         .setTunnelType(tunType)
613                         .build());
614                 rpcResult = result.get();
615                 if(!rpcResult.isSuccessful()) {
616                     LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
617                 } else {
618                     return rpcResult.getResult().getInterfaceName();
619                 }
620                 LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
621             } else {
622                 return rpcResult.getResult().getInterfaceName();
623             }
624         } catch (InterruptedException | ExecutionException | NullPointerException e) {
625             LOG.warn("NAT Service : Exception when getting tunnel interface Id for tunnel between {} and  {}", srcDpId, dstDpId);
626         }
627
628         return null;
629     }
630
631     protected List<ActionInfo> getEgressActionsForInterface(String ifName, long routerId) {
632         LOG.debug("NAT Service : getEgressActionsForInterface called for interface {}", ifName);
633         List<ActionInfo> listActionInfo = new ArrayList<>();
634         try {
635             Future<RpcResult<GetEgressActionsForInterfaceOutput>> result =
636                 interfaceManager.getEgressActionsForInterface(
637                     new GetEgressActionsForInterfaceInputBuilder().setIntfName(ifName).setTunnelKey(routerId).build());
638             RpcResult<GetEgressActionsForInterfaceOutput> rpcResult = result.get();
639             if(!rpcResult.isSuccessful()) {
640                 LOG.warn("RPC Call to Get egress actions for interface {} returned with Errors {}", ifName, rpcResult.getErrors());
641             } else {
642                 List<Action> actions =
643                     rpcResult.getResult().getAction();
644                 for (Action action : actions) {
645                     org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action actionClass = action.getAction();
646                     if (actionClass instanceof OutputActionCase) {
647                         listActionInfo.add(new ActionInfo(ActionType.output,
648                                                           new String[] {((OutputActionCase)actionClass).getOutputAction()
649                                                                             .getOutputNodeConnector().getValue()}));
650                     } else if (actionClass instanceof PushVlanActionCase) {
651                         listActionInfo.add(new ActionInfo(ActionType.push_vlan, new String[] {}));
652                     } else if (actionClass instanceof SetFieldCase) {
653                         if (((SetFieldCase)actionClass).getSetField().getVlanMatch() != null) {
654                             int vlanVid = ((SetFieldCase)actionClass).getSetField().getVlanMatch().getVlanId().getVlanId().getValue();
655                             listActionInfo.add(new ActionInfo(ActionType.set_field_vlan_vid,
656                                                               new String[] { Long.toString(vlanVid) }));
657                         }
658                     }
659                 }
660             }
661         } catch (InterruptedException | ExecutionException e) {
662             LOG.warn("Exception when egress actions for interface {}", ifName, e);
663         }
664         return listActionInfo;
665     }
666
667     protected void installSnatMissEntryForPrimrySwch(BigInteger dpnId, String routerName) {
668         LOG.debug("NAT Service : installSnatMissEntry called for for the primary NAOT switch dpnId {} ", dpnId);
669         // Install miss entry pointing to group
670         FlowEntity flowEntity = buildSnatFlowEntityForPrmrySwtch(dpnId, routerName);
671         mdsalManager.installFlow(flowEntity);
672     }
673
674     protected void installSnatMissEntry(BigInteger dpnId, List<BucketInfo> bucketInfo, String routerName) {
675         LOG.debug("NAT Service : installSnatMissEntry called for dpnId {} with primaryBucket {} ", dpnId, bucketInfo.get(0));
676         // Install the select group
677         long groupId = createGroupId(getGroupIdKey(routerName));
678         GroupEntity groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, bucketInfo);
679         LOG.debug("NAT Service : installing the SNAT to NAPT GroupEntity:{}", groupEntity);
680         mdsalManager.installGroup(groupEntity);
681         // Install miss entry pointing to group
682         FlowEntity flowEntity = buildSnatFlowEntity(dpnId, routerName, groupId);
683         mdsalManager.installFlow(flowEntity);
684     }
685
686     long installGroup(BigInteger dpnId, String routerName, List<BucketInfo> bucketInfo){
687         long groupId = createGroupId(getGroupIdKey(routerName));
688         GroupEntity groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, bucketInfo);
689         LOG.debug("NAT Service : installing the SNAT to NAPT GroupEntity:{}", groupEntity);
690         mdsalManager.installGroup(groupEntity);
691         return groupId;
692     }
693
694     public FlowEntity buildSnatFlowEntity(BigInteger dpId, String routerName, long groupId) {
695
696         LOG.debug("NAT Service : buildSnatFlowEntity is called for dpId {}, routerName {} and groupId {}", dpId, routerName, groupId );
697         long routerId = NatUtil.getVpnId(dataBroker, routerName);
698         List<MatchInfo> matches = new ArrayList<>();
699         matches.add(new MatchInfo(MatchFieldType.eth_type,
700                 new long[] { 0x0800L }));
701         matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
702                 BigInteger.valueOf(routerId), MetaDataUtil.METADATA_MASK_VRFID }));
703
704
705         List<InstructionInfo> instructions = new ArrayList<>();
706         List<ActionInfo> actionsInfo = new ArrayList<>();
707
708         ActionInfo actionSetField = new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {
709                         BigInteger.valueOf(routerId)}) ;
710         actionsInfo.add(actionSetField);
711         LOG.debug("NAT Service : Setting the tunnel to the list of action infos {}", actionsInfo);
712         actionsInfo.add(new ActionInfo(ActionType.group, new String[] {String.valueOf(groupId)}));
713         instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfo));
714         String flowRef = getFlowRefSnat(dpId, NatConstants.PSNAT_TABLE, routerName);
715         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PSNAT_TABLE, flowRef,
716                 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
717                 NatConstants.COOKIE_SNAT_TABLE, matches, instructions);
718
719         LOG.debug("NAT Service : Returning SNAT Flow Entity {}", flowEntity);
720         return flowEntity;
721     }
722
723     public FlowEntity buildSnatFlowEntityForPrmrySwtch(BigInteger dpId, String routerName) {
724
725         LOG.debug("NAT Service : buildSnatFlowEntity is called for primary NAPT switch dpId {}, routerName {}", dpId,
726                 routerName );
727         long routerId = NatUtil.getVpnId(dataBroker, routerName);
728         List<MatchInfo> matches = new ArrayList<MatchInfo>();
729         matches.add(new MatchInfo(MatchFieldType.eth_type,
730                 new long[] { 0x0800L }));
731         matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
732                 BigInteger.valueOf(routerId), MetaDataUtil.METADATA_MASK_VRFID }));
733
734         List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
735         instructions.add(new InstructionInfo(InstructionType.goto_table, new long[]
736                 { NatConstants.OUTBOUND_NAPT_TABLE }));
737
738         String flowRef = getFlowRefSnat(dpId, NatConstants.PSNAT_TABLE, routerName);
739         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PSNAT_TABLE, flowRef,
740                 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
741                 NatConstants.COOKIE_SNAT_TABLE, matches, instructions);
742
743         LOG.debug("NAT Service : Returning SNAT Flow Entity {}", flowEntity);
744         return flowEntity;
745     }
746
747     // TODO : Replace this with ITM Rpc once its available with full functionality
748     protected void installTerminatingServiceTblEntry(BigInteger dpnId, String routerName) {
749         LOG.debug("NAT Service : creating entry for Terminating Service Table for switch {}, routerName {}", dpnId, routerName);
750         FlowEntity flowEntity = buildTsFlowEntity(dpnId, routerName);
751         mdsalManager.installFlow(flowEntity);
752
753     }
754
755     private FlowEntity buildTsFlowEntity(BigInteger dpId, String routerName) {
756
757         BigInteger routerId = BigInteger.valueOf (NatUtil.getVpnId(dataBroker, routerName));
758         List<MatchInfo> matches = new ArrayList<>();
759         matches.add(new MatchInfo(MatchFieldType.eth_type,
760                 new long[] { 0x0800L }));
761         matches.add(new MatchInfo(MatchFieldType.tunnel_id, new  BigInteger[] {routerId }));
762
763         List<InstructionInfo> instructions = new ArrayList<>();
764         instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[]
765                 { routerId, MetaDataUtil.METADATA_MASK_VRFID }));
766         instructions.add(new InstructionInfo(InstructionType.goto_table, new long[]
767                 { NatConstants.OUTBOUND_NAPT_TABLE }));
768         String flowRef = getFlowRefTs(dpId, NatConstants.TERMINATING_SERVICE_TABLE, routerId.longValue());
769         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.TERMINATING_SERVICE_TABLE, flowRef,
770                 NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, 0, 0,
771                 NatConstants.COOKIE_TS_TABLE, matches, instructions);
772         return flowEntity;
773     }
774
775     public String getFlowRefTs(BigInteger dpnId, short tableId, long routerID) {
776         return new StringBuilder().append(NatConstants.NAPT_FLOWID_PREFIX).append(dpnId).append(NatConstants.FLOWID_SEPARATOR).
777                 append(tableId).append(NatConstants.FLOWID_SEPARATOR).append(routerID).toString();
778     }
779
780     public static String getFlowRefSnat(BigInteger dpnId, short tableId, String routerID) {
781         return new StringBuilder().append(NatConstants.SNAT_FLOWID_PREFIX).append(dpnId).append(NatConstants.FLOWID_SEPARATOR).
782             append(tableId).append(NatConstants.FLOWID_SEPARATOR).append(routerID).toString();
783     }
784
785     private String getGroupIdKey(String routerName){
786         String groupIdKey = new String("snatmiss." + routerName);
787         return groupIdKey;
788     }
789
790     protected long createGroupId(String groupIdKey) {
791         AllocateIdInput getIdInput = new AllocateIdInputBuilder()
792             .setPoolName(NatConstants.SNAT_IDPOOL_NAME).setIdKey(groupIdKey)
793             .build();
794         try {
795             Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
796             RpcResult<AllocateIdOutput> rpcResult = result.get();
797             return rpcResult.getResult().getIdValue();
798         } catch (NullPointerException | InterruptedException | ExecutionException e) {
799             LOG.trace("",e);
800         }
801         return 0;
802     }
803
804     protected void createGroupIdPool() {
805         CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
806             .setPoolName(NatConstants.SNAT_IDPOOL_NAME)
807             .setLow(NatConstants.SNAT_ID_LOW_VALUE)
808             .setHigh(NatConstants.SNAT_ID_HIGH_VALUE)
809             .build();
810         try {
811             Future<RpcResult<Void>> result = idManager.createIdPool(createPool);
812                 if ((result != null) && (result.get().isSuccessful())) {
813                     LOG.debug("NAT Service : Created GroupIdPool");
814                 } else {
815                     LOG.error("NAT Service : Unable to create GroupIdPool");
816                 }
817         } catch (InterruptedException | ExecutionException e) {
818             LOG.error("Failed to create PortPool for NAPT Service",e);
819         }
820     }
821
822     protected void handleSwitches (BigInteger dpnId, String routerName, BigInteger primarySwitchId) {
823         LOG.debug("NAT Service : Installing SNAT miss entry in switch {}", dpnId);
824         List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
825         String ifNamePrimary = getTunnelInterfaceName( dpnId, primarySwitchId);
826         List<BucketInfo> listBucketInfo = new ArrayList<>();
827         long routerId = NatUtil.getVpnId(dataBroker, routerName);
828
829         if(ifNamePrimary != null) {
830             LOG.debug("NAT Service : On Non- Napt switch , Primary Tunnel interface is {}", ifNamePrimary);
831             listActionInfoPrimary = getEgressActionsForInterface(ifNamePrimary, routerId);
832         }
833         BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
834
835         listBucketInfo.add(0, bucketPrimary);
836         installSnatMissEntry(dpnId, listBucketInfo, routerName);
837
838     }
839     List<BucketInfo> getBucketInfoForNonNaptSwitches(BigInteger nonNaptSwitchId, BigInteger primarySwitchId, String routerName) {
840         List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
841         String ifNamePrimary = getTunnelInterfaceName(nonNaptSwitchId, primarySwitchId);
842         List<BucketInfo> listBucketInfo = new ArrayList<>();
843         long routerId = NatUtil.getVpnId(dataBroker, routerName);
844
845         if (ifNamePrimary != null) {
846             LOG.debug("NAT Service : On Non- Napt switch , Primary Tunnel interface is {}", ifNamePrimary);
847             listActionInfoPrimary = getEgressActionsForInterface(ifNamePrimary, routerId);
848         }
849         BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
850
851         listBucketInfo.add(0, bucketPrimary);
852         return listBucketInfo;
853     }
854     protected void handlePrimaryNaptSwitch (BigInteger dpnId, String routerName) {
855
856            /*
857             * Primary NAPT Switch Ã¢â‚¬â€œ bucket Should always point back to its own Outbound Table
858             */
859
860             LOG.debug("NAT Service : Installing SNAT miss entry in Primary NAPT switch {} ", dpnId);
861
862 /*
863             List<BucketInfo> listBucketInfo = new ArrayList<>();
864             List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
865             listActionInfoPrimary.add(new ActionInfo(ActionType.nx_resubmit, new String[]{String.valueOf(NatConstants.TERMINATING_SERVICE_TABLE)}));
866             BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
867             listBucketInfo.add(0, bucketPrimary);
868 */
869
870             long routerId = NatUtil.getVpnId(dataBroker, routerName);
871
872             installSnatMissEntryForPrimrySwch(dpnId, routerName);
873             installTerminatingServiceTblEntry(dpnId, routerName);
874             //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the router ID.
875             installNaptPfibEntry(dpnId, routerId);
876             Long vpnId = NatUtil.getVpnId(dataBroker, routerId);
877            //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
878             if(vpnId != null && vpnId != NatConstants.INVALID_ID) {
879                 installNaptPfibEntry(dpnId, vpnId);
880             }
881     }
882
883     List<BucketInfo> getBucketInfoForPrimaryNaptSwitch(){
884         List<BucketInfo> listBucketInfo = new ArrayList<>();
885         List<ActionInfo> listActionInfoPrimary =  new ArrayList<>();
886         listActionInfoPrimary.add(new ActionInfo(ActionType.nx_resubmit, new String[]{String.valueOf(NatConstants.TERMINATING_SERVICE_TABLE)}));
887         BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
888         listBucketInfo.add(0, bucketPrimary);
889         return listBucketInfo;
890     }
891
892     public void installNaptPfibEntry(BigInteger dpnId, long segmentId) {
893         LOG.debug("NAT Service : installNaptPfibEntry called for dpnId {} and segmentId {} ", dpnId, segmentId);
894         FlowEntity naptPfibFlowEntity = buildNaptPfibFlowEntity(dpnId, segmentId);
895         mdsalManager.installFlow(naptPfibFlowEntity);
896     }
897
898     public FlowEntity buildNaptPfibFlowEntity(BigInteger dpId, long segmentId) {
899
900         LOG.debug("NAT Service : buildNaptPfibFlowEntity is called for dpId {}, segmentId {}", dpId, segmentId );
901         List<MatchInfo> matches = new ArrayList<>();
902         matches.add(new MatchInfo(MatchFieldType.eth_type,
903                 new long[] { 0x0800L }));
904         matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
905                 BigInteger.valueOf(segmentId), MetaDataUtil.METADATA_MASK_VRFID }));
906
907         ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
908         ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
909         listActionInfo.add(new ActionInfo(ActionType.nx_resubmit, new String[] { Integer.toString(NatConstants.L3_FIB_TABLE) }));
910         instructionInfo.add(new InstructionInfo(InstructionType.apply_actions, listActionInfo));
911
912         String flowRef = getFlowRefTs(dpId, NatConstants.NAPT_PFIB_TABLE, segmentId);
913         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.NAPT_PFIB_TABLE, flowRef,
914                 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
915                 NatConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
916
917         LOG.debug("NAT Service : Returning NaptPFib Flow Entity {}", flowEntity);
918         return flowEntity;
919     }
920
921     private void handleSnatReverseTraffic(BigInteger dpnId, long routerId, String externalIp) {
922         LOG.debug("NAT Service : handleSnatReverseTraffic() entry for DPN ID, routerId, externalIp : {}", dpnId, routerId, externalIp);
923         Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
924         if(networkId == null) {
925             LOG.error("NAT Service : networkId is null for the router ID {}", routerId);
926             return;
927         }
928         final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
929         if(vpnName == null) {
930             LOG.error("NAT Service : No VPN associated with ext nw {} to handle add external ip configuration {} in router {}",
931                     networkId, externalIp, routerId);
932             return;
933         }
934         advToBgpAndInstallFibAndTsFlows(dpnId, NatConstants.INBOUND_NAPT_TABLE, vpnName, routerId, externalIp, vpnService, fibService, bgpManager, dataBroker, LOG);
935         LOG.debug("NAT Service : handleSnatReverseTraffic() exit for DPN ID, routerId, externalIp : {}", dpnId, routerId, externalIp);
936     }
937
938     public void advToBgpAndInstallFibAndTsFlows(final BigInteger dpnId, final short tableId, final String vpnName, final long routerId, final String externalIp,
939                                                 VpnRpcService vpnService, final FibRpcService fibService, final IBgpManager bgpManager, final DataBroker dataBroker,
940                                                 final Logger log){
941         LOG.debug("NAT Service : advToBgpAndInstallFibAndTsFlows() entry for DPN ID {}, tableId {}, vpnname {} and externalIp {}", dpnId, tableId, vpnName, externalIp);
942         //Generate VPN label for the external IP
943         GenerateVpnLabelInput labelInput = new GenerateVpnLabelInputBuilder().setVpnName(vpnName).setIpPrefix(externalIp).build();
944         Future<RpcResult<GenerateVpnLabelOutput>> labelFuture = vpnService.generateVpnLabel(labelInput);
945
946         //On successful generation of the VPN label, advertise the route to the BGP and install the FIB routes.
947         ListenableFuture<RpcResult<Void>> future = Futures.transform(JdkFutureAdapters.listenInPoolThread(labelFuture), new AsyncFunction<RpcResult<GenerateVpnLabelOutput>, RpcResult<Void>>() {
948
949             @Override
950             public ListenableFuture<RpcResult<Void>> apply(RpcResult<GenerateVpnLabelOutput> result) throws Exception {
951                 if (result.isSuccessful()) {
952                     LOG.debug("NAT Service : inside apply with result success");
953                     GenerateVpnLabelOutput output = result.getResult();
954                     final long label = output.getLabel();
955
956                     int externalIpInDsFlag = 0;
957                     //Get IPMaps from the DB for the router ID
958                     List<IpMap> dbIpMaps = NaptManager.getIpMapList(dataBroker, routerId);
959                     if (dbIpMaps != null) {
960                         for (IpMap dbIpMap : dbIpMaps) {
961                             String dbExternalIp = dbIpMap.getExternalIp();
962                             //Select the IPMap, whose external IP is the IP for which FIB is installed
963                             if (externalIp.equals(dbExternalIp)) {
964                                 String dbInternalIp = dbIpMap.getInternalIp();
965                                 IpMapKey dbIpMapKey = dbIpMap.getKey();
966                                 LOG.debug("Setting label {} for internalIp {} and externalIp {}", label, dbInternalIp, externalIp);
967                                 IpMap newIpm = new IpMapBuilder().setKey(dbIpMapKey).setInternalIp(dbInternalIp).setExternalIp(dbExternalIp).setLabel(label).build();
968                                 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, naptManager.getIpMapIdentifier(routerId, dbInternalIp), newIpm);
969                                 externalIpInDsFlag++;
970                             }
971                         }
972                         if (externalIpInDsFlag <=0) {
973                             LOG.debug("NAT Service : External Ip {} not found in DS,Failed to update label {} for routerId {} in DS", externalIp, label, routerId);
974                             String errMsg = String.format("Failed to update label %s due to external Ip %s not found in DS for router %s", externalIp, label, routerId);
975                             return Futures.immediateFailedFuture(new Exception(errMsg));
976                         }
977                     } else {
978                         LOG.error("NAT Service : Failed to write label {} for externalIp {} for routerId {} in DS", label, externalIp, routerId);
979                     }
980
981
982                     //Inform BGP
983                     String rd = NatUtil.getVpnRd(dataBroker, vpnName);
984                     String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, dpnId);
985                     NatUtil.addPrefixToBGP(bgpManager, rd, externalIp, nextHopIp, label, log);
986
987                     //Install custom FIB routes
988                     List<Instruction> customInstructions = new ArrayList<>();
989                     customInstructions.add(new InstructionInfo(InstructionType.goto_table, new long[]{tableId}).buildInstruction(0));
990                     makeTunnelTableEntry(dpnId, label, customInstructions);
991                     makeLFibTableEntry(dpnId, label, tableId);
992
993                     CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName).setSourceDpid(dpnId)
994                             .setIpAddress(externalIp).setServiceId(label).setInstruction(customInstructions).build();
995                     Future<RpcResult<Void>> future = fibService.createFibEntry(input);
996                     return JdkFutureAdapters.listenInPoolThread(future);
997                 } else {
998                     LOG.error("NAT Service : inside apply with result failed");
999                     String errMsg = String.format("Could not retrieve the label for prefix %s in VPN %s, %s", externalIp, vpnName, result.getErrors());
1000                     return Futures.immediateFailedFuture(new RuntimeException(errMsg));
1001                 }
1002             }
1003         });
1004
1005             Futures.addCallback(future, new FutureCallback<RpcResult<Void>>() {
1006
1007                 @Override
1008                 public void onFailure(Throwable error) {
1009                     log.error("NAT Service : Error in generate label or fib install process", error);
1010                 }
1011
1012                 @Override
1013                 public void onSuccess(RpcResult<Void> result) {
1014                     if (result.isSuccessful()) {
1015                         log.info("NAT Service : Successfully installed custom FIB routes for prefix {}", externalIp);
1016                     } else {
1017                         log.error("NAT Service : Error in rpc call to create custom Fib entries for prefix {} in DPN {}, {}", externalIp, dpnId, result.getErrors());
1018                     }
1019                 }
1020             });
1021      }
1022
1023     private void makeLFibTableEntry(BigInteger dpId, long serviceId, long tableId) {
1024         List<MatchInfo> matches = new ArrayList<>();
1025         matches.add(new MatchInfo(MatchFieldType.eth_type,
1026                 new long[]{0x8847L}));
1027         matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(serviceId)}));
1028
1029         List<Instruction> instructions = new ArrayList<>();
1030         List<ActionInfo> actionsInfos = new ArrayList<>();
1031         actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
1032         Instruction writeInstruction = new InstructionInfo(InstructionType.apply_actions, actionsInfos).buildInstruction(0);
1033         instructions.add(writeInstruction);
1034         instructions.add(new InstructionInfo(InstructionType.goto_table, new long[]{tableId}).buildInstruction(1));
1035
1036         // Install the flow entry in L3_LFIB_TABLE
1037         String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, serviceId, "");
1038
1039         Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
1040                 10, flowRef, 0, 0,
1041                 COOKIE_VM_LFIB_TABLE, matches, instructions);
1042
1043         mdsalManager.installFlow(dpId, flowEntity);
1044
1045         LOG.debug("NAT Service : LFIB Entry for dpID {} : label : {} modified successfully {}",dpId, serviceId );
1046     }
1047
1048     private void makeTunnelTableEntry(BigInteger dpnId, long serviceId, List<Instruction> customInstructions) {
1049         List<MatchInfo> mkMatches = new ArrayList<>();
1050
1051         LOG.debug("NAT Service : Create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", dpnId , serviceId);
1052
1053         mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(serviceId)}));
1054
1055         Flow terminatingServiceTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
1056                 getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""), 5, String.format("%s:%d", "TST Flow Entry ", serviceId),
1057                 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, customInstructions);
1058
1059         mdsalManager.installFlow(dpnId, terminatingServiceTableFlowEntity);
1060     }
1061
1062     protected InstanceIdentifier<RouterIds> getRoutersIdentifier(long routerId) {
1063         InstanceIdentifier<RouterIds> id = InstanceIdentifier.builder(
1064                 RouterIdName.class).child(RouterIds.class, new RouterIdsKey(routerId)).build();
1065         return id;
1066     }
1067
1068     private String getFlowRef(BigInteger dpnId, short tableId, long id, String ipAddress) {
1069         return new StringBuilder(64).append(NatConstants.SNAT_FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
1070                 .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
1071                 .append(id).append(NwConstants.FLOWID_SEPARATOR).append(ipAddress).toString();
1072     }
1073
1074     @Override
1075     protected void update(InstanceIdentifier<Routers> identifier, Routers original, Routers update) {
1076         String routerName = original.getRouterName();
1077         Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1078         BigInteger dpnId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
1079         Uuid networkId = original.getNetworkId();
1080
1081         // Check if its update on SNAT flag
1082         boolean originalSNATEnabled = original.isEnableSnat();
1083         boolean updatedSNATEnabled = update.isEnableSnat();
1084         LOG.debug("NAT Service : update of externalRoutersListener called with originalFlag and updatedFlag as {} and {}", originalSNATEnabled, updatedSNATEnabled);
1085         if(originalSNATEnabled != updatedSNATEnabled) {
1086             if(originalSNATEnabled) {
1087                 //SNAT disabled for the router
1088                 Uuid networkUuid = original.getNetworkId();
1089                 LOG.info("NAT Service : SNAT disabled for Router {}", routerName);
1090                 if (routerId == NatConstants.INVALID_ID) {
1091                     LOG.error("NAT Service : Invalid routerId returned for routerName {}", routerName);
1092                     return;
1093                 }
1094                 List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker,routerId);
1095                 handleDisableSnat(routerName, networkUuid, externalIps, false, null);
1096             } else {
1097                 LOG.info("NAT Service : SNAT enabled for Router {}", original.getRouterName());
1098                 handleEnableSnat(original);
1099             }
1100         }
1101
1102         //Check if the Update is on External IPs
1103         LOG.debug("NAT Service : Checking if this is update on External IPs");
1104         List<String> originalExternalIpsList = original.getExternalIps();
1105         List<String> updatedExternalIpsList = update.getExternalIps();
1106         Set<String> originalExternalIps = Sets.newHashSet(originalExternalIpsList);
1107         Set<String> updatedExternalIps = Sets.newHashSet(updatedExternalIpsList);
1108
1109         //Check if the External IPs are added during the update.
1110         SetView<String> addedExternalIps = Sets.difference(updatedExternalIps, originalExternalIps);
1111         if(addedExternalIps.size() != 0) {
1112             LOG.debug("NAT Service : Start processing of the External IPs addition during the update operation");
1113             for (String addedExternalIp : addedExternalIps) {
1114                 /*
1115                     1) Do nothing in the IntExtIp model.
1116                     2) Initialise the count of the added external IP to 0 in the ExternalCounter model.
1117                 */
1118                 String[] externalIpParts = NatUtil.getExternalIpAndPrefix(addedExternalIp);
1119                 String externalIp = externalIpParts[0];
1120                 String externalIpPrefix = externalIpParts[1];
1121                 String externalpStr = externalIp + "/" + externalIpPrefix;
1122                 LOG.debug("NAT Service : Initialise the count mapping of the external IP {} for the router ID {} in the ExternalIpsCounter model.",
1123                         externalpStr, routerId);
1124                 naptManager.initialiseNewExternalIpCounter(routerId, externalpStr);
1125             }
1126             LOG.debug("NAT Service : End processing of the External IPs addition during the update operation");
1127         }
1128
1129         //Check if the External IPs are removed during the update.
1130         SetView<String> removedExternalIps = Sets.difference(originalExternalIps, updatedExternalIps);
1131         if(removedExternalIps.size() > 0) {
1132             LOG.debug("NAT Service : Start processing of the External IPs removal during the update operation");
1133             List<String> removedExternalIpsAsList = new ArrayList<>();
1134             for (String removedExternalIp : removedExternalIps) {
1135              /*
1136                 1) Remove the mappings in the IntExt IP model which has external IP.
1137                 2) Remove the external IP in the ExternalCounter model.
1138                 3) For the corresponding subnet IDs whose external IP mapping was removed, allocate one of the least loaded external IP.
1139                    Store the subnet IP and the reallocated external IP mapping in the IntExtIp model.
1140                 4) Increase the count of the allocated external IP by one.
1141                 5) Advertise to the BGP if external IP is allocated for the first time for the router i.e. the route for the external IP is absent.
1142                 6) Remove the NAPT translation entries from Inbound and Outbound NAPT tables for the removed external IPs and also from the model.
1143                 7) Advertise to the BGP for removing the route for the removed external IPs.
1144               */
1145
1146                 String[] externalIpParts = NatUtil.getExternalIpAndPrefix(removedExternalIp);
1147                 String externalIp = externalIpParts[0];
1148                 String externalIpPrefix = externalIpParts[1];
1149                 String externalIpAddrStr = externalIp + "/" + externalIpPrefix;
1150
1151                 LOG.debug("NAT Service : Clear the routes from the BGP and remove the FIB and TS entries for removed external IP {}", externalIpAddrStr);
1152                 Uuid vpnUuId = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
1153                 String vpnName = "";
1154                 if(vpnUuId != null){
1155                     vpnName = vpnUuId.getValue();
1156                 }
1157                 clrRtsFromBgpAndDelFibTs(dpnId, routerId, externalIpAddrStr, vpnName);
1158
1159                 LOG.debug("NAT Service : Remove the mappings in the IntExtIP model which has external IP.");
1160                 //Get the internal IPs which are associated to the removed external IPs
1161                 List<IpMap> ipMaps = naptManager.getIpMapList(dataBroker, routerId);
1162                 List<String> removedInternalIps = new ArrayList<>();
1163                 for(IpMap ipMap : ipMaps){
1164                     if(ipMap.getExternalIp().equals(externalIpAddrStr)){
1165                         removedInternalIps.add(ipMap.getInternalIp());
1166                     }
1167                 }
1168
1169                 LOG.debug("Remove the mappings of the internal IPs from the IntExtIP model.");
1170                 for(String removedInternalIp : removedInternalIps){
1171                     LOG.debug("NAT Service : Remove the IP mapping of the internal IP {} for the router ID {} from the IntExtIP model",
1172                             removedInternalIp, routerId);
1173                     naptManager.removeFromIpMapDS(routerId, removedInternalIp);
1174                 }
1175
1176                 LOG.debug("NAT Service : Remove the count mapping of the external IP {} for the router ID {} from the ExternalIpsCounter model.",
1177                         externalIpAddrStr, routerId );
1178                 naptManager.removeExternalIpCounter(routerId, externalIpAddrStr);
1179                 removedExternalIpsAsList.add(externalIpAddrStr);
1180
1181                 LOG.debug("NAT Service : Allocate the least loaded external IPs to the subnets whose external IPs were removed.");
1182                 for(String removedInternalIp : removedInternalIps) {
1183                     allocateExternalIp(dpnId, routerId, networkId, removedInternalIp);
1184                 }
1185
1186                 LOG.debug("NAT Service : Remove the NAPT translation entries from Inbound and Outbound NAPT tables for the removed external IPs.");
1187                 //Get the internalIP and internal Port which were associated to the removed external IP.
1188                 List<Integer> externalPorts = new ArrayList<>();
1189                 Map<ProtocolTypes, List<String>> protoTypesIntIpPortsMap = new HashMap<>();
1190                 InstanceIdentifier<IpPortMapping> ipPortMappingId = InstanceIdentifier.builder(IntextIpPortMap.class)
1191                         .child(IpPortMapping.class, new IpPortMappingKey(routerId)).build();
1192                 Optional<IpPortMapping> ipPortMapping = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, ipPortMappingId);
1193                 if (ipPortMapping.isPresent()) {
1194                     List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.get().getIntextIpProtocolType();
1195                     for(IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes){
1196                         ProtocolTypes protoType = intextIpProtocolType.getProtocol();
1197                         List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
1198                         for(IpPortMap ipPortMap : ipPortMaps){
1199                             IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
1200                             if(ipPortExternal.getIpAddress().equals(externalIp)){
1201                                 externalPorts.add(ipPortExternal.getPortNum());
1202                                 List<String> removedInternalIpPorts = protoTypesIntIpPortsMap.get(protoType);
1203                                 if(removedInternalIpPorts != null){
1204                                     removedInternalIpPorts.add(ipPortMap.getIpPortInternal());
1205                                     protoTypesIntIpPortsMap.put(protoType, removedInternalIpPorts);
1206                                 }else{
1207                                     removedInternalIpPorts = new ArrayList<>();
1208                                     removedInternalIpPorts.add(ipPortMap.getIpPortInternal());
1209                                     protoTypesIntIpPortsMap.put(protoType, removedInternalIpPorts);
1210                                 }
1211                             }
1212                         }
1213                     }
1214                 }
1215
1216                 //Remove the IP port map from the intext-ip-port-map model, which were containing the removed external IP.
1217                 Set<Map.Entry<ProtocolTypes, List<String>>> protoTypesIntIpPorts = protoTypesIntIpPortsMap.entrySet();
1218                 Map<String, List<String>> internalIpPortMap = new HashMap<>();
1219                 for(Map.Entry protoTypesIntIpPort : protoTypesIntIpPorts){
1220                     ProtocolTypes protocolType = (ProtocolTypes)protoTypesIntIpPort.getKey();
1221                     List<String> removedInternalIpPorts = (List<String>)protoTypesIntIpPort.getValue();
1222                     for(String removedInternalIpPort : removedInternalIpPorts){
1223                         //Remove the IP port map from the intext-ip-port-map model, which were containing the removed external IP
1224                         naptManager.removeFromIpPortMapDS(routerId, removedInternalIpPort, protocolType);
1225                         //Remove the IP port incomint packer map.
1226                         naptPacketInHandler.removeIncomingPacketMap(removedInternalIpPort);
1227                         String[] removedInternalIpPortParts = removedInternalIpPort.split(":");
1228                         if(removedInternalIpPortParts.length == 2){
1229                             String removedInternalIp = removedInternalIpPortParts[0];
1230                             String removedInternalPort = removedInternalIpPortParts[1];
1231                             List<String> removedInternalPortsList =  internalIpPortMap.get(removedInternalPort);
1232                             if (removedInternalPortsList != null){
1233                                 removedInternalPortsList.add(removedInternalPort);
1234                                 internalIpPortMap.put(removedInternalIp, removedInternalPortsList);
1235                             }else{
1236                                 removedInternalPortsList = new ArrayList<>();
1237                                 removedInternalPortsList.add(removedInternalPort);
1238                                 internalIpPortMap.put(removedInternalIp, removedInternalPortsList);
1239                             }
1240                         }
1241                     }
1242                 }
1243
1244                 // Delete the entry from SnatIntIpPortMap DS
1245                 Set<String> internalIps = internalIpPortMap.keySet();
1246                 for(String internalIp : internalIps){
1247                     LOG.debug("NAT Service : Removing IpPort having the internal IP {} from the model SnatIntIpPortMap", internalIp);
1248                     naptManager.removeFromSnatIpPortDS(routerId, internalIp);
1249                 }
1250
1251                 naptManager.removeNaptPortPool(externalIp);
1252
1253                 LOG.debug("Remove the NAPT translation entries from Inbound NAPT tables for the removed external IP {}", externalIp);
1254                 for(Integer externalPort : externalPorts) {
1255                     //Remove the NAPT translation entries from Inbound NAPT table
1256                     naptEventHandler.removeNatFlows(dpnId, NatConstants.INBOUND_NAPT_TABLE, routerId, externalIp, externalPort);
1257                 }
1258
1259                 Set<Map.Entry<String, List<String>>> internalIpPorts = internalIpPortMap.entrySet();
1260                 for(Map.Entry<String, List<String>> internalIpPort : internalIpPorts) {
1261                     String internalIp = internalIpPort.getKey();
1262                     LOG.debug("Remove the NAPT translation entries from Outbound NAPT tables for the removed internal IP {}", internalIp);
1263                     List<String> internalPorts = internalIpPort.getValue();
1264                     for(String internalPort : internalPorts){
1265                         //Remove the NAPT translation entries from Outbound NAPT table
1266                         naptEventHandler.removeNatFlows(dpnId, NatConstants.OUTBOUND_NAPT_TABLE, routerId, internalIp, Integer.valueOf(internalPort));
1267                     }
1268                 }
1269             }
1270             LOG.debug("NAT Service : End processing of the External IPs removal during the update operation");
1271         }
1272
1273         //Check if its Update on subnets
1274         LOG.debug("NAT Service : Checking if this is update on subnets");
1275         List<Uuid> originalSubnetIdsList = original.getSubnetIds();
1276         List<Uuid> updatedSubnetIdsList = update.getSubnetIds();
1277         Set<Uuid> originalSubnetIds = Sets.newHashSet(originalSubnetIdsList);
1278         Set<Uuid> updatedSubnetIds = Sets.newHashSet(updatedSubnetIdsList);
1279         SetView<Uuid> addedSubnetIds = Sets.difference(updatedSubnetIds, originalSubnetIds);
1280
1281         //Check if the Subnet IDs are added during the update.
1282         if(addedSubnetIds.size() != 0){
1283             LOG.debug("NAT Service : Start processing of the Subnet IDs addition during the update operation");
1284             for(Uuid addedSubnetId : addedSubnetIds){
1285                 /*
1286                 1) Select the least loaded external IP for the subnet and store the mapping of the subnet IP and the external IP in the IntExtIp model.
1287                 2) Increase the count of the selected external IP by one.
1288                 3) Advertise to the BGP if external IP is allocated for the first time for the router i.e. the route for the external IP is absent.
1289                 */
1290                 String subnetIp = NatUtil.getSubnetIp(dataBroker, addedSubnetId);
1291                 if(subnetIp != null) {
1292                     allocateExternalIp(dpnId, routerId, networkId, subnetIp);
1293                 }
1294             }
1295             LOG.debug("NAT Service : End processing of the Subnet IDs addition during the update operation");
1296         }
1297
1298         //Check if the Subnet IDs are removed during the update.
1299         SetView<Uuid> removedSubnetIds = Sets.difference(originalSubnetIds, updatedSubnetIds);
1300         if(removedSubnetIds.size() != 0){
1301             LOG.debug("NAT Service : Start processing of the Subnet IDs removal during the update operation");
1302             for(Uuid removedSubnetId : removedSubnetIds){
1303                 String[] subnetAddr = NatUtil.getSubnetIpAndPrefix(dataBroker, removedSubnetId);
1304                 if(subnetAddr != null){
1305                     /*
1306                     1) Remove the subnet IP and the external IP in the IntExtIp map
1307                     2) Decrease the count of the coresponding external IP by one.
1308                     3) Advertise to the BGP for removing the routes of the corresponding external IP if its not allocated to any other internal IP.
1309                     */
1310
1311                     String externalIp = naptManager.getExternalIpAllocatedForSubnet(routerId, subnetAddr[0] + "/" + subnetAddr[1]);
1312                     if (externalIp == null) {
1313                         LOG.debug("No mapping found for router ID {} and internal IP {}", routerId, subnetAddr[0]);
1314                         return;
1315                     }
1316
1317                     naptManager.updateCounter(routerId, externalIp, false);
1318                     //Traverse entire model of external-ip counter whether external ip is not used by any other internal ip in any router
1319                     if (!isExternalIpAllocated(externalIp)) {
1320                         LOG.debug("NAT Service : external ip is not allocated to any other internal IP so proceeding to remove routes");
1321                         List<String> externalIps = new ArrayList<>();
1322                         externalIps.add(externalIp);
1323                         clrRtsFromBgpAndDelFibTs(dpnId, routerId, networkId, externalIps, null);
1324                         LOG.debug("Successfully removed fib entries in switch {} for router {} with networkId {} and externalIps {}",
1325                                 dpnId,routerId,networkId,externalIps);
1326                     }
1327
1328                     LOG.debug("NAT Service : Remove the IP mapping for the router ID {} and internal IP {} external IP {}", routerId, subnetAddr[0],externalIp);
1329                     naptManager.removeIntExtIpMapDS(routerId, subnetAddr[0] + "/" + subnetAddr[1]);
1330                 }
1331             }
1332             LOG.debug("NAT Service : End processing of the Subnet IDs removal during the update operation");
1333         }
1334     }
1335     
1336     private boolean isExternalIpAllocated(String externalIp) {
1337         InstanceIdentifier<ExternalIpsCounter> id = InstanceIdentifier.builder(ExternalIpsCounter.class).build();
1338         Optional <ExternalIpsCounter> externalCountersData = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
1339         if (externalCountersData.isPresent()) {
1340             ExternalIpsCounter externalIpsCounters = externalCountersData.get();
1341             List<ExternalCounters> externalCounters = externalIpsCounters.getExternalCounters();
1342             for(ExternalCounters ext : externalCounters) {
1343                 for (ExternalIpCounter externalIpCount : ext.getExternalIpCounter()) {
1344                     if (externalIpCount.getExternalIp().equals(externalIp)) {
1345                         if (externalIpCount.getCounter() != 0) {
1346                             return true;
1347                         }
1348                         break;
1349                     }
1350                 }
1351             }
1352         }
1353         return false;
1354     }
1355
1356     private void allocateExternalIp(BigInteger dpnId, long routerId, Uuid networkId, String subnetIp){
1357         String leastLoadedExtIpAddr = NatUtil.getLeastLoadedExternalIp(dataBroker, routerId);
1358         if (leastLoadedExtIpAddr != null) {
1359             String[] externalIpParts = NatUtil.getExternalIpAndPrefix(leastLoadedExtIpAddr);
1360             String leastLoadedExtIp = externalIpParts[0];
1361             String leastLoadedExtIpPrefix = externalIpParts[1];
1362             String leastLoadedExtIpAddrStr = leastLoadedExtIp + "/" + leastLoadedExtIpPrefix;
1363             IPAddress externalIpAddr = new IPAddress(leastLoadedExtIp, Integer.parseInt(leastLoadedExtIpPrefix));
1364             String[] subnetIpParts = NatUtil.getSubnetIpAndPrefix(subnetIp);
1365             subnetIp = subnetIpParts[0];
1366             String subnetIpPrefix = subnetIpParts[1];
1367             IPAddress subnetIpAddr = new IPAddress(subnetIp, Integer.parseInt(subnetIpPrefix));
1368             LOG.debug("NAT Service : Add the IP mapping for the router ID {} and internal IP {} and prefix {} -> external IP {} and prefix {}",
1369                     routerId, subnetIp, subnetIpPrefix, leastLoadedExtIp, leastLoadedExtIpPrefix);
1370             naptManager.registerMapping(routerId, subnetIpAddr, externalIpAddr);
1371
1372
1373             //Check if external IP is already assigned a route. (i.e. External IP is previously allocated to any of the subnets)
1374             //If external IP is already assigned a route, (, do not re-advertise to the BGP
1375             Long label = checkExternalIpLabel(routerId, leastLoadedExtIpAddrStr);
1376             if(label != null){
1377                 //update
1378                 String internalIp = subnetIpParts[0] + "/" + subnetIpParts[1];
1379                 IpMapKey ipMapKey = new IpMapKey(internalIp);
1380                 LOG.debug("Setting label {} for internalIp {} and externalIp {}", label, internalIp, leastLoadedExtIpAddrStr);
1381                 IpMap newIpm = new IpMapBuilder().setKey(ipMapKey).setInternalIp(internalIp).setExternalIp(leastLoadedExtIpAddrStr).setLabel(label).build();
1382                 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, naptManager.getIpMapIdentifier(routerId, internalIp), newIpm);
1383                 return;
1384             }
1385
1386             //Re-advertise to the BGP for the external IP, which is allocated to the subnet for the first time and hence not having a route.
1387             //Get the VPN Name using the network ID
1388             final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
1389             if (vpnName != null) {
1390                 LOG.debug("Retrieved vpnName {} for networkId {}", vpnName, networkId);
1391                 if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
1392                     LOG.debug("Best effort for getting primary napt switch when router i/f are added after gateway-set");
1393                     dpnId = NatUtil.getPrimaryNaptfromRouterId(dataBroker,routerId);
1394                 }
1395                 advToBgpAndInstallFibAndTsFlows(dpnId, NatConstants.INBOUND_NAPT_TABLE, vpnName, routerId,
1396                         leastLoadedExtIp + "/" + leastLoadedExtIpPrefix, vpnService, fibService, bgpManager, dataBroker, LOG);
1397             }
1398         }
1399     }
1400
1401     private Long checkExternalIpLabel(long routerId, String externalIp){
1402         List<IpMap> ipMaps = naptManager.getIpMapList(dataBroker, routerId);
1403         for(IpMap ipMap : ipMaps){
1404             if(ipMap.getExternalIp().equals(externalIp)){
1405                 if (ipMap.getLabel() != null){
1406                     return ipMap.getLabel();
1407                 }
1408             }
1409         }
1410         return null;
1411     }
1412
1413     @Override
1414     protected void remove(InstanceIdentifier<Routers> identifier, Routers router) {
1415         LOG.trace("NAT Service : Router delete method");
1416         {
1417         /*
1418             ROUTER DELETE SCENARIO
1419             1) Get the router ID from the event.
1420             2) Build the cookie information from the router ID.
1421             3) Get the primary and secondary switch DPN IDs using the router ID from the model.
1422             4) Build the flow with the cookie value.
1423             5) Delete the flows which matches the cookie information from the NAPT outbound, inbound tables.
1424             6) Remove the flows from the other switches which points to the primary and secondary switches for the flows related the router ID.
1425             7) Get the list of external IP address maintained for the router ID.
1426             8) Use the NaptMananager removeMapping API to remove the list of IP addresses maintained.
1427             9) Withdraw the corresponding routes from the BGP.
1428          */
1429
1430             if (identifier == null || router == null) {
1431                 LOG.info("++++++++++++++NAT Service : ExternalRoutersListener:remove:: returning without processing since routers is null");
1432                 return;
1433             }
1434
1435             String routerName = router.getRouterName();
1436             LOG.info("Removing default NAT route from FIB on all dpns part of router {} ", routerName);
1437             addOrDelDefFibRouteToSNAT(routerName, false);
1438             Uuid networkUuid = router.getNetworkId();
1439             Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1440             if (routerId == NatConstants.INVALID_ID) {
1441                 LOG.error("NAT Service : Invalid routerId returned for routerName {}", routerName);
1442                 return;
1443             }
1444             List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
1445             handleDisableSnat(routerName, networkUuid, externalIps, true, null);
1446         }
1447     }
1448
1449     public void handleDisableSnat(String routerName, Uuid networkUuid, List<String> externalIps, boolean routerFlag, String vpnId){
1450         LOG.info("NAT Service : handleDisableSnat() Entry");
1451         try {
1452             Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1453
1454             BigInteger naptSwitchDpnId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
1455             LOG.debug("NAT Service : got primarySwitch as dpnId{} ", naptSwitchDpnId);
1456             if (naptSwitchDpnId == null || naptSwitchDpnId.equals(BigInteger.ZERO)){
1457                 LOG.error("NAT Service : Unable to retrieve the primary NAPT switch for the router ID {} from RouterNaptSwitch model", routerId);
1458                 return;
1459             }
1460             removeNaptFlowsFromActiveSwitch(routerId, routerName, naptSwitchDpnId, networkUuid, vpnId );
1461             removeFlowsFromNonActiveSwitches(routerName, naptSwitchDpnId, networkUuid);
1462             try {
1463                 clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, vpnId);
1464             } catch (Exception ex) {
1465                 LOG.debug("Failed to remove fib entries for routerId {} in naptSwitchDpnId {} : {}", routerId, naptSwitchDpnId,ex);
1466             }
1467
1468             //Use the NaptMananager removeMapping API to remove the entire list of IP addresses maintained for the router ID.
1469             LOG.debug("NAT Service : Remove the Internal to external IP address maintained for the router ID {} in the DS", routerId);
1470             naptManager.removeMapping(routerId);
1471
1472             if(routerFlag) {
1473                 removeNaptSwitch(routerName);
1474             } else {
1475                 updateNaptSwitch(routerName, BigInteger.ZERO);
1476             }
1477
1478             LOG.debug("NAT Service : Remove the ExternalCounter model for the router ID {}", routerId);
1479             naptManager.removeExternalCounter(routerId);
1480         } catch (Exception ex) {
1481             LOG.error("Exception while handling disableSNAT : {}", ex);
1482         }
1483         LOG.info("NAT Service : handleDisableSnat() Exit");
1484     }
1485
1486     public void handleDisableSnatInternetVpn(String routerName, Uuid networkUuid, List<String> externalIps, boolean routerFlag, String vpnId){
1487         LOG.debug("NAT Service : handleDisableSnatInternetVpn() Entry");
1488         try {
1489             Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1490             BigInteger naptSwitchDpnId = null;
1491             InstanceIdentifier<RouterToNaptSwitch> routerToNaptSwitch = NatUtil.buildNaptSwitchRouterIdentifier(routerName);
1492             Optional<RouterToNaptSwitch> rtrToNapt = read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerToNaptSwitch);
1493             if (rtrToNapt.isPresent()) {
1494                 naptSwitchDpnId = rtrToNapt.get().getPrimarySwitchId();
1495             }
1496             LOG.debug("NAT Service : got primarySwitch as dpnId{} ", naptSwitchDpnId);
1497
1498             removeNaptFlowsFromActiveSwitchInternetVpn(routerId, routerName, naptSwitchDpnId, networkUuid, vpnId );
1499             try {
1500                 clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, vpnId);
1501             } catch (Exception ex) {
1502                 LOG.debug("Failed to remove fib entries for routerId {} in naptSwitchDpnId {} : {}", routerId, naptSwitchDpnId,ex);
1503             }
1504           } catch (Exception ex) {
1505             LOG.error("Exception while handling disableSNATInternetVpn : {}", ex);
1506         }
1507         LOG.debug("NAT Service : handleDisableSnatInternetVpn() Exit");
1508     }
1509
1510     public void updateNaptSwitch(String routerName, BigInteger naptSwitchId) {
1511         RouterToNaptSwitch naptSwitch = new RouterToNaptSwitchBuilder().setKey(new RouterToNaptSwitchKey(routerName))
1512                 .setPrimarySwitchId(naptSwitchId).build();
1513         try {
1514             MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
1515                     NatUtil.buildNaptSwitchRouterIdentifier(routerName), naptSwitch);
1516         } catch (Exception ex) {
1517             LOG.error("Failed to write naptSwitch {} for router {} in ds",
1518                     naptSwitchId,routerName);
1519         }
1520         LOG.debug("Successfully updated naptSwitch {} for router {} in ds",
1521                 naptSwitchId,routerName);
1522     }
1523
1524     protected void removeNaptSwitch(String routerName){
1525         // Remove router and switch from model
1526         InstanceIdentifier<RouterToNaptSwitch> id = InstanceIdentifier.builder(NaptSwitches.class).child(RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();
1527         LOG.debug("NAPT Service : Removing NaptSwitch and Router for the router {} from datastore", routerName);
1528         MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1529     }
1530
1531      public void removeNaptFlowsFromActiveSwitch(long routerId, String routerName, BigInteger dpnId, Uuid networkId, String vpnName){
1532
1533         LOG.debug("NAT Service : Remove NAPT flows from Active switch");
1534         BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
1535
1536         //Remove the PSNAT entry which forwards the packet to Outbound NAPT Table (For the
1537         // traffic which comes from the  VMs of the NAPT switches)
1538         String pSNatFlowRef = getFlowRefSnat(dpnId, NatConstants.PSNAT_TABLE, routerName);
1539         FlowEntity pSNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.PSNAT_TABLE, pSNatFlowRef);
1540
1541         LOG.info("NAT Service : Remove the flow in the " + NatConstants.PSNAT_TABLE + " for the active switch with the DPN ID {} and router ID {}", dpnId, routerId);
1542         mdsalManager.removeFlow(pSNatFlowEntity);
1543
1544         //Remove the Terminating Service table entry which forwards the packet to Outbound NAPT Table (For the
1545         // traffic which comes from the VMs of the non NAPT switches)
1546         String tsFlowRef = getFlowRefTs(dpnId, NatConstants.TERMINATING_SERVICE_TABLE, routerId);
1547         FlowEntity tsNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.TERMINATING_SERVICE_TABLE, tsFlowRef);
1548
1549         LOG.info("NAT Service : Remove the flow in the " + NatConstants.TERMINATING_SERVICE_TABLE + " for the active switch with the DPN ID {} and router ID {}", dpnId, routerId);
1550         mdsalManager.removeFlow(tsNatFlowEntity);
1551
1552         //Remove the Outbound flow entry which forwards the packet to FIB Table
1553         String outboundNatFlowRef = getFlowRefOutbound(dpnId, NatConstants.OUTBOUND_NAPT_TABLE, routerId);
1554         FlowEntity outboundNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.OUTBOUND_NAPT_TABLE, outboundNatFlowRef);
1555
1556         LOG.info("NAT Service : Remove the flow in the " + NatConstants.OUTBOUND_NAPT_TABLE + " for the active switch with the DPN ID {} and router ID {}", dpnId, routerId);
1557         mdsalManager.removeFlow(outboundNatFlowEntity);
1558
1559         //Remove the NAPT PFIB TABLE which forwards the incoming packet to FIB Table matching on the router ID.
1560         String natPfibFlowRef = getFlowRefTs(dpnId, NatConstants.NAPT_PFIB_TABLE, routerId);
1561         FlowEntity natPfibFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.NAPT_PFIB_TABLE, natPfibFlowRef);
1562
1563         LOG.info("NAT Service : Remove the flow in the " + NatConstants.NAPT_PFIB_TABLE + " for the active switch with the DPN ID {} and router ID {}", dpnId, routerId);
1564         mdsalManager.removeFlow(natPfibFlowEntity);
1565
1566         //Long vpnId = NatUtil.getVpnId(dataBroker, routerId); - This does not work since ext-routers is deleted already - no network info
1567         //Get the VPN ID from the ExternalNetworks model
1568         long vpnId = -1;
1569         if( (vpnName == null) || (vpnName.isEmpty()) ) {
1570             // ie called from router delete cases
1571             Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
1572             LOG.debug("NAT Service : vpnUuid is {}", vpnUuid);
1573             if(vpnUuid != null) {
1574                 vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
1575                 LOG.debug("NAT Service : vpnId for routerdelete or disableSNAT scenario {}", vpnId );
1576             }
1577         } else {
1578             // ie called from disassociate vpn case
1579             LOG.debug("NAT Service: This is disassociate nw with vpn case with vpnName {}", vpnName);
1580             vpnId = NatUtil.getVpnId(dataBroker, vpnName);
1581             LOG.debug("NAT Service : vpnId for disassociate nw with vpn scenario {}", vpnId );
1582         }
1583
1584         if(vpnId != NatConstants.INVALID_ID){
1585            //Remove the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
1586            String natPfibVpnFlowRef = getFlowRefTs(dpnId, NatConstants.NAPT_PFIB_TABLE, vpnId);
1587            FlowEntity natPfibVpnFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.NAPT_PFIB_TABLE, natPfibVpnFlowRef);
1588            LOG.info("NAT Service : Remove the flow in the " + NatConstants.NAPT_PFIB_TABLE + " for the active switch with the DPN ID {} and VPN ID {}", dpnId, vpnId);
1589            mdsalManager.removeFlow(natPfibVpnFlowEntity);
1590         }
1591
1592         //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
1593         IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
1594         if(ipPortMapping == null){
1595             LOG.error("NAT Service : Unable to retrieve the IpPortMapping");
1596             return;
1597         }
1598
1599         List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
1600         for(IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes){
1601             List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
1602             for(IpPortMap ipPortMap : ipPortMaps){
1603                 String ipPortInternal = ipPortMap.getIpPortInternal();
1604                 String[] ipPortParts = ipPortInternal.split(":");
1605                 if(ipPortParts.length != 2) {
1606                     LOG.error("NAT Service : Unable to retrieve the Internal IP and port");
1607                     return;
1608                 }
1609                 String internalIp = ipPortParts[0];
1610                 String internalPort = ipPortParts[1];
1611
1612                 //Build the flow for the outbound NAPT table
1613                 String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NatConstants.OUTBOUND_NAPT_TABLE, String.valueOf(routerId), internalIp, Integer.valueOf(internalPort));
1614                 FlowEntity outboundNaptFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.OUTBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
1615
1616                 LOG.info("NAT Service : Remove the flow in the " + NatConstants.OUTBOUND_NAPT_TABLE + " for the active switch with the DPN ID {} and router ID {}", dpnId, routerId);
1617                 mdsalManager.removeFlow(outboundNaptFlowEntity);
1618
1619                 IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
1620                 String externalIp = ipPortExternal.getIpAddress();
1621                 int externalPort = ipPortExternal.getPortNum();
1622
1623                 //Build the flow for the inbound NAPT table
1624                 switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NatConstants.INBOUND_NAPT_TABLE, String.valueOf(routerId), externalIp, externalPort);
1625                 FlowEntity inboundNaptFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.INBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
1626
1627                 LOG.info("NAT Service : Remove the flow in the " + NatConstants.INBOUND_NAPT_TABLE + " for the active active switch with the DPN ID {} and router ID {}", dpnId, routerId);
1628                 mdsalManager.removeFlow(inboundNaptFlowEntity);
1629             }
1630         }
1631     }
1632
1633      public void removeNaptFlowsFromActiveSwitchInternetVpn(long routerId, String routerName, BigInteger dpnId, Uuid networkId, String vpnName){
1634
1635          LOG.debug("NAT Service : Remove NAPT flows from Active switch Internet Vpn");
1636          BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
1637
1638          //Remove the NAPT PFIB TABLE entry
1639          long vpnId = -1;
1640          if(vpnName != null) {
1641              // ie called from disassociate vpn case
1642              LOG.debug("NAT Service: This is disassociate nw with vpn case with vpnName {}", vpnName);
1643              vpnId = NatUtil.getVpnId(dataBroker, vpnName);
1644              LOG.debug("NAT Service : vpnId for disassociate nw with vpn scenario {}", vpnId );
1645          }
1646
1647          if(vpnId != NatConstants.INVALID_ID){
1648             //Remove the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
1649             String natPfibVpnFlowRef = getFlowRefTs(dpnId, NatConstants.NAPT_PFIB_TABLE, vpnId);
1650             FlowEntity natPfibVpnFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.NAPT_PFIB_TABLE, natPfibVpnFlowRef);
1651             LOG.info("NAT Service : Remove the flow in the " + NatConstants.NAPT_PFIB_TABLE + " for the active switch with the DPN ID {} and VPN ID {}", dpnId, vpnId);
1652             mdsalManager.removeFlow(natPfibVpnFlowEntity);
1653
1654              // Remove IP-PORT active NAPT entries and release port from IdManager
1655              //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
1656              IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
1657              if(ipPortMapping == null){
1658                  LOG.error("NAT Service : Unable to retrieve the IpPortMapping");
1659                  return;
1660              }
1661              List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
1662              for(IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes){
1663                  List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
1664                  for(IpPortMap ipPortMap : ipPortMaps){
1665                      String ipPortInternal = ipPortMap.getIpPortInternal();
1666                      String[] ipPortParts = ipPortInternal.split(":");
1667                      if(ipPortParts.length != 2) {
1668                          LOG.error("NAT Service : Unable to retrieve the Internal IP and port");
1669                          return;
1670                      }
1671                      String internalIp = ipPortParts[0];
1672                      String internalPort = ipPortParts[1];
1673
1674                      //Build the flow for the outbound NAPT table
1675                      String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NatConstants.OUTBOUND_NAPT_TABLE, String.valueOf(routerId), internalIp, Integer.valueOf(internalPort));
1676                      FlowEntity outboundNaptFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.OUTBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
1677
1678                      LOG.info("NAT Service : Remove the flow in the " + NatConstants.OUTBOUND_NAPT_TABLE + " for the active switch with the DPN ID {} and router ID {}", dpnId, routerId);
1679                      mdsalManager.removeFlow(outboundNaptFlowEntity);
1680
1681                      IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
1682                      String externalIp = ipPortExternal.getIpAddress();
1683                      int externalPort = ipPortExternal.getPortNum();
1684
1685                      //Build the flow for the inbound NAPT table
1686                      switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NatConstants.INBOUND_NAPT_TABLE, String.valueOf(routerId), externalIp, externalPort);
1687                      FlowEntity inboundNaptFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.INBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
1688
1689                      LOG.info("NAT Service : Remove the flow in the " + NatConstants.INBOUND_NAPT_TABLE + " for the active active switch with the DPN ID {} and router ID {}", dpnId, routerId);
1690                      mdsalManager.removeFlow(inboundNaptFlowEntity);
1691
1692                      // Finally release port from idmanager
1693                      String internalIpPort = internalIp +":"+internalPort;
1694                      naptManager.removePortFromPool(internalIpPort, externalIp);
1695
1696                      //Remove sessions from models
1697                      naptManager.removeIpPortMappingForRouterID(routerId);
1698                      naptManager.removeIntIpPortMappingForRouterID(routerId);
1699                  }
1700              }
1701          } else {
1702              LOG.error("NAT Service : Invalid vpnId {}", vpnId);
1703          }
1704      }
1705
1706     public void removeFlowsFromNonActiveSwitches(String routerName, BigInteger naptSwitchDpnId, Uuid networkId){
1707         LOG.debug("NAT Service : Remove NAPT related flows from non active switches");
1708
1709         //Remove the flows from the other switches which points to the primary and secondary switches for the flows related the router ID.
1710         List<BigInteger> allSwitchList = naptSwitchSelector.getDpnsForVpn(routerName);
1711         if(allSwitchList == null || allSwitchList.isEmpty()){
1712             LOG.error("NAT Service : Unable to get the swithces for the router {}", routerName);
1713             return;
1714         }
1715         Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1716         for (BigInteger dpnId : allSwitchList) {
1717             if (!naptSwitchDpnId.equals(dpnId)) {
1718                 LOG.info("NAT Service : Handle Ordinary switch");
1719
1720                 //Remove the PSNAT entry which forwards the packet to Terminating Service table
1721                 String pSNatFlowRef = getFlowRefSnat(dpnId, NatConstants.PSNAT_TABLE, String.valueOf(routerName));
1722                 FlowEntity pSNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NatConstants.PSNAT_TABLE, pSNatFlowRef);
1723
1724                 LOG.info("Remove the flow in the " + NatConstants.PSNAT_TABLE + " for the non active switch with the DPN ID {} and router ID {}", dpnId, routerId);
1725                 mdsalManager.removeFlow(pSNatFlowEntity);
1726
1727                 //Remove the group entry which forwards the traffic to the out port (VXLAN tunnel).
1728                 long groupId = createGroupId(getGroupIdKey(routerName));
1729                 List<BucketInfo> listBucketInfo = new ArrayList<>();
1730                 GroupEntity pSNatGroupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, listBucketInfo);
1731
1732                 LOG.info("NAT Service : Remove the group {} for the non active switch with the DPN ID {} and router ID {}", groupId, dpnId, routerId);
1733                 mdsalManager.removeGroup(pSNatGroupEntity);
1734
1735             }
1736         }
1737     }
1738
1739     public void clrRtsFromBgpAndDelFibTs(final BigInteger dpnId, Long routerId, Uuid networkUuid, List<String> externalIps, String vpnName) {
1740         //Withdraw the corresponding routes from the BGP.
1741         //Get the network ID using the router ID.
1742         LOG.debug("NAT Service : Advertise to BGP and remove routes for externalIps {} with routerId {}, network Id {} and vpnName {}",
1743                 externalIps,routerId,networkUuid, vpnName);
1744         if(networkUuid == null ){
1745             LOG.error("NAT Service : networkId is null");
1746             return;
1747         }
1748
1749         if (externalIps == null || externalIps.isEmpty()) {
1750             LOG.debug("NAT Service : externalIps is null");
1751             return;
1752         }
1753
1754         if(vpnName ==null) {
1755             //Get the VPN Name using the network ID
1756             vpnName = NatUtil.getAssociatedVPN(dataBroker, networkUuid, LOG);
1757             if (vpnName == null) {
1758                 LOG.error("No VPN associated with ext nw {} for the router {}",
1759                         networkUuid, routerId);
1760                 return;
1761             }
1762         }
1763         LOG.debug("Retrieved vpnName {} for networkId {}",vpnName,networkUuid);
1764
1765         //Remove custom FIB routes
1766         //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
1767         for (String extIp : externalIps) {
1768             clrRtsFromBgpAndDelFibTs(dpnId, routerId, extIp, vpnName);
1769         }
1770     }
1771
1772     protected void clrRtsFromBgpAndDelFibTs(final BigInteger dpnId, long routerId, String extIp, final String vpnName) {
1773         clearBgpRoutes(extIp,vpnName);
1774         delFibTsAndReverseTraffic(dpnId,routerId,extIp,vpnName);
1775     }
1776
1777     protected void delFibTsAndReverseTraffic(final BigInteger dpnId, long routerId, String extIp, final String vpnName,long tempLabel) {
1778         LOG.debug("Removing fib entry for externalIp {} in routerId {}",extIp,routerId);
1779
1780         if (tempLabel < 0 || tempLabel == NatConstants.INVALID_ID) {
1781             LOG.error("NAT Service : Label not found for externalIp {} with router id {}",extIp,routerId);
1782             return;
1783         }
1784
1785         final long label = tempLabel;
1786         final String externalIp = extIp;
1787
1788         RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName).setSourceDpid(dpnId).setIpAddress(externalIp).setServiceId(label).build();
1789         Future<RpcResult<Void>> future = fibService.removeFibEntry(input);
1790
1791         ListenableFuture<RpcResult<Void>> labelFuture = Futures.transform(JdkFutureAdapters.listenInPoolThread(future), new AsyncFunction<RpcResult<Void>, RpcResult<Void>>() {
1792
1793             @Override
1794             public ListenableFuture<RpcResult<Void>> apply(RpcResult<Void> result) throws Exception {
1795                 //Release label
1796                 if (result.isSuccessful()) {
1797                     removeTunnelTableEntry(dpnId, label);
1798                     removeLFibTableEntry(dpnId, label);
1799                     RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder().setVpnName(vpnName).setIpPrefix(externalIp).build();
1800                     Future<RpcResult<Void>> labelFuture = vpnService.removeVpnLabel(labelInput);
1801                     return JdkFutureAdapters.listenInPoolThread(labelFuture);
1802                 } else {
1803                     String errMsg = String.format("RPC call to remove custom FIB entries on dpn %s for prefix %s Failed - %s", dpnId, externalIp, result.getErrors());
1804                     LOG.error(errMsg);
1805                     return Futures.immediateFailedFuture(new RuntimeException(errMsg));
1806                 }
1807             }
1808
1809         });
1810
1811         Futures.addCallback(labelFuture, new FutureCallback<RpcResult<Void>>() {
1812
1813             @Override
1814             public void onFailure(Throwable error) {
1815                 LOG.error("NAT Service : Error in removing the label or custom fib entries", error);
1816             }
1817
1818             @Override
1819             public void onSuccess(RpcResult<Void> result) {
1820                 if (result.isSuccessful()) {
1821                     LOG.debug("NAT Service : Successfully removed the label for the prefix {} from VPN {}", externalIp, vpnName);
1822                 } else {
1823                     LOG.error("NAT Service : Error in removing the label for prefix {} from VPN {}, {}", externalIp, vpnName, result.getErrors());
1824                 }
1825             }
1826         });
1827     }
1828
1829     private void delFibTsAndReverseTraffic(final BigInteger dpnId, long routerId, String extIp, final String vpnName) {
1830         LOG.debug("Removing fib entry for externalIp {} in routerId {}",extIp,routerId);
1831         //Get IPMaps from the DB for the router ID
1832         List<IpMap> dbIpMaps = NaptManager.getIpMapList(dataBroker, routerId);
1833         if (dbIpMaps == null || dbIpMaps.isEmpty()) {
1834             LOG.error("NAT Service : IPMaps not found for router {}",routerId);
1835             return;
1836         }
1837
1838         long tempLabel = NatConstants.INVALID_ID;
1839         for (IpMap dbIpMap : dbIpMaps) {
1840             String dbExternalIp = dbIpMap.getExternalIp();
1841             LOG.debug("Retrieved dbExternalIp {} for router id {}",dbExternalIp,routerId);
1842             //Select the IPMap, whose external IP is the IP for which FIB is installed
1843             if (extIp.equals(dbExternalIp)) {
1844                 tempLabel = dbIpMap.getLabel();
1845                 LOG.debug("Retrieved label {} for dbExternalIp {} with router id {}",tempLabel,dbExternalIp,routerId);
1846                 break;
1847             }
1848         }
1849         if (tempLabel < 0 || tempLabel == NatConstants.INVALID_ID) {
1850             LOG.error("NAT Service : Label not found for externalIp {} with router id {}",extIp,routerId);
1851             return;
1852         }
1853
1854         final long label = tempLabel;
1855         final String externalIp = extIp;
1856
1857         RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName).setSourceDpid(dpnId).setIpAddress(externalIp).setServiceId(label).build();
1858         Future<RpcResult<Void>> future = fibService.removeFibEntry(input);
1859
1860         ListenableFuture<RpcResult<Void>> labelFuture = Futures.transform(JdkFutureAdapters.listenInPoolThread(future), new AsyncFunction<RpcResult<Void>, RpcResult<Void>>() {
1861
1862             @Override
1863             public ListenableFuture<RpcResult<Void>> apply(RpcResult<Void> result) throws Exception {
1864                 //Release label
1865                 if (result.isSuccessful()) {
1866                     removeTunnelTableEntry(dpnId, label);
1867                     removeLFibTableEntry(dpnId, label);
1868                     RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder().setVpnName(vpnName).setIpPrefix(externalIp).build();
1869                     Future<RpcResult<Void>> labelFuture = vpnService.removeVpnLabel(labelInput);
1870                     return JdkFutureAdapters.listenInPoolThread(labelFuture);
1871                 } else {
1872                     String errMsg = String.format("RPC call to remove custom FIB entries on dpn %s for prefix %s Failed - %s", dpnId, externalIp, result.getErrors());
1873                     LOG.error(errMsg);
1874                     return Futures.immediateFailedFuture(new RuntimeException(errMsg));
1875                 }
1876             }
1877
1878         });
1879
1880         Futures.addCallback(labelFuture, new FutureCallback<RpcResult<Void>>() {
1881
1882             @Override
1883             public void onFailure(Throwable error) {
1884                 LOG.error("NAT Service : Error in removing the label or custom fib entries", error);
1885             }
1886
1887             @Override
1888             public void onSuccess(RpcResult<Void> result) {
1889                 if (result.isSuccessful()) {
1890                     LOG.debug("NAT Service : Successfully removed the label for the prefix {} from VPN {}", externalIp, vpnName);
1891                 } else {
1892                     LOG.error("NAT Service : Error in removing the label for prefix {} from VPN {}, {}", externalIp, vpnName, result.getErrors());
1893                 }
1894             }
1895         });
1896     }
1897
1898     protected void clearFibTsAndReverseTraffic(final BigInteger dpnId, Long routerId, Uuid networkUuid, List<String> externalIps, String vpnName) {
1899         //Withdraw the corresponding routes from the BGP.
1900         //Get the network ID using the router ID.
1901         LOG.debug("NAT Service : clearFibTsAndReverseTraffic for externalIps {} with routerId {}, network Id {} and vpnName {}",
1902                 externalIps,routerId,networkUuid, vpnName);
1903         if (networkUuid == null) {
1904             LOG.error("NAT Service : networkId is null");
1905             return;
1906         }
1907
1908         if (externalIps == null || externalIps.isEmpty()) {
1909             LOG.debug("NAT Service : externalIps is null");
1910             return;
1911         }
1912
1913         if (vpnName == null) {
1914             //Get the VPN Name using the network ID
1915             vpnName = NatUtil.getAssociatedVPN(dataBroker, networkUuid, LOG);
1916             if (vpnName == null) {
1917                 LOG.error("No VPN associated with ext nw {} for the router {}",
1918                         networkUuid, routerId);
1919                 return;
1920             }
1921         }
1922         LOG.debug("Retrieved vpnName {} for networkId {}",vpnName,networkUuid);
1923
1924         //Remove custom FIB routes
1925         //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
1926         for (String extIp : externalIps) {
1927             delFibTsAndReverseTraffic(dpnId,routerId,extIp,vpnName);
1928         }
1929     }
1930
1931     protected  void clearBgpRoutes(String externalIp, final String vpnName) {
1932         //Inform BGP about the route removal
1933         LOG.info("Informing BGP to remove route for externalIP {} of vpn {}",externalIp,vpnName);
1934         String rd = NatUtil.getVpnRd(dataBroker, vpnName);
1935         NatUtil.removePrefixFromBGP(bgpManager, rd, externalIp, LOG);
1936     }
1937
1938     private void removeTunnelTableEntry(BigInteger dpnId, long serviceId) {
1939         LOG.info("NAT Service : remove terminatingServiceActions called with DpnId = {} and label = {}", dpnId , serviceId);
1940         List<MatchInfo> mkMatches = new ArrayList<>();
1941         // Matching metadata
1942         mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(serviceId)}));
1943         Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
1944                 getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""),
1945                 5, String.format("%s:%d","TST Flow Entry ",serviceId), 0, 0,
1946                 COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, null);
1947         mdsalManager.removeFlow(dpnId, flowEntity);
1948         LOG.debug("NAT Service : Terminating service Entry for dpID {} : label : {} removed successfully {}",dpnId, serviceId);
1949     }
1950
1951     private void removeLFibTableEntry(BigInteger dpnId, long serviceId) {
1952         List<MatchInfo> matches = new ArrayList<>();
1953         matches.add(new MatchInfo(MatchFieldType.eth_type,
1954                 new long[] { 0x8847L }));
1955         matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(serviceId)}));
1956
1957         String flowRef = getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, serviceId, "");
1958
1959         LOG.debug("NAT Service : removing LFib entry with flow ref {}", flowRef);
1960
1961         Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
1962                 10, flowRef, 0, 0,
1963                 COOKIE_VM_LFIB_TABLE, matches, null);
1964
1965         mdsalManager.removeFlow(dpnId, flowEntity);
1966
1967         LOG.debug("NAT Service : LFIB Entry for dpID : {} label : {} removed successfully {}",dpnId, serviceId);
1968     }
1969
1970     protected InstanceIdentifier<Routers> getWildCardPath()
1971     {
1972         return InstanceIdentifier.create(ExtRouters.class).child(Routers.class);
1973     }
1974
1975
1976     /**
1977      * router association to vpn
1978      *
1979      */
1980     public void changeLocalVpnIdToBgpVpnId(String routerName, String bgpVpnName){
1981         LOG.debug("NAT Service : Router associated to BGP VPN");
1982         if (chkExtRtrAndSnatEnbl(new Uuid(routerName))) {
1983             long bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnName);
1984
1985             LOG.debug("BGP VPN ID value {} ", bgpVpnId);
1986
1987             if(bgpVpnId != NatConstants.INVALID_ID){
1988                 LOG.debug("Populate the router-id-name container with the mapping BGP VPN-ID {} -> BGP VPN-NAME {}", bgpVpnId, bgpVpnName);
1989                 RouterIds rtrs = new RouterIdsBuilder().setKey(new RouterIdsKey(bgpVpnId)).setRouterId(bgpVpnId).setRouterName(bgpVpnName).build();
1990                 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, getRoutersIdentifier(bgpVpnId), rtrs);
1991
1992                 // Get the allocated Primary NAPT Switch for this router
1993                 long routerId = NatUtil.getVpnId(dataBroker, routerName);
1994                 LOG.debug("Router ID value {} ", routerId);
1995                 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
1996
1997                 LOG.debug("NAT Service : Update the Router ID {} to the BGP VPN ID {} ", routerId, bgpVpnId);
1998                 addOrDelDefaultFibRouteForSNATWIthBgpVpn(routerName, bgpVpnId, true);
1999
2000                 // Get the group ID
2001                 long groupId = createGroupId(getGroupIdKey(routerName));
2002                 installFlowsWithUpdatedVpnId(primarySwitchId, routerName, bgpVpnId, routerId, true);
2003             }
2004         }
2005     }
2006
2007     /**
2008      * router disassociation from vpn
2009      *
2010      */
2011     public void changeBgpVpnIdToLocalVpnId(String routerName, String bgpVpnName){
2012         LOG.debug("NAT Service : Router dissociated from BGP VPN");
2013         if(chkExtRtrAndSnatEnbl(new Uuid(routerName))) {
2014             long bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnName);
2015             LOG.debug("BGP VPN ID value {} ", bgpVpnId);
2016
2017             // Get the allocated Primary NAPT Switch for this router
2018             long routerId = NatUtil.getVpnId(dataBroker, routerName);
2019             LOG.debug("Router ID value {} ", routerId);
2020             BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
2021
2022             LOG.debug("NAT Service : Update the BGP VPN ID {} to the Router ID {}", bgpVpnId, routerId);
2023             addOrDelDefaultFibRouteForSNATWIthBgpVpn(routerName, NatConstants.INVALID_ID, true);
2024
2025             // Get the group ID
2026             long groupId = createGroupId(getGroupIdKey(routerName));
2027             installFlowsWithUpdatedVpnId(primarySwitchId, routerName, NatConstants.INVALID_ID, routerId, true);
2028         }
2029     }
2030
2031     boolean chkExtRtrAndSnatEnbl(Uuid routerUuid){
2032         InstanceIdentifier<Routers> routerInstanceIndentifier = InstanceIdentifier.builder(ExtRouters.class).child
2033                 (Routers.class, new RoutersKey(routerUuid.getValue())).build();
2034         Optional<Routers> routerData = read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerInstanceIndentifier);
2035         if (routerData.isPresent() && routerData.get().isEnableSnat()) {
2036             return true;
2037         }
2038         return false;
2039     }
2040
2041     public void installFlowsWithUpdatedVpnId(BigInteger primarySwitchId, String routerName, long bgpVpnId, long
2042             routerId, boolean isSnatCfgd){
2043         long changedVpnId = bgpVpnId;
2044         String logMsg = "NAT Service : Update the BGP VPN ID {}";
2045         if (bgpVpnId == NatConstants.INVALID_ID){
2046             changedVpnId = routerId;
2047             logMsg = "NAT Service : Update the router ID {}";
2048         }
2049
2050         List<BigInteger> switches = NatUtil.getDpnsForRouter(dataBroker, routerName);
2051         if (switches == null || switches.isEmpty()) {
2052             LOG.debug("No switches found for router {}",routerName);
2053             return;
2054         }
2055         for(BigInteger dpnId : switches) {
2056             // Update the BGP VPN ID in the SNAT miss entry to group
2057             if( !dpnId.equals(primarySwitchId) ) {
2058                 LOG.debug("NAT Service : Install group in non NAPT switch {}", dpnId);
2059                 List<BucketInfo> bucketInfoForNonNaptSwitches = getBucketInfoForNonNaptSwitches(dpnId, primarySwitchId, routerName);
2060                 long groupId = createGroupId(getGroupIdKey(routerName));
2061                 if(!isSnatCfgd){
2062                     groupId = installGroup(dpnId, routerName, bucketInfoForNonNaptSwitches);
2063                 }
2064
2065                 LOG.debug(logMsg + " in the SNAT miss entry pointing to group {} in the non NAPT switch {}",
2066                         changedVpnId, groupId, dpnId);
2067                 FlowEntity flowEntity = buildSnatFlowEntityWithUpdatedVpnId(dpnId, routerName, groupId, changedVpnId);
2068                 mdsalManager.installFlow(flowEntity);
2069             }else{
2070
2071                 LOG.debug(logMsg + " in the SNAT miss entry pointing to group {} in the primary switch {}",
2072                         changedVpnId, primarySwitchId);
2073                 FlowEntity flowEntity = buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch(primarySwitchId, routerName, changedVpnId);
2074                 mdsalManager.installFlow(flowEntity);
2075
2076                 LOG.debug(logMsg + " in the Terminating Service table (table ID 36) which forwards the packet" +
2077                         " to the table 46 in the Primary switch {}",  changedVpnId, primarySwitchId);
2078                 installTerminatingServiceTblEntryWithUpdatedVpnId(primarySwitchId, routerName, changedVpnId);
2079
2080                 LOG.debug(logMsg + " in the Outbound NAPT table (table ID 46) which punts the packet to the" +
2081                         " controller in the Primary switch {}", changedVpnId, primarySwitchId);
2082                 createOutboundTblEntryWithBgpVpn(primarySwitchId, routerId, changedVpnId);
2083
2084                 LOG.debug(logMsg + " in the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table in the Primary switch {}",
2085                         changedVpnId, primarySwitchId);
2086                 installNaptPfibEntryWithBgpVpn(primarySwitchId, routerId, changedVpnId);
2087
2088                 LOG.debug(logMsg + " in the NAPT flows for the Outbound NAPT table (table ID 46) and the INBOUND NAPT table (table ID 44)" +
2089                         " in the Primary switch {}", changedVpnId, primarySwitchId);
2090                 updateNaptFlowsWithVpnId(primarySwitchId, routerId, bgpVpnId);
2091
2092                 LOG.debug("NAT Service : Installing SNAT PFIB flow in the primary switch {}", primarySwitchId);
2093                 Long vpnId = NatUtil.getVpnId(dataBroker, routerId);
2094                 //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
2095                 if (vpnId != null && vpnId != NatConstants.INVALID_ID) {
2096                     installNaptPfibEntry(primarySwitchId, vpnId);
2097                 }
2098             }
2099         }
2100     }
2101
2102     public void updateNaptFlowsWithVpnId(BigInteger dpnId, long routerId, long bgpVpnId){
2103         //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
2104         IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
2105         if(ipPortMapping == null){
2106             LOG.error("NAT Service : Unable to retrieve the IpPortMapping");
2107             return;
2108         }
2109
2110         List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
2111         for(IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes){
2112             List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
2113             for(IpPortMap ipPortMap : ipPortMaps){
2114                 String ipPortInternal = ipPortMap.getIpPortInternal();
2115                 String[] ipPortParts = ipPortInternal.split(":");
2116                 if(ipPortParts.length != 2) {
2117                     LOG.error("NAT Service : Unable to retrieve the Internal IP and port");
2118                     return;
2119                 }
2120                 String internalIp = ipPortParts[0];
2121                 String internalPort = ipPortParts[1];
2122
2123                 ProtocolTypes protocolTypes = intextIpProtocolType.getProtocol();
2124                 NAPTEntryEvent.Protocol protocol;
2125                 switch (protocolTypes){
2126                     case TCP:
2127                         protocol = NAPTEntryEvent.Protocol.TCP;
2128                         break;
2129                     case UDP:
2130                         protocol = NAPTEntryEvent.Protocol.UDP;
2131                         break;
2132                     default:
2133                         protocol = NAPTEntryEvent.Protocol.TCP;
2134                 }
2135                 SessionAddress internalAddress = new SessionAddress(internalIp, Integer.valueOf(internalPort));
2136                 SessionAddress externalAddress = naptManager.getExternalAddressMapping(routerId, internalAddress, protocol);
2137                 long internetVpnid = NatUtil.getVpnId(dataBroker, routerId);
2138                 naptEventHandler.buildAndInstallNatFlows(dpnId, NatConstants.OUTBOUND_NAPT_TABLE, internetVpnid, routerId, bgpVpnId,
2139                         internalAddress, externalAddress, protocol);
2140                 naptEventHandler.buildAndInstallNatFlows(dpnId, NatConstants.INBOUND_NAPT_TABLE, internetVpnid, routerId, bgpVpnId,
2141                         externalAddress, internalAddress, protocol);
2142
2143             }
2144         }
2145     }
2146
2147     public FlowEntity buildSnatFlowEntityWithUpdatedVpnId(BigInteger dpId, String routerName, long groupId, long changedVpnId) {
2148
2149         LOG.debug("NAT Service : buildSnatFlowEntity is called for dpId {}, routerName {} groupId {} changed VPN ID {}", dpId, routerName, groupId, changedVpnId );
2150         List<MatchInfo> matches = new ArrayList<>();
2151         matches.add(new MatchInfo(MatchFieldType.eth_type,
2152                 new long[] { 0x0800L }));
2153         matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
2154                 BigInteger.valueOf(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID }));
2155
2156         List<InstructionInfo> instructions = new ArrayList<>();
2157         List<ActionInfo> actionsInfo = new ArrayList<>();
2158
2159         ActionInfo actionSetField = new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {
2160                 BigInteger.valueOf(changedVpnId)}) ;
2161         actionsInfo.add(actionSetField);
2162         LOG.debug("NAT Service : Setting the tunnel to the list of action infos {}", actionsInfo);
2163         actionsInfo.add(new ActionInfo(ActionType.group, new String[] {String.valueOf(groupId)}));
2164         instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfo));
2165         String flowRef = getFlowRefSnat(dpId, NatConstants.PSNAT_TABLE, routerName);
2166         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PSNAT_TABLE, flowRef,
2167                 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
2168                 NatConstants.COOKIE_SNAT_TABLE, matches, instructions);
2169
2170         LOG.debug("NAT Service : Returning SNAT Flow Entity {}", flowEntity);
2171         return flowEntity;
2172     }
2173
2174     public FlowEntity buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch(BigInteger dpId, String routerName, long changedVpnId) {
2175
2176         LOG.debug("NAT Service : buildSnatFlowEntity is called for dpId {}, routerName {} changed VPN ID {}", dpId, routerName, changedVpnId );
2177         List<MatchInfo> matches = new ArrayList<>();
2178         matches.add(new MatchInfo(MatchFieldType.eth_type,
2179                 new long[] { 0x0800L }));
2180         matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
2181                 BigInteger.valueOf(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID }));
2182
2183         List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
2184         instructions.add(new InstructionInfo(InstructionType.goto_table, new long[]
2185                 { NatConstants.OUTBOUND_NAPT_TABLE }));
2186
2187         String flowRef = getFlowRefSnat(dpId, NatConstants.PSNAT_TABLE, routerName);
2188         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PSNAT_TABLE, flowRef,
2189                 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
2190                 NatConstants.COOKIE_SNAT_TABLE, matches, instructions);
2191
2192         LOG.debug("NAT Service : Returning SNAT Flow Entity {}", flowEntity);
2193         return flowEntity;
2194     }
2195
2196     // TODO : Replace this with ITM Rpc once its available with full functionality
2197     protected void installTerminatingServiceTblEntryWithUpdatedVpnId(BigInteger dpnId, String routerName, long changedVpnId) {
2198         LOG.debug("NAT Service : installTerminatingServiceTblEntryWithUpdatedVpnId called for switch {}, routerName {}, BGP VPN ID {}", dpnId, routerName, changedVpnId);
2199         FlowEntity flowEntity = buildTsFlowEntityWithUpdatedVpnId(dpnId, routerName, changedVpnId);
2200         mdsalManager.installFlow(flowEntity);
2201
2202     }
2203
2204     private FlowEntity buildTsFlowEntityWithUpdatedVpnId(BigInteger dpId, String routerName, long changedVpnId) {
2205         LOG.debug("NAT Service : buildTsFlowEntityWithUpdatedVpnId called for switch {}, routerName {}, BGP VPN ID {}", dpId, routerName, changedVpnId);
2206         BigInteger routerId = BigInteger.valueOf (NatUtil.getVpnId(dataBroker, routerName));
2207         BigInteger bgpVpnIdAsBigInt = BigInteger.valueOf(changedVpnId);
2208         List<MatchInfo> matches = new ArrayList<>();
2209         matches.add(new MatchInfo(MatchFieldType.eth_type,
2210                 new long[] { 0x0800L }));
2211         matches.add(new MatchInfo(MatchFieldType.tunnel_id, new  BigInteger[] {bgpVpnIdAsBigInt }));
2212
2213         List<InstructionInfo> instructions = new ArrayList<>();
2214         instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[]
2215                 { bgpVpnIdAsBigInt, MetaDataUtil.METADATA_MASK_VRFID }));
2216         instructions.add(new InstructionInfo(InstructionType.goto_table, new long[]
2217                 { NatConstants.OUTBOUND_NAPT_TABLE }));
2218         String flowRef = getFlowRefTs(dpId, NatConstants.TERMINATING_SERVICE_TABLE, routerId.longValue());
2219         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.TERMINATING_SERVICE_TABLE, flowRef,
2220                 NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, 0, 0,
2221                 NatConstants.COOKIE_TS_TABLE, matches, instructions);
2222         return flowEntity;
2223     }
2224
2225     public void createOutboundTblEntryWithBgpVpn(BigInteger dpnId, long routerId, long changedVpnId) {
2226         LOG.debug("NAT Service : createOutboundTblEntry called for dpId {} and routerId {}, BGP VPN ID {}", dpnId, routerId, changedVpnId);
2227         FlowEntity flowEntity = buildOutboundFlowEntityWithBgpVpn(dpnId, routerId, changedVpnId);
2228         LOG.debug("NAT Service : Installing flow {}", flowEntity);
2229         mdsalManager.installFlow(flowEntity);
2230     }
2231
2232     protected FlowEntity buildOutboundFlowEntityWithBgpVpn(BigInteger dpId, long routerId, long changedVpnId) {
2233         LOG.debug("NAT Service : buildOutboundFlowEntityWithBgpVpn called for dpId {} and routerId {}, BGP VPN ID {}", dpId, routerId, changedVpnId);
2234         List<MatchInfo> matches = new ArrayList<>();
2235         matches.add(new MatchInfo(MatchFieldType.eth_type,
2236                 new long[]{0x0800L}));
2237         matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[]{
2238                 BigInteger.valueOf(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID}));
2239
2240         List<InstructionInfo> instructions = new ArrayList<>();
2241         List<ActionInfo> actionsInfos = new ArrayList<>();
2242         actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[] {}));
2243         instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
2244         instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[]{BigInteger.valueOf(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID}));
2245
2246         String flowRef = getFlowRefOutbound(dpId, NatConstants.OUTBOUND_NAPT_TABLE, routerId);
2247         BigInteger cookie = getCookieOutboundFlow(routerId);
2248         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.OUTBOUND_NAPT_TABLE, flowRef,
2249                 5, flowRef, 0, 0,
2250                 cookie, matches, instructions);
2251         LOG.debug("NAT Service : returning flowEntity {}", flowEntity);
2252         return flowEntity;
2253     }
2254
2255     public void installNaptPfibEntryWithBgpVpn(BigInteger dpnId, long segmentId, long changedVpnId) {
2256         LOG.debug("NAT Service : installNaptPfibEntryWithBgpVpn called for dpnId {} and segmentId {} ,BGP VPN ID {}", dpnId, segmentId, changedVpnId);
2257         FlowEntity naptPfibFlowEntity = buildNaptPfibFlowEntityWithUpdatedVpnId(dpnId, segmentId, changedVpnId);
2258         mdsalManager.installFlow(naptPfibFlowEntity);
2259     }
2260
2261     public FlowEntity buildNaptPfibFlowEntityWithUpdatedVpnId(BigInteger dpId, long segmentId, long changedVpnId) {
2262
2263         LOG.debug("NAT Service : buildNaptPfibFlowEntityWithUpdatedVpnId is called for dpId {}, segmentId {}, BGP VPN ID {}", dpId, segmentId, changedVpnId);
2264         List<MatchInfo> matches = new ArrayList<>();
2265         matches.add(new MatchInfo(MatchFieldType.eth_type,
2266                 new long[] { 0x0800L }));
2267         matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
2268                 BigInteger.valueOf(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID }));
2269
2270         ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
2271         ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
2272         listActionInfo.add(new ActionInfo(ActionType.nx_resubmit, new String[] { Integer.toString(NatConstants.L3_FIB_TABLE) }));
2273         instructionInfo.add(new InstructionInfo(InstructionType.apply_actions, listActionInfo));
2274
2275         String flowRef = getFlowRefTs(dpId, NatConstants.NAPT_PFIB_TABLE, segmentId);
2276         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.NAPT_PFIB_TABLE, flowRef,
2277                 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
2278                 NatConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
2279
2280         LOG.debug("NAT Service : Returning NaptPFib Flow Entity {}", flowEntity);
2281         return flowEntity;
2282     }
2283
2284     @Override
2285     protected ExternalRoutersListener getDataTreeChangeListener()
2286     {
2287         return ExternalRoutersListener.this;
2288     }
2289
2290 }