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