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