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