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