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