Bug 7444 : External routes are not getting populated
[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                 // Allocate Primary Napt Switch for existing router
1098                 BigInteger primarySwitchId = getPrimaryNaptSwitch(routerName, routerId);
1099                 if(primarySwitchId == null || primarySwitchId.equals(BigInteger.ZERO)){
1100                     LOG.error("NAT Service: Failed to get or allocated NAPT switch in ExternalRouterListener.Update()");
1101                     return;
1102                 }
1103                 LOG.info("NAT Service : SNAT enabled for Router {}", original.getRouterName());
1104                 handleEnableSnat(original, routerId, primarySwitchId);
1105             }
1106         }
1107
1108         if (!Objects.equals(original.getExtGwMacAddress(), update.getExtGwMacAddress())) {
1109             handleRouterGwFlows(original, dpnId, NwConstants.DEL_FLOW);
1110             handleRouterGwFlows(update, dpnId, NwConstants.ADD_FLOW);
1111         }
1112
1113         //Check if the Update is on External IPs
1114         LOG.debug("NAT Service : Checking if this is update on External IPs");
1115         List<String> originalExternalIpsList = original.getExternalIps();
1116         List<String> updatedExternalIpsList = update.getExternalIps();
1117         Set<String> originalExternalIps = Sets.newHashSet(originalExternalIpsList);
1118         Set<String> updatedExternalIps = Sets.newHashSet(updatedExternalIpsList);
1119
1120         //Check if the External IPs are added during the update.
1121         SetView<String> addedExternalIps = Sets.difference(updatedExternalIps, originalExternalIps);
1122         if(addedExternalIps.size() != 0) {
1123             LOG.debug("NAT Service : Start processing of the External IPs addition during the update operation");
1124             vpnManager.setupArpResponderFlowsToExternalNetworkIps(routerName, addedExternalIps, update.getExtGwMacAddress(), dpnId,
1125                     update.getNetworkId(), null, NwConstants.ADD_FLOW);
1126
1127             for (String addedExternalIp : addedExternalIps) {
1128                 /*
1129                     1) Do nothing in the IntExtIp model.
1130                     2) Initialise the count of the added external IP to 0 in the ExternalCounter model.
1131                 */
1132                 String[] externalIpParts = NatUtil.getExternalIpAndPrefix(addedExternalIp);
1133                 String externalIp = externalIpParts[0];
1134                 String externalIpPrefix = externalIpParts[1];
1135                 String externalpStr = externalIp + "/" + externalIpPrefix;
1136                 LOG.debug("NAT Service : Initialise the count mapping of the external IP {} for the router ID {} in the ExternalIpsCounter model.",
1137                         externalpStr, routerId);
1138                 naptManager.initialiseNewExternalIpCounter(routerId, externalpStr);
1139             }
1140             LOG.debug("NAT Service : End processing of the External IPs addition during the update operation");
1141         }
1142
1143         //Check if the External IPs are removed during the update.
1144         SetView<String> removedExternalIps = Sets.difference(originalExternalIps, updatedExternalIps);
1145         if(removedExternalIps.size() > 0) {
1146             LOG.debug("NAT Service : Start processing of the External IPs removal during the update operation");
1147             vpnManager.setupArpResponderFlowsToExternalNetworkIps(routerName, removedExternalIps, original.getExtGwMacAddress(),
1148                     dpnId, networkId, null, NwConstants.DEL_FLOW);
1149
1150             List<String> removedExternalIpsAsList = new ArrayList<>();
1151             for (String removedExternalIp : removedExternalIps) {
1152              /*
1153                 1) Remove the mappings in the IntExt IP model which has external IP.
1154                 2) Remove the external IP in the ExternalCounter model.
1155                 3) For the corresponding subnet IDs whose external IP mapping was removed, allocate one of the least loaded external IP.
1156                    Store the subnet IP and the reallocated external IP mapping in the IntExtIp model.
1157                 4) Increase the count of the allocated external IP by one.
1158                 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.
1159                 6) Remove the NAPT translation entries from Inbound and Outbound NAPT tables for the removed external IPs and also from the model.
1160                 7) Advertise to the BGP for removing the route for the removed external IPs.
1161               */
1162
1163                 String[] externalIpParts = NatUtil.getExternalIpAndPrefix(removedExternalIp);
1164                 String externalIp = externalIpParts[0];
1165                 String externalIpPrefix = externalIpParts[1];
1166                 String externalIpAddrStr = externalIp + "/" + externalIpPrefix;
1167
1168                 LOG.debug("NAT Service : Clear the routes from the BGP and remove the FIB and TS entries for removed external IP {}", externalIpAddrStr);
1169                 Uuid vpnUuId = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
1170                 String vpnName = "";
1171                 if(vpnUuId != null){
1172                     vpnName = vpnUuId.getValue();
1173                 }
1174                 clrRtsFromBgpAndDelFibTs(dpnId, routerId, externalIpAddrStr, vpnName);
1175
1176                 LOG.debug("NAT Service : Remove the mappings in the IntExtIP model which has external IP.");
1177                 //Get the internal IPs which are associated to the removed external IPs
1178                 List<IpMap> ipMaps = naptManager.getIpMapList(dataBroker, routerId);
1179                 List<String> removedInternalIps = new ArrayList<>();
1180                 for(IpMap ipMap : ipMaps){
1181                     if(ipMap.getExternalIp().equals(externalIpAddrStr)){
1182                         removedInternalIps.add(ipMap.getInternalIp());
1183                     }
1184                 }
1185
1186                 LOG.debug("Remove the mappings of the internal IPs from the IntExtIP model.");
1187                 for(String removedInternalIp : removedInternalIps){
1188                     LOG.debug("NAT Service : Remove the IP mapping of the internal IP {} for the router ID {} from the IntExtIP model",
1189                             removedInternalIp, routerId);
1190                     naptManager.removeFromIpMapDS(routerId, removedInternalIp);
1191                 }
1192
1193                 LOG.debug("NAT Service : Remove the count mapping of the external IP {} for the router ID {} from the ExternalIpsCounter model.",
1194                         externalIpAddrStr, routerId );
1195                 naptManager.removeExternalIpCounter(routerId, externalIpAddrStr);
1196                 removedExternalIpsAsList.add(externalIpAddrStr);
1197
1198                 LOG.debug("NAT Service : Allocate the least loaded external IPs to the subnets whose external IPs were removed.");
1199                 for(String removedInternalIp : removedInternalIps) {
1200                     allocateExternalIp(dpnId, routerId, networkId, removedInternalIp);
1201                 }
1202
1203                 LOG.debug("NAT Service : Remove the NAPT translation entries from Inbound and Outbound NAPT tables for the removed external IPs.");
1204                 //Get the internalIP and internal Port which were associated to the removed external IP.
1205                 List<Integer> externalPorts = new ArrayList<>();
1206                 Map<ProtocolTypes, List<String>> protoTypesIntIpPortsMap = new HashMap<>();
1207                 InstanceIdentifier<IpPortMapping> ipPortMappingId = InstanceIdentifier.builder(IntextIpPortMap.class)
1208                         .child(IpPortMapping.class, new IpPortMappingKey(routerId)).build();
1209                 Optional<IpPortMapping> ipPortMapping = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, ipPortMappingId);
1210                 if (ipPortMapping.isPresent()) {
1211                     List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.get().getIntextIpProtocolType();
1212                     for(IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes){
1213                         ProtocolTypes protoType = intextIpProtocolType.getProtocol();
1214                         List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
1215                         for(IpPortMap ipPortMap : ipPortMaps){
1216                             IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
1217                             if(ipPortExternal.getIpAddress().equals(externalIp)){
1218                                 externalPorts.add(ipPortExternal.getPortNum());
1219                                 List<String> removedInternalIpPorts = protoTypesIntIpPortsMap.get(protoType);
1220                                 if(removedInternalIpPorts != null){
1221                                     removedInternalIpPorts.add(ipPortMap.getIpPortInternal());
1222                                     protoTypesIntIpPortsMap.put(protoType, removedInternalIpPorts);
1223                                 }else{
1224                                     removedInternalIpPorts = new ArrayList<>();
1225                                     removedInternalIpPorts.add(ipPortMap.getIpPortInternal());
1226                                     protoTypesIntIpPortsMap.put(protoType, removedInternalIpPorts);
1227                                 }
1228                             }
1229                         }
1230                     }
1231                 }
1232
1233                 //Remove the IP port map from the intext-ip-port-map model, which were containing the removed external IP.
1234                 Set<Map.Entry<ProtocolTypes, List<String>>> protoTypesIntIpPorts = protoTypesIntIpPortsMap.entrySet();
1235                 Map<String, List<String>> internalIpPortMap = new HashMap<>();
1236                 for(Map.Entry protoTypesIntIpPort : protoTypesIntIpPorts){
1237                     ProtocolTypes protocolType = (ProtocolTypes)protoTypesIntIpPort.getKey();
1238                     List<String> removedInternalIpPorts = (List<String>)protoTypesIntIpPort.getValue();
1239                     for(String removedInternalIpPort : removedInternalIpPorts){
1240                         //Remove the IP port map from the intext-ip-port-map model, which were containing the removed external IP
1241                         naptManager.removeFromIpPortMapDS(routerId, removedInternalIpPort, protocolType);
1242                         //Remove the IP port incomint packer map.
1243                         naptPacketInHandler.removeIncomingPacketMap(removedInternalIpPort);
1244                         String[] removedInternalIpPortParts = removedInternalIpPort.split(":");
1245                         if(removedInternalIpPortParts.length == 2){
1246                             String removedInternalIp = removedInternalIpPortParts[0];
1247                             String removedInternalPort = removedInternalIpPortParts[1];
1248                             List<String> removedInternalPortsList =  internalIpPortMap.get(removedInternalPort);
1249                             if (removedInternalPortsList != null){
1250                                 removedInternalPortsList.add(removedInternalPort);
1251                                 internalIpPortMap.put(removedInternalIp, removedInternalPortsList);
1252                             }else{
1253                                 removedInternalPortsList = new ArrayList<>();
1254                                 removedInternalPortsList.add(removedInternalPort);
1255                                 internalIpPortMap.put(removedInternalIp, removedInternalPortsList);
1256                             }
1257                         }
1258                     }
1259                 }
1260
1261                 // Delete the entry from SnatIntIpPortMap DS
1262                 Set<String> internalIps = internalIpPortMap.keySet();
1263                 for(String internalIp : internalIps){
1264                     LOG.debug("NAT Service : Removing IpPort having the internal IP {} from the model SnatIntIpPortMap", internalIp);
1265                     naptManager.removeFromSnatIpPortDS(routerId, internalIp);
1266                 }
1267
1268                 naptManager.removeNaptPortPool(externalIp);
1269
1270                 LOG.debug("Remove the NAPT translation entries from Inbound NAPT tables for the removed external IP {}", externalIp);
1271                 for(Integer externalPort : externalPorts) {
1272                     //Remove the NAPT translation entries from Inbound NAPT table
1273                     naptEventHandler.removeNatFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, routerId, externalIp, externalPort);
1274                 }
1275
1276                 Set<Map.Entry<String, List<String>>> internalIpPorts = internalIpPortMap.entrySet();
1277                 for(Map.Entry<String, List<String>> internalIpPort : internalIpPorts) {
1278                     String internalIp = internalIpPort.getKey();
1279                     LOG.debug("Remove the NAPT translation entries from Outbound NAPT tables for the removed internal IP {}", internalIp);
1280                     List<String> internalPorts = internalIpPort.getValue();
1281                     for(String internalPort : internalPorts){
1282                         //Remove the NAPT translation entries from Outbound NAPT table
1283                         naptEventHandler.removeNatFlows(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId, internalIp, Integer.valueOf(internalPort));
1284                     }
1285                 }
1286             }
1287             LOG.debug("NAT Service : End processing of the External IPs removal during the update operation");
1288         }
1289
1290         //Check if its Update on subnets
1291         LOG.debug("NAT Service : Checking if this is update on subnets");
1292         List<Uuid> originalSubnetIdsList = original.getSubnetIds();
1293         List<Uuid> updatedSubnetIdsList = update.getSubnetIds();
1294         Set<Uuid> originalSubnetIds = Sets.newHashSet(originalSubnetIdsList);
1295         Set<Uuid> updatedSubnetIds = Sets.newHashSet(updatedSubnetIdsList);
1296         SetView<Uuid> addedSubnetIds = Sets.difference(updatedSubnetIds, originalSubnetIds);
1297
1298         //Check if the Subnet IDs are added during the update.
1299         if(addedSubnetIds.size() != 0){
1300             LOG.debug("NAT Service : Start processing of the Subnet IDs addition during the update operation");
1301             for(Uuid addedSubnetId : addedSubnetIds){
1302                 /*
1303                 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.
1304                 2) Increase the count of the selected external IP by one.
1305                 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.
1306                 */
1307                 String subnetIp = NatUtil.getSubnetIp(dataBroker, addedSubnetId);
1308                 if(subnetIp != null) {
1309                     allocateExternalIp(dpnId, routerId, networkId, subnetIp);
1310                 }
1311             }
1312             LOG.debug("NAT Service : End processing of the Subnet IDs addition during the update operation");
1313         }
1314
1315         //Check if the Subnet IDs are removed during the update.
1316         SetView<Uuid> removedSubnetIds = Sets.difference(originalSubnetIds, updatedSubnetIds);
1317         if(removedSubnetIds.size() != 0){
1318             LOG.debug("NAT Service : Start processing of the Subnet IDs removal during the update operation");
1319             for(Uuid removedSubnetId : removedSubnetIds){
1320                 String[] subnetAddr = NatUtil.getSubnetIpAndPrefix(dataBroker, removedSubnetId);
1321                 if(subnetAddr != null){
1322                     /*
1323                     1) Remove the subnet IP and the external IP in the IntExtIp map
1324                     2) Decrease the count of the coresponding external IP by one.
1325                     3) Advertise to the BGP for removing the routes of the corresponding external IP if its not allocated to any other internal IP.
1326                     */
1327
1328                     String externalIp = naptManager.getExternalIpAllocatedForSubnet(routerId, subnetAddr[0] + "/" + subnetAddr[1]);
1329                     if (externalIp == null) {
1330                         LOG.debug("No mapping found for router ID {} and internal IP {}", routerId, subnetAddr[0]);
1331                         return;
1332                     }
1333
1334                     naptManager.updateCounter(routerId, externalIp, false);
1335                     //Traverse entire model of external-ip counter whether external ip is not used by any other internal ip in any router
1336                     if (!isExternalIpAllocated(externalIp)) {
1337                         LOG.debug("NAT Service : external ip is not allocated to any other internal IP so proceeding to remove routes");
1338                         List<String> externalIps = new ArrayList<>();
1339                         externalIps.add(externalIp);
1340                         clrRtsFromBgpAndDelFibTs(dpnId, routerId, networkId, externalIps, null);
1341                         LOG.debug("Successfully removed fib entries in switch {} for router {} with networkId {} and externalIps {}",
1342                                 dpnId,routerId,networkId,externalIps);
1343                     }
1344
1345                     LOG.debug("NAT Service : Remove the IP mapping for the router ID {} and internal IP {} external IP {}", routerId, subnetAddr[0],externalIp);
1346                     naptManager.removeIntExtIpMapDS(routerId, subnetAddr[0] + "/" + subnetAddr[1]);
1347                 }
1348             }
1349             LOG.debug("NAT Service : End processing of the Subnet IDs removal during the update operation");
1350         }
1351     }
1352
1353     private boolean isExternalIpAllocated(String externalIp) {
1354         InstanceIdentifier<ExternalIpsCounter> id = InstanceIdentifier.builder(ExternalIpsCounter.class).build();
1355         Optional <ExternalIpsCounter> externalCountersData = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
1356         if (externalCountersData.isPresent()) {
1357             ExternalIpsCounter externalIpsCounters = externalCountersData.get();
1358             List<ExternalCounters> externalCounters = externalIpsCounters.getExternalCounters();
1359             for(ExternalCounters ext : externalCounters) {
1360                 for (ExternalIpCounter externalIpCount : ext.getExternalIpCounter()) {
1361                     if (externalIpCount.getExternalIp().equals(externalIp)) {
1362                         if (externalIpCount.getCounter() != 0) {
1363                             return true;
1364                         }
1365                         break;
1366                     }
1367                 }
1368             }
1369         }
1370         return false;
1371     }
1372
1373     private void allocateExternalIp(BigInteger dpnId, long routerId, Uuid networkId, String subnetIp){
1374         String leastLoadedExtIpAddr = NatUtil.getLeastLoadedExternalIp(dataBroker, routerId);
1375         if (leastLoadedExtIpAddr != null) {
1376             String[] externalIpParts = NatUtil.getExternalIpAndPrefix(leastLoadedExtIpAddr);
1377             String leastLoadedExtIp = externalIpParts[0];
1378             String leastLoadedExtIpPrefix = externalIpParts[1];
1379             String leastLoadedExtIpAddrStr = leastLoadedExtIp + "/" + leastLoadedExtIpPrefix;
1380             IPAddress externalIpAddr = new IPAddress(leastLoadedExtIp, Integer.parseInt(leastLoadedExtIpPrefix));
1381             String[] subnetIpParts = NatUtil.getSubnetIpAndPrefix(subnetIp);
1382             subnetIp = subnetIpParts[0];
1383             String subnetIpPrefix = subnetIpParts[1];
1384             IPAddress subnetIpAddr = new IPAddress(subnetIp, Integer.parseInt(subnetIpPrefix));
1385             LOG.debug("NAT Service : Add the IP mapping for the router ID {} and internal IP {} and prefix {} -> external IP {} and prefix {}",
1386                     routerId, subnetIp, subnetIpPrefix, leastLoadedExtIp, leastLoadedExtIpPrefix);
1387             naptManager.registerMapping(routerId, subnetIpAddr, externalIpAddr);
1388
1389
1390             //Check if external IP is already assigned a route. (i.e. External IP is previously allocated to any of the subnets)
1391             //If external IP is already assigned a route, (, do not re-advertise to the BGP
1392             Long label = checkExternalIpLabel(routerId, leastLoadedExtIpAddrStr);
1393             if(label != null){
1394                 //update
1395                 String internalIp = subnetIpParts[0] + "/" + subnetIpParts[1];
1396                 IpMapKey ipMapKey = new IpMapKey(internalIp);
1397                 LOG.debug("Setting label {} for internalIp {} and externalIp {}", label, internalIp, leastLoadedExtIpAddrStr);
1398                 IpMap newIpm = new IpMapBuilder().setKey(ipMapKey).setInternalIp(internalIp).setExternalIp(leastLoadedExtIpAddrStr).setLabel(label).build();
1399                 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, naptManager.getIpMapIdentifier(routerId, internalIp), newIpm);
1400                 return;
1401             }
1402
1403             //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.
1404             //Get the VPN Name using the network ID
1405             final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
1406             if (vpnName != null) {
1407                 LOG.debug("Retrieved vpnName {} for networkId {}", vpnName, networkId);
1408                 if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
1409                     LOG.debug("Best effort for getting primary napt switch when router i/f are added after gateway-set");
1410                     dpnId = NatUtil.getPrimaryNaptfromRouterId(dataBroker,routerId);
1411                 }
1412                 advToBgpAndInstallFibAndTsFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, vpnName, routerId,
1413                         leastLoadedExtIp + "/" + leastLoadedExtIpPrefix, vpnService, fibService, bgpManager, dataBroker, LOG);
1414             }
1415         }
1416     }
1417
1418     protected Long checkExternalIpLabel(long routerId, String externalIp){
1419         List<IpMap> ipMaps = naptManager.getIpMapList(dataBroker, routerId);
1420         for(IpMap ipMap : ipMaps){
1421             if(ipMap.getExternalIp().equals(externalIp)){
1422                 if (ipMap.getLabel() != null){
1423                     return ipMap.getLabel();
1424                 }
1425             }
1426         }
1427         return null;
1428     }
1429
1430     @Override
1431     protected void remove(InstanceIdentifier<Routers> identifier, Routers router) {
1432         LOG.trace("NAT Service : Router delete method");
1433         {
1434         /*
1435             ROUTER DELETE SCENARIO
1436             1) Get the router ID from the event.
1437             2) Build the cookie information from the router ID.
1438             3) Get the primary and secondary switch DPN IDs using the router ID from the model.
1439             4) Build the flow with the cookie value.
1440             5) Delete the flows which matches the cookie information from the NAPT outbound, inbound tables.
1441             6) Remove the flows from the other switches which points to the primary and secondary switches for the flows related the router ID.
1442             7) Get the list of external IP address maintained for the router ID.
1443             8) Use the NaptMananager removeMapping API to remove the list of IP addresses maintained.
1444             9) Withdraw the corresponding routes from the BGP.
1445          */
1446
1447             if (identifier == null || router == null) {
1448                 LOG.info("++++++++++++++NAT Service : ExternalRoutersListener:remove:: returning without processing since routers is null");
1449                 return;
1450             }
1451
1452             String routerName = router.getRouterName();
1453             LOG.info("Removing default NAT route from FIB on all dpns part of router {} ", routerName);
1454             addOrDelDefFibRouteToSNAT(routerName, false);
1455             Uuid networkUuid = router.getNetworkId();
1456             Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1457             if (routerId == NatConstants.INVALID_ID) {
1458                 LOG.error("NAT Service : Invalid routerId returned for routerName {}", routerName);
1459                 return;
1460             }
1461
1462             BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
1463             handleRouterGwFlows(router, primarySwitchId, NwConstants.DEL_FLOW);
1464             List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
1465             handleDisableSnat(router, networkUuid, externalIps, true, null, primarySwitchId);
1466         }
1467     }
1468
1469     private void handleRouterGwFlows(Routers router, BigInteger primarySwitchId, int addOrRemove) {
1470         WriteTransaction writeTx = dataBroker.newWriteOnlyTransaction();
1471         vpnManager.setupRouterGwMacFlow(router.getRouterName(), router.getExtGwMacAddress(), primarySwitchId,
1472                 router.getNetworkId(), writeTx, addOrRemove);
1473         vpnManager.setupArpResponderFlowsToExternalNetworkIps(router.getRouterName(), router.getExternalIps(),
1474                 router.getExtGwMacAddress(), primarySwitchId, router.getNetworkId(), writeTx, addOrRemove);
1475         writeTx.submit();
1476     }
1477
1478     public void handleDisableSnat(Routers router, Uuid networkUuid, List<String> externalIps, boolean routerFlag,
1479             String vpnId, BigInteger naptSwitchDpnId) {
1480         LOG.info("NAT Service : handleDisableSnat() Entry");
1481         String routerName = router.getRouterName();
1482         try {
1483             Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1484
1485             LOG.debug("NAT Service : got primarySwitch as dpnId{} ", naptSwitchDpnId);
1486             if (naptSwitchDpnId == null || naptSwitchDpnId.equals(BigInteger.ZERO)){
1487                 LOG.error("NAT Service : Unable to retrieve the primary NAPT switch for the router ID {} from RouterNaptSwitch model", routerId);
1488                 return;
1489             }
1490             removeNaptFlowsFromActiveSwitch(routerId, routerName, naptSwitchDpnId, networkUuid, vpnId, externalIps);
1491             removeFlowsFromNonActiveSwitches(routerName, naptSwitchDpnId, networkUuid);
1492             try {
1493                 clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, vpnId);
1494             } catch (Exception ex) {
1495                 LOG.debug("Failed to remove fib entries for routerId {} in naptSwitchDpnId {} : {}", routerId, naptSwitchDpnId,ex);
1496             }
1497
1498             //Use the NaptMananager removeMapping API to remove the entire list of IP addresses maintained for the router ID.
1499             LOG.debug("NAT Service : Remove the Internal to external IP address maintained for the router ID {} in the DS", routerId);
1500             naptManager.removeMapping(routerId);
1501
1502             if(routerFlag) {
1503                 removeNaptSwitch(routerName);
1504             } else {
1505                 updateNaptSwitch(routerName, BigInteger.ZERO);
1506             }
1507
1508             LOG.debug("NAT Service : Remove the ExternalCounter model for the router ID {}", routerId);
1509             naptManager.removeExternalCounter(routerId);
1510         } catch (Exception ex) {
1511             LOG.error("Exception while handling disableSNAT : {}", ex);
1512         }
1513         LOG.info("NAT Service : handleDisableSnat() Exit");
1514     }
1515
1516     public void handleDisableSnatInternetVpn(String routerName, Uuid networkUuid, List<String> externalIps, boolean routerFlag, String vpnId){
1517         LOG.debug("NAT Service : handleDisableSnatInternetVpn() Entry");
1518         try {
1519             Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1520             BigInteger naptSwitchDpnId = null;
1521             InstanceIdentifier<RouterToNaptSwitch> routerToNaptSwitch = NatUtil.buildNaptSwitchRouterIdentifier(routerName);
1522             Optional<RouterToNaptSwitch> rtrToNapt = read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerToNaptSwitch);
1523             if (rtrToNapt.isPresent()) {
1524                 naptSwitchDpnId = rtrToNapt.get().getPrimarySwitchId();
1525             }
1526             LOG.debug("NAT Service : got primarySwitch as dpnId{} ", naptSwitchDpnId);
1527
1528             removeNaptFlowsFromActiveSwitchInternetVpn(routerId, routerName, naptSwitchDpnId, networkUuid, vpnId );
1529             try {
1530                 clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, vpnId);
1531             } catch (Exception ex) {
1532                 LOG.debug("Failed to remove fib entries for routerId {} in naptSwitchDpnId {} : {}", routerId, naptSwitchDpnId,ex);
1533             }
1534           } catch (Exception ex) {
1535             LOG.error("Exception while handling disableSNATInternetVpn : {}", ex);
1536         }
1537         LOG.debug("NAT Service : handleDisableSnatInternetVpn() Exit");
1538     }
1539
1540     public void updateNaptSwitch(String routerName, BigInteger naptSwitchId) {
1541         RouterToNaptSwitch naptSwitch = new RouterToNaptSwitchBuilder().setKey(new RouterToNaptSwitchKey(routerName))
1542                 .setPrimarySwitchId(naptSwitchId).build();
1543         try {
1544             MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
1545                     NatUtil.buildNaptSwitchRouterIdentifier(routerName), naptSwitch);
1546         } catch (Exception ex) {
1547             LOG.error("Failed to write naptSwitch {} for router {} in ds",
1548                     naptSwitchId,routerName);
1549         }
1550         LOG.debug("Successfully updated naptSwitch {} for router {} in ds",
1551                 naptSwitchId,routerName);
1552     }
1553
1554     protected void removeNaptSwitch(String routerName){
1555         // Remove router and switch from model
1556         InstanceIdentifier<RouterToNaptSwitch> id = InstanceIdentifier.builder(NaptSwitches.class).child(RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();
1557         LOG.debug("NAPT Service : Removing NaptSwitch and Router for the router {} from datastore", routerName);
1558         MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1559     }
1560
1561      public void removeNaptFlowsFromActiveSwitch(long routerId, String routerName, BigInteger dpnId, Uuid networkId, String vpnName, List<String> externalIps){
1562
1563         LOG.debug("NAT Service : Remove NAPT flows from Active switch");
1564         BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
1565
1566         //Remove the PSNAT entry which forwards the packet to Outbound NAPT Table (For the
1567         // traffic which comes from the  VMs of the NAPT switches)
1568         String pSNatFlowRef = getFlowRefSnat(dpnId, NwConstants.PSNAT_TABLE, routerName);
1569         FlowEntity pSNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.PSNAT_TABLE, pSNatFlowRef);
1570
1571         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);
1572         mdsalManager.removeFlow(pSNatFlowEntity);
1573
1574         //Remove the Terminating Service table entry which forwards the packet to Outbound NAPT Table (For the
1575         // traffic which comes from the VMs of the non NAPT switches)
1576         String tsFlowRef = getFlowRefTs(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId);
1577         FlowEntity tsNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, tsFlowRef);
1578
1579         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);
1580         mdsalManager.removeFlow(tsNatFlowEntity);
1581
1582         //Remove the Outbound flow entry which forwards the packet to FIB Table
1583         String outboundNatFlowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId);
1584         FlowEntity outboundNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, outboundNatFlowRef);
1585
1586         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);
1587         mdsalManager.removeFlow(outboundNatFlowEntity);
1588
1589         removeNaptFibExternalOutputFlows(routerId, dpnId, externalIps);
1590
1591         //Remove the NAPT PFIB TABLE which forwards the incoming packet to FIB Table matching on the router ID.
1592         String natPfibFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, routerId);
1593         FlowEntity natPfibFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibFlowRef);
1594
1595         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);
1596         mdsalManager.removeFlow(natPfibFlowEntity);
1597
1598         //Long vpnId = NatUtil.getVpnId(dataBroker, routerId); - This does not work since ext-routers is deleted already - no network info
1599         //Get the VPN ID from the ExternalNetworks model
1600         long vpnId = -1;
1601         if( (vpnName == null) || (vpnName.isEmpty()) ) {
1602             // ie called from router delete cases
1603             Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
1604             LOG.debug("NAT Service : vpnUuid is {}", vpnUuid);
1605             if(vpnUuid != null) {
1606                 vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
1607                 LOG.debug("NAT Service : vpnId for routerdelete or disableSNAT scenario {}", vpnId );
1608             }
1609         } else {
1610             // ie called from disassociate vpn case
1611             LOG.debug("NAT Service: This is disassociate nw with vpn case with vpnName {}", vpnName);
1612             vpnId = NatUtil.getVpnId(dataBroker, vpnName);
1613             LOG.debug("NAT Service : vpnId for disassociate nw with vpn scenario {}", vpnId );
1614         }
1615
1616         if(vpnId != NatConstants.INVALID_ID){
1617            //Remove the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
1618            String natPfibVpnFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, vpnId);
1619            FlowEntity natPfibVpnFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibVpnFlowRef);
1620            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);
1621            mdsalManager.removeFlow(natPfibVpnFlowEntity);
1622         }
1623
1624         //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
1625         IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
1626         if(ipPortMapping == null){
1627             LOG.error("NAT Service : Unable to retrieve the IpPortMapping");
1628             return;
1629         }
1630
1631         List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
1632         for(IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes){
1633             List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
1634             for(IpPortMap ipPortMap : ipPortMaps){
1635                 String ipPortInternal = ipPortMap.getIpPortInternal();
1636                 String[] ipPortParts = ipPortInternal.split(":");
1637                 if(ipPortParts.length != 2) {
1638                     LOG.error("NAT Service : Unable to retrieve the Internal IP and port");
1639                     return;
1640                 }
1641                 String internalIp = ipPortParts[0];
1642                 String internalPort = ipPortParts[1];
1643
1644                 //Build the flow for the outbound NAPT table
1645                 String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, String.valueOf(routerId), internalIp, Integer.valueOf(internalPort));
1646                 FlowEntity outboundNaptFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
1647
1648                 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);
1649                 mdsalManager.removeFlow(outboundNaptFlowEntity);
1650
1651                 IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
1652                 String externalIp = ipPortExternal.getIpAddress();
1653                 int externalPort = ipPortExternal.getPortNum();
1654
1655                 //Build the flow for the inbound NAPT table
1656                 switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.INBOUND_NAPT_TABLE, String.valueOf(routerId), externalIp, externalPort);
1657                 FlowEntity inboundNaptFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.INBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
1658
1659                 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);
1660                 mdsalManager.removeFlow(inboundNaptFlowEntity);
1661             }
1662         }
1663     }
1664
1665     private void removeNaptFibExternalOutputFlows(long routerId, BigInteger dpnId, List<String> externalIps) {
1666         for (String ip : externalIps) {
1667             String extIp = removeMaskFromIp(ip);
1668             String postNaptFlowRef = getFlowRefNaptFib(dpnId, NwConstants.NAPT_PFIB_TABLE, routerId, extIp);
1669             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);
1670             mdsalManager.removeFlow(NatUtil.buildFlowEntity(dpnId,NwConstants.NAPT_PFIB_TABLE, postNaptFlowRef));
1671         }
1672     }
1673
1674     private String removeMaskFromIp(String ip) {
1675         if (ip != null && !ip.trim().isEmpty()) {
1676             return ip.split("/")[0];
1677         }
1678         return ip;
1679     }
1680
1681      public void removeNaptFlowsFromActiveSwitchInternetVpn(long routerId, String routerName, BigInteger dpnId, Uuid networkId, String vpnName){
1682
1683          LOG.debug("NAT Service : Remove NAPT flows from Active switch Internet Vpn");
1684          BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
1685
1686          //Remove the NAPT PFIB TABLE entry
1687          long vpnId = -1;
1688          if(vpnName != null) {
1689              // ie called from disassociate vpn case
1690              LOG.debug("NAT Service: This is disassociate nw with vpn case with vpnName {}", vpnName);
1691              vpnId = NatUtil.getVpnId(dataBroker, vpnName);
1692              LOG.debug("NAT Service : vpnId for disassociate nw with vpn scenario {}", vpnId );
1693          }
1694
1695          if(vpnId != NatConstants.INVALID_ID){
1696             //Remove the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
1697             String natPfibVpnFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, vpnId);
1698             FlowEntity natPfibVpnFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibVpnFlowRef);
1699             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);
1700             mdsalManager.removeFlow(natPfibVpnFlowEntity);
1701
1702              // Remove IP-PORT active NAPT entries and release port from IdManager
1703              //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
1704              IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
1705              if(ipPortMapping == null){
1706                  LOG.error("NAT Service : Unable to retrieve the IpPortMapping");
1707                  return;
1708              }
1709              List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
1710              for(IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes){
1711                  List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
1712                  for(IpPortMap ipPortMap : ipPortMaps){
1713                      String ipPortInternal = ipPortMap.getIpPortInternal();
1714                      String[] ipPortParts = ipPortInternal.split(":");
1715                      if(ipPortParts.length != 2) {
1716                          LOG.error("NAT Service : Unable to retrieve the Internal IP and port");
1717                          return;
1718                      }
1719                      String internalIp = ipPortParts[0];
1720                      String internalPort = ipPortParts[1];
1721
1722                      //Build the flow for the outbound NAPT table
1723                      String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, String.valueOf(routerId), internalIp, Integer.valueOf(internalPort));
1724                      FlowEntity outboundNaptFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
1725
1726                      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);
1727                      mdsalManager.removeFlow(outboundNaptFlowEntity);
1728
1729                      IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
1730                      String externalIp = ipPortExternal.getIpAddress();
1731                      int externalPort = ipPortExternal.getPortNum();
1732
1733                      //Build the flow for the inbound NAPT table
1734                      switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.INBOUND_NAPT_TABLE, String.valueOf(routerId), externalIp, externalPort);
1735                      FlowEntity inboundNaptFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.INBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
1736
1737                      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);
1738                      mdsalManager.removeFlow(inboundNaptFlowEntity);
1739
1740                      // Finally release port from idmanager
1741                      String internalIpPort = internalIp +":"+internalPort;
1742                      naptManager.removePortFromPool(internalIpPort, externalIp);
1743
1744                      //Remove sessions from models
1745                      naptManager.removeIpPortMappingForRouterID(routerId);
1746                      naptManager.removeIntIpPortMappingForRouterID(routerId);
1747                  }
1748              }
1749          } else {
1750              LOG.error("NAT Service : Invalid vpnId {}", vpnId);
1751          }
1752      }
1753
1754     public void removeFlowsFromNonActiveSwitches(String routerName, BigInteger naptSwitchDpnId, Uuid networkId){
1755         LOG.debug("NAT Service : Remove NAPT related flows from non active switches");
1756
1757         //Remove the flows from the other switches which points to the primary and secondary switches for the flows related the router ID.
1758         List<BigInteger> allSwitchList = naptSwitchSelector.getDpnsForVpn(routerName);
1759         if(allSwitchList == null || allSwitchList.isEmpty()){
1760             LOG.error("NAT Service : Unable to get the swithces for the router {}", routerName);
1761             return;
1762         }
1763         Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1764         for (BigInteger dpnId : allSwitchList) {
1765             if (!naptSwitchDpnId.equals(dpnId)) {
1766                 LOG.info("NAT Service : Handle Ordinary switch");
1767
1768                 //Remove the PSNAT entry which forwards the packet to Terminating Service table
1769                 String pSNatFlowRef = getFlowRefSnat(dpnId, NwConstants.PSNAT_TABLE, String.valueOf(routerName));
1770                 FlowEntity pSNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.PSNAT_TABLE, pSNatFlowRef);
1771
1772                 LOG.info("Remove the flow in the " + NwConstants.PSNAT_TABLE + " for the non active switch with the DPN ID {} and router ID {}", dpnId, routerId);
1773                 mdsalManager.removeFlow(pSNatFlowEntity);
1774
1775                 //Remove the group entry which forwards the traffic to the out port (VXLAN tunnel).
1776                 long groupId = createGroupId(getGroupIdKey(routerName));
1777                 List<BucketInfo> listBucketInfo = new ArrayList<>();
1778                 GroupEntity pSNatGroupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, listBucketInfo);
1779
1780                 LOG.info("NAT Service : Remove the group {} for the non active switch with the DPN ID {} and router ID {}", groupId, dpnId, routerId);
1781                 mdsalManager.removeGroup(pSNatGroupEntity);
1782
1783             }
1784         }
1785     }
1786
1787     public void clrRtsFromBgpAndDelFibTs(final BigInteger dpnId, Long routerId, Uuid networkUuid, List<String> externalIps, String vpnName) {
1788         //Withdraw the corresponding routes from the BGP.
1789         //Get the network ID using the router ID.
1790         LOG.debug("NAT Service : Advertise to BGP and remove routes for externalIps {} with routerId {}, network Id {} and vpnName {}",
1791                 externalIps,routerId,networkUuid, vpnName);
1792         if(networkUuid == null ){
1793             LOG.error("NAT Service : networkId is null");
1794             return;
1795         }
1796
1797         if (externalIps == null || externalIps.isEmpty()) {
1798             LOG.debug("NAT Service : externalIps is null");
1799             return;
1800         }
1801
1802         if(vpnName ==null) {
1803             //Get the VPN Name using the network ID
1804             vpnName = NatUtil.getAssociatedVPN(dataBroker, networkUuid, LOG);
1805             if (vpnName == null) {
1806                 LOG.error("No VPN associated with ext nw {} for the router {}",
1807                         networkUuid, routerId);
1808                 return;
1809             }
1810         }
1811         LOG.debug("Retrieved vpnName {} for networkId {}",vpnName,networkUuid);
1812
1813         //Remove custom FIB routes
1814         //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
1815         for (String extIp : externalIps) {
1816             clrRtsFromBgpAndDelFibTs(dpnId, routerId, extIp, vpnName);
1817         }
1818     }
1819
1820     protected void clrRtsFromBgpAndDelFibTs(final BigInteger dpnId, long routerId, String extIp, final String vpnName) {
1821         clearBgpRoutes(extIp,vpnName);
1822         delFibTsAndReverseTraffic(dpnId,routerId,extIp,vpnName);
1823     }
1824
1825     protected void delFibTsAndReverseTraffic(final BigInteger dpnId, long routerId, String extIp, final String vpnName,long tempLabel) {
1826         LOG.debug("Removing fib entry for externalIp {} in routerId {}",extIp,routerId);
1827
1828         if (tempLabel < 0 || tempLabel == NatConstants.INVALID_ID) {
1829             LOG.error("NAT Service : Label not found for externalIp {} with router id {}",extIp,routerId);
1830             return;
1831         }
1832
1833         final long label = tempLabel;
1834         final String externalIp = extIp;
1835
1836         RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName).setSourceDpid(dpnId).setIpAddress(externalIp).setServiceId(label).build();
1837         Future<RpcResult<Void>> future = fibService.removeFibEntry(input);
1838
1839         ListenableFuture<RpcResult<Void>> labelFuture = Futures.transform(JdkFutureAdapters.listenInPoolThread(future), new AsyncFunction<RpcResult<Void>, RpcResult<Void>>() {
1840
1841             @Override
1842             public ListenableFuture<RpcResult<Void>> apply(RpcResult<Void> result) throws Exception {
1843                 //Release label
1844                 if (result.isSuccessful()) {
1845                     removeTunnelTableEntry(dpnId, label);
1846                     removeLFibTableEntry(dpnId, label);
1847                     RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder().setVpnName(vpnName).setIpPrefix(externalIp).build();
1848                     Future<RpcResult<Void>> labelFuture = vpnService.removeVpnLabel(labelInput);
1849                     return JdkFutureAdapters.listenInPoolThread(labelFuture);
1850                 } else {
1851                     String errMsg = String.format("RPC call to remove custom FIB entries on dpn %s for prefix %s Failed - %s", dpnId, externalIp, result.getErrors());
1852                     LOG.error(errMsg);
1853                     return Futures.immediateFailedFuture(new RuntimeException(errMsg));
1854                 }
1855             }
1856
1857         });
1858
1859         Futures.addCallback(labelFuture, new FutureCallback<RpcResult<Void>>() {
1860
1861             @Override
1862             public void onFailure(Throwable error) {
1863                 LOG.error("NAT Service : Error in removing the label or custom fib entries", error);
1864             }
1865
1866             @Override
1867             public void onSuccess(RpcResult<Void> result) {
1868                 if (result.isSuccessful()) {
1869                     LOG.debug("NAT Service : Successfully removed the label for the prefix {} from VPN {}", externalIp, vpnName);
1870                 } else {
1871                     LOG.error("NAT Service : Error in removing the label for prefix {} from VPN {}, {}", externalIp, vpnName, result.getErrors());
1872                 }
1873             }
1874         });
1875     }
1876
1877     private void delFibTsAndReverseTraffic(final BigInteger dpnId, long routerId, String extIp, final String vpnName) {
1878         LOG.debug("Removing fib entry for externalIp {} in routerId {}",extIp,routerId);
1879         //Get IPMaps from the DB for the router ID
1880         List<IpMap> dbIpMaps = NaptManager.getIpMapList(dataBroker, routerId);
1881         if (dbIpMaps == null || dbIpMaps.isEmpty()) {
1882             LOG.error("NAT Service : IPMaps not found for router {}",routerId);
1883             return;
1884         }
1885
1886         long tempLabel = NatConstants.INVALID_ID;
1887         for (IpMap dbIpMap : dbIpMaps) {
1888             String dbExternalIp = dbIpMap.getExternalIp();
1889             LOG.debug("Retrieved dbExternalIp {} for router id {}",dbExternalIp,routerId);
1890             //Select the IPMap, whose external IP is the IP for which FIB is installed
1891             if (extIp.equals(dbExternalIp)) {
1892                 tempLabel = dbIpMap.getLabel();
1893                 LOG.debug("Retrieved label {} for dbExternalIp {} with router id {}",tempLabel,dbExternalIp,routerId);
1894                 break;
1895             }
1896         }
1897         if (tempLabel < 0 || tempLabel == NatConstants.INVALID_ID) {
1898             LOG.error("NAT Service : Label not found for externalIp {} with router id {}",extIp,routerId);
1899             return;
1900         }
1901
1902         final long label = tempLabel;
1903         final String externalIp = extIp;
1904
1905         RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName).setSourceDpid(dpnId).setIpAddress(externalIp).setServiceId(label).build();
1906         Future<RpcResult<Void>> future = fibService.removeFibEntry(input);
1907
1908         ListenableFuture<RpcResult<Void>> labelFuture = Futures.transform(JdkFutureAdapters.listenInPoolThread(future), new AsyncFunction<RpcResult<Void>, RpcResult<Void>>() {
1909
1910             @Override
1911             public ListenableFuture<RpcResult<Void>> apply(RpcResult<Void> result) throws Exception {
1912                 //Release label
1913                 if (result.isSuccessful()) {
1914                     removeTunnelTableEntry(dpnId, label);
1915                     removeLFibTableEntry(dpnId, label);
1916                     RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder().setVpnName(vpnName).setIpPrefix(externalIp).build();
1917                     Future<RpcResult<Void>> labelFuture = vpnService.removeVpnLabel(labelInput);
1918                     return JdkFutureAdapters.listenInPoolThread(labelFuture);
1919                 } else {
1920                     String errMsg = String.format("RPC call to remove custom FIB entries on dpn %s for prefix %s Failed - %s", dpnId, externalIp, result.getErrors());
1921                     LOG.error(errMsg);
1922                     return Futures.immediateFailedFuture(new RuntimeException(errMsg));
1923                 }
1924             }
1925
1926         });
1927
1928         Futures.addCallback(labelFuture, new FutureCallback<RpcResult<Void>>() {
1929
1930             @Override
1931             public void onFailure(Throwable error) {
1932                 LOG.error("NAT Service : Error in removing the label or custom fib entries", error);
1933             }
1934
1935             @Override
1936             public void onSuccess(RpcResult<Void> result) {
1937                 if (result.isSuccessful()) {
1938                     LOG.debug("NAT Service : Successfully removed the label for the prefix {} from VPN {}", externalIp, vpnName);
1939                 } else {
1940                     LOG.error("NAT Service : Error in removing the label for prefix {} from VPN {}, {}", externalIp, vpnName, result.getErrors());
1941                 }
1942             }
1943         });
1944     }
1945
1946     protected void clearFibTsAndReverseTraffic(final BigInteger dpnId, Long routerId, Uuid networkUuid, List<String> externalIps, String vpnName) {
1947         //Withdraw the corresponding routes from the BGP.
1948         //Get the network ID using the router ID.
1949         LOG.debug("NAT Service : clearFibTsAndReverseTraffic for externalIps {} with routerId {}, network Id {} and vpnName {}",
1950                 externalIps,routerId,networkUuid, vpnName);
1951         if (networkUuid == null) {
1952             LOG.error("NAT Service : networkId is null");
1953             return;
1954         }
1955
1956         if (externalIps == null || externalIps.isEmpty()) {
1957             LOG.debug("NAT Service : externalIps is null");
1958             return;
1959         }
1960
1961         if (vpnName == null) {
1962             //Get the VPN Name using the network ID
1963             vpnName = NatUtil.getAssociatedVPN(dataBroker, networkUuid, LOG);
1964             if (vpnName == null) {
1965                 LOG.error("No VPN associated with ext nw {} for the router {}",
1966                         networkUuid, routerId);
1967                 return;
1968             }
1969         }
1970         LOG.debug("Retrieved vpnName {} for networkId {}",vpnName,networkUuid);
1971
1972         //Remove custom FIB routes
1973         //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
1974         for (String extIp : externalIps) {
1975             delFibTsAndReverseTraffic(dpnId,routerId,extIp,vpnName);
1976         }
1977     }
1978
1979     protected  void clearBgpRoutes(String externalIp, final String vpnName) {
1980         //Inform BGP about the route removal
1981         LOG.info("Informing BGP to remove route for externalIP {} of vpn {}",externalIp,vpnName);
1982         String rd = NatUtil.getVpnRd(dataBroker, vpnName);
1983         NatUtil.removePrefixFromBGP(dataBroker, bgpManager, fibManager, rd, externalIp, LOG);
1984     }
1985
1986     private void removeTunnelTableEntry(BigInteger dpnId, long serviceId) {
1987         LOG.info("NAT Service : remove terminatingServiceActions called with DpnId = {} and label = {}", dpnId , serviceId);
1988         List<MatchInfo> mkMatches = new ArrayList<>();
1989         // Matching metadata
1990         mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(serviceId)}));
1991         Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
1992                 getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""),
1993                 5, String.format("%s:%d","TST Flow Entry ",serviceId), 0, 0,
1994                 COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, null);
1995         mdsalManager.removeFlow(dpnId, flowEntity);
1996         LOG.debug("NAT Service : Terminating service Entry for dpID {} : label : {} removed successfully {}",dpnId, serviceId);
1997     }
1998
1999     private void removeLFibTableEntry(BigInteger dpnId, long serviceId) {
2000         List<MatchInfo> matches = new ArrayList<>();
2001         matches.add(new MatchInfo(MatchFieldType.eth_type,
2002                 new long[] { 0x8847L }));
2003         matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(serviceId)}));
2004
2005         String flowRef = getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, serviceId, "");
2006
2007         LOG.debug("NAT Service : removing LFib entry with flow ref {}", flowRef);
2008
2009         Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
2010                 10, flowRef, 0, 0,
2011                 COOKIE_VM_LFIB_TABLE, matches, null);
2012
2013         mdsalManager.removeFlow(dpnId, flowEntity);
2014
2015         LOG.debug("NAT Service : LFIB Entry for dpID : {} label : {} removed successfully {}",dpnId, serviceId);
2016     }
2017
2018     /**
2019      * router association to vpn
2020      *@param routerName - Name of router
2021      *@param bgpVpnName BGP VPN name
2022      */
2023     public void changeLocalVpnIdToBgpVpnId(String routerName, String bgpVpnName){
2024         LOG.debug("NAT Service : Router associated to BGP VPN");
2025         if (chkExtRtrAndSnatEnbl(new Uuid(routerName))) {
2026             long bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnName);
2027
2028             LOG.debug("BGP VPN ID value {} ", bgpVpnId);
2029
2030             if(bgpVpnId != NatConstants.INVALID_ID){
2031                 LOG.debug("Populate the router-id-name container with the mapping BGP VPN-ID {} -> BGP VPN-NAME {}", bgpVpnId, bgpVpnName);
2032                 RouterIds rtrs = new RouterIdsBuilder().setKey(new RouterIdsKey(bgpVpnId)).setRouterId(bgpVpnId).setRouterName(bgpVpnName).build();
2033                 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, getRoutersIdentifier(bgpVpnId), rtrs);
2034
2035                 // Get the allocated Primary NAPT Switch for this router
2036                 long routerId = NatUtil.getVpnId(dataBroker, routerName);
2037                 LOG.debug("Router ID value {} ", routerId);
2038                 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
2039
2040                 LOG.debug("NAT Service : Update the Router ID {} to the BGP VPN ID {} ", routerId, bgpVpnId);
2041                 addOrDelDefaultFibRouteForSNATWIthBgpVpn(routerName, bgpVpnId, true);
2042
2043                 // Get the group ID
2044                 long groupId = createGroupId(getGroupIdKey(routerName));
2045                 installFlowsWithUpdatedVpnId(primarySwitchId, routerName, bgpVpnId, routerId, true);
2046             }
2047         }
2048     }
2049
2050     /**
2051      * router disassociation from vpn
2052      *@param routerName - Name of router
2053      *@param bgpVpnName BGP VPN name
2054      */
2055     public void changeBgpVpnIdToLocalVpnId(String routerName, String bgpVpnName){
2056         LOG.debug("NAT Service : Router dissociated from BGP VPN");
2057         if(chkExtRtrAndSnatEnbl(new Uuid(routerName))) {
2058             long bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnName);
2059             LOG.debug("BGP VPN ID value {} ", bgpVpnId);
2060
2061             // Get the allocated Primary NAPT Switch for this router
2062             long routerId = NatUtil.getVpnId(dataBroker, routerName);
2063             LOG.debug("Router ID value {} ", routerId);
2064             BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
2065
2066             LOG.debug("NAT Service : Update the BGP VPN ID {} to the Router ID {}", bgpVpnId, routerId);
2067             addOrDelDefaultFibRouteForSNATWIthBgpVpn(routerName, NatConstants.INVALID_ID, true);
2068
2069             // Get the group ID
2070             long groupId = createGroupId(getGroupIdKey(routerName));
2071             installFlowsWithUpdatedVpnId(primarySwitchId, routerName, NatConstants.INVALID_ID, routerId, true);
2072         }
2073     }
2074
2075     boolean chkExtRtrAndSnatEnbl(Uuid routerUuid){
2076         InstanceIdentifier<Routers> routerInstanceIndentifier = InstanceIdentifier.builder(ExtRouters.class).child
2077                 (Routers.class, new RoutersKey(routerUuid.getValue())).build();
2078         Optional<Routers> routerData = read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerInstanceIndentifier);
2079         if (routerData.isPresent() && routerData.get().isEnableSnat()) {
2080             return true;
2081         }
2082         return false;
2083     }
2084     public void installFlowsWithUpdatedVpnId(BigInteger primarySwitchId, String routerName, long bgpVpnId, long
2085             routerId, boolean isSnatCfgd){
2086         installFlowsWithUpdatedVpnId(primarySwitchId, routerName, bgpVpnId, routerId, isSnatCfgd, null);
2087     }
2088
2089     public void installFlowsWithUpdatedVpnId(BigInteger primarySwitchId, String routerName, long bgpVpnId, long
2090             routerId, boolean isSnatCfgd, Routers router){
2091         long changedVpnId = bgpVpnId;
2092         String logMsg = "NAT Service : Update the BGP VPN ID {}";
2093         if (bgpVpnId == NatConstants.INVALID_ID){
2094             changedVpnId = routerId;
2095             logMsg = "NAT Service : Update the router ID {}";
2096         }
2097
2098         List<BigInteger> switches = NatUtil.getDpnsForRouter(dataBroker, routerName);
2099         if (switches == null || switches.isEmpty()) {
2100             LOG.debug("No switches found for router {}",routerName);
2101             return;
2102         }
2103         for(BigInteger dpnId : switches) {
2104             // Update the BGP VPN ID in the SNAT miss entry to group
2105             if( !dpnId.equals(primarySwitchId) ) {
2106                 LOG.debug("NAT Service : Install group in non NAPT switch {}", dpnId);
2107                 List<BucketInfo> bucketInfoForNonNaptSwitches = getBucketInfoForNonNaptSwitches(dpnId, primarySwitchId, routerName);
2108                 long groupId = createGroupId(getGroupIdKey(routerName));
2109                 if(!isSnatCfgd){
2110                     groupId = installGroup(dpnId, routerName, bucketInfoForNonNaptSwitches);
2111                 }
2112
2113                 LOG.debug(logMsg + " in the SNAT miss entry pointing to group {} in the non NAPT switch {}",
2114                         changedVpnId, groupId, dpnId);
2115                 FlowEntity flowEntity = buildSnatFlowEntityWithUpdatedVpnId(dpnId, routerName, groupId, changedVpnId);
2116                 mdsalManager.installFlow(flowEntity);
2117             }else{
2118
2119                 LOG.debug(logMsg + " in the SNAT miss entry pointing to group {} in the primary switch {}",
2120                         changedVpnId, primarySwitchId);
2121                 FlowEntity flowEntity = buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch(primarySwitchId, routerName, changedVpnId);
2122                 mdsalManager.installFlow(flowEntity);
2123
2124                 LOG.debug(logMsg + " in the Terminating Service table (table ID 36) which forwards the packet" +
2125                         " to the table 46 in the Primary switch {}",  changedVpnId, primarySwitchId);
2126                 installTerminatingServiceTblEntryWithUpdatedVpnId(primarySwitchId, routerName, changedVpnId);
2127
2128                 LOG.debug(logMsg + " in the Outbound NAPT table (table ID 46) which punts the packet to the" +
2129                         " controller in the Primary switch {}", changedVpnId, primarySwitchId);
2130                 createOutboundTblEntryWithBgpVpn(primarySwitchId, routerId, changedVpnId);
2131
2132                 LOG.debug(logMsg + " in the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table in the Primary switch {}",
2133                         changedVpnId, primarySwitchId);
2134                 installNaptPfibEntryWithBgpVpn(primarySwitchId, routerId, changedVpnId);
2135
2136                 LOG.debug(logMsg + " in the NAPT flows for the Outbound NAPT table (table ID 46) and the INBOUND NAPT table (table ID 44)" +
2137                         " in the Primary switch {}", changedVpnId, primarySwitchId);
2138                 updateNaptFlowsWithVpnId(primarySwitchId, routerId, bgpVpnId);
2139
2140                 LOG.debug("NAT Service : Installing SNAT PFIB flow in the primary switch {}", primarySwitchId);
2141                 Long vpnId = NatUtil.getVpnId(dataBroker, routerId);
2142                 //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
2143                 if (vpnId != null && vpnId != NatConstants.INVALID_ID) {
2144                     installNaptPfibEntry(primarySwitchId, vpnId);
2145                 }
2146             }
2147         }
2148     }
2149
2150     public void updateNaptFlowsWithVpnId(BigInteger dpnId, long routerId, long bgpVpnId){
2151         //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
2152         IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
2153         if(ipPortMapping == null){
2154             LOG.error("NAT Service : Unable to retrieve the IpPortMapping");
2155             return;
2156         }
2157
2158         List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
2159         for(IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes){
2160             List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
2161             for(IpPortMap ipPortMap : ipPortMaps){
2162                 String ipPortInternal = ipPortMap.getIpPortInternal();
2163                 String[] ipPortParts = ipPortInternal.split(":");
2164                 if(ipPortParts.length != 2) {
2165                     LOG.error("NAT Service : Unable to retrieve the Internal IP and port");
2166                     return;
2167                 }
2168                 String internalIp = ipPortParts[0];
2169                 String internalPort = ipPortParts[1];
2170
2171                 ProtocolTypes protocolTypes = intextIpProtocolType.getProtocol();
2172                 NAPTEntryEvent.Protocol protocol;
2173                 switch (protocolTypes){
2174                     case TCP:
2175                         protocol = NAPTEntryEvent.Protocol.TCP;
2176                         break;
2177                     case UDP:
2178                         protocol = NAPTEntryEvent.Protocol.UDP;
2179                         break;
2180                     default:
2181                         protocol = NAPTEntryEvent.Protocol.TCP;
2182                 }
2183                 SessionAddress internalAddress = new SessionAddress(internalIp, Integer.valueOf(internalPort));
2184                 SessionAddress externalAddress = naptManager.getExternalAddressMapping(routerId, internalAddress, protocol);
2185                 long internetVpnid = NatUtil.getVpnId(dataBroker, routerId);
2186                 NaptEventHandler.buildAndInstallNatFlows(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, internetVpnid, routerId, bgpVpnId,
2187                         internalAddress, externalAddress, protocol);
2188                 NaptEventHandler.buildAndInstallNatFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, internetVpnid, routerId, bgpVpnId,
2189                         externalAddress, internalAddress, protocol);
2190
2191             }
2192         }
2193     }
2194
2195     public FlowEntity buildSnatFlowEntityWithUpdatedVpnId(BigInteger dpId, String routerName, long groupId, long changedVpnId) {
2196
2197         LOG.debug("NAT Service : buildSnatFlowEntity is called for dpId {}, routerName {} groupId {} changed VPN ID {}", dpId, routerName, groupId, changedVpnId );
2198         List<MatchInfo> matches = new ArrayList<>();
2199         matches.add(new MatchInfo(MatchFieldType.eth_type,
2200                 new long[] { 0x0800L }));
2201         matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
2202                 MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID }));
2203
2204         List<InstructionInfo> instructions = new ArrayList<>();
2205         List<ActionInfo> actionsInfo = new ArrayList<>();
2206
2207         ActionInfo actionSetField = new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {
2208                 BigInteger.valueOf(changedVpnId)}) ;
2209         actionsInfo.add(actionSetField);
2210         LOG.debug("NAT Service : Setting the tunnel to the list of action infos {}", actionsInfo);
2211         actionsInfo.add(new ActionInfo(ActionType.group, new String[] {String.valueOf(groupId)}));
2212         instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfo));
2213         String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
2214         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
2215                 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
2216                 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
2217
2218         LOG.debug("NAT Service : Returning SNAT Flow Entity {}", flowEntity);
2219         return flowEntity;
2220     }
2221
2222     public FlowEntity buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch(BigInteger dpId, String routerName, long changedVpnId) {
2223
2224         LOG.debug("NAT Service : buildSnatFlowEntity is called for dpId {}, routerName {} changed VPN ID {}", dpId, routerName, changedVpnId );
2225         List<MatchInfo> matches = new ArrayList<>();
2226         matches.add(new MatchInfo(MatchFieldType.eth_type,
2227                 new long[] { 0x0800L }));
2228         matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
2229                 MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID }));
2230
2231         List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
2232         instructions.add(new InstructionInfo(InstructionType.goto_table, new long[]
2233                 { NwConstants.OUTBOUND_NAPT_TABLE }));
2234
2235         String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
2236         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
2237                 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
2238                 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
2239
2240         LOG.debug("NAT Service : Returning SNAT Flow Entity {}", flowEntity);
2241         return flowEntity;
2242     }
2243
2244     // TODO : Replace this with ITM Rpc once its available with full functionality
2245     protected void installTerminatingServiceTblEntryWithUpdatedVpnId(BigInteger dpnId, String routerName, long changedVpnId) {
2246         LOG.debug("NAT Service : installTerminatingServiceTblEntryWithUpdatedVpnId called for switch {}, routerName {}, BGP VPN ID {}", dpnId, routerName, changedVpnId);
2247         FlowEntity flowEntity = buildTsFlowEntityWithUpdatedVpnId(dpnId, routerName, changedVpnId);
2248         mdsalManager.installFlow(flowEntity);
2249
2250     }
2251
2252     private FlowEntity buildTsFlowEntityWithUpdatedVpnId(BigInteger dpId, String routerName, long changedVpnId) {
2253         LOG.debug("NAT Service : buildTsFlowEntityWithUpdatedVpnId called for switch {}, routerName {}, BGP VPN ID {}", dpId, routerName, changedVpnId);
2254         BigInteger routerId = BigInteger.valueOf (NatUtil.getVpnId(dataBroker, routerName));
2255         BigInteger bgpVpnIdAsBigInt = BigInteger.valueOf(changedVpnId);
2256         List<MatchInfo> matches = new ArrayList<>();
2257         matches.add(new MatchInfo(MatchFieldType.eth_type,
2258                 new long[] { 0x0800L }));
2259         matches.add(new MatchInfo(MatchFieldType.tunnel_id, new  BigInteger[] {bgpVpnIdAsBigInt }));
2260
2261         List<InstructionInfo> instructions = new ArrayList<>();
2262         instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[]
2263                 { MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID }));
2264         instructions.add(new InstructionInfo(InstructionType.goto_table, new long[]
2265                 { NwConstants.OUTBOUND_NAPT_TABLE }));
2266         String flowRef = getFlowRefTs(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId.longValue());
2267         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef,
2268                 NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, 0, 0,
2269                 NwConstants.COOKIE_TS_TABLE, matches, instructions);
2270         return flowEntity;
2271     }
2272
2273     public void createOutboundTblEntryWithBgpVpn(BigInteger dpnId, long routerId, long changedVpnId) {
2274         LOG.debug("NAT Service : createOutboundTblEntry called for dpId {} and routerId {}, BGP VPN ID {}", dpnId, routerId, changedVpnId);
2275         FlowEntity flowEntity = buildOutboundFlowEntityWithBgpVpn(dpnId, routerId, changedVpnId);
2276         LOG.debug("NAT Service : Installing flow {}", flowEntity);
2277         mdsalManager.installFlow(flowEntity);
2278     }
2279
2280     protected FlowEntity buildOutboundFlowEntityWithBgpVpn(BigInteger dpId, long routerId, long changedVpnId) {
2281         LOG.debug("NAT Service : buildOutboundFlowEntityWithBgpVpn called for dpId {} and routerId {}, BGP VPN ID {}", dpId, routerId, changedVpnId);
2282         List<MatchInfo> matches = new ArrayList<>();
2283         matches.add(new MatchInfo(MatchFieldType.eth_type,
2284                 new long[]{0x0800L}));
2285         matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[]{
2286                 MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID}));
2287
2288         List<InstructionInfo> instructions = new ArrayList<>();
2289         List<ActionInfo> actionsInfos = new ArrayList<>();
2290         actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[] {}));
2291         instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
2292         instructions.add(new InstructionInfo(InstructionType.write_metadata,
2293                 new BigInteger[] { MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID }));
2294
2295         String flowRef = getFlowRefOutbound(dpId, NwConstants.OUTBOUND_NAPT_TABLE, routerId);
2296         BigInteger cookie = getCookieOutboundFlow(routerId);
2297         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef, 5, flowRef, 0, 0,
2298                 cookie, matches, instructions);
2299         LOG.debug("NAT Service : returning flowEntity {}", flowEntity);
2300         return flowEntity;
2301     }
2302
2303     protected FlowEntity buildNaptFibExternalOutputFlowEntity(BigInteger dpId, long extVpnId, Uuid subnetId, String externalIp) {
2304         LOG.debug("NAT Service : buildPostSnatFlowEntity called for dpId {}, routerId {}, srcIp {}", dpId, extVpnId,
2305                 externalIp);
2306
2307         List<MatchInfo> matches = new ArrayList<>();
2308         matches.add(new MatchInfo(MatchFieldType.eth_type, new long[] { NwConstants.ETHTYPE_IPV4 }));
2309         matches.add(new MatchInfo(MatchFieldType.metadata,
2310                 new BigInteger[] { MetaDataUtil.getVpnIdMetadata(extVpnId), MetaDataUtil.METADATA_MASK_VRFID }));
2311         matches.add(new MatchInfo(MatchFieldType.ipv4_source, new String[] { externalIp , "32" }));
2312
2313         List<InstructionInfo> instructions = new ArrayList<>();
2314         List<ActionInfo> actionsInfos = new ArrayList<>();
2315         instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
2316         long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(subnetId.getValue()), idManager);
2317         actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
2318
2319         String flowRef = getFlowRefNaptFib(dpId, NwConstants.NAPT_PFIB_TABLE, extVpnId, externalIp);
2320         BigInteger cookie = getCookieOutboundFlow(extVpnId);
2321         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.NAPT_PFIB_TABLE, flowRef, 6, flowRef, 0,
2322                 0, cookie, matches, instructions);
2323         LOG.debug("NAT Service : returning flowEntity {}", flowEntity);
2324         return flowEntity;
2325     }
2326
2327     public void installNaptPfibEntryWithBgpVpn(BigInteger dpnId, long segmentId, long changedVpnId) {
2328         LOG.debug("NAT Service : installNaptPfibEntryWithBgpVpn called for dpnId {} and segmentId {} ,BGP VPN ID {}", dpnId, segmentId, changedVpnId);
2329         FlowEntity naptPfibFlowEntity = buildNaptPfibFlowEntityWithUpdatedVpnId(dpnId, segmentId, changedVpnId);
2330         mdsalManager.installFlow(naptPfibFlowEntity);
2331     }
2332
2333     public FlowEntity buildNaptPfibFlowEntityWithUpdatedVpnId(BigInteger dpId, long segmentId, long changedVpnId) {
2334
2335         LOG.debug("NAT Service : buildNaptPfibFlowEntityWithUpdatedVpnId is called for dpId {}, segmentId {}, BGP VPN ID {}", dpId, segmentId, changedVpnId);
2336         List<MatchInfo> matches = new ArrayList<>();
2337         matches.add(new MatchInfo(MatchFieldType.eth_type,
2338                 new long[] { 0x0800L }));
2339         matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
2340                 MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID }));
2341
2342         ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
2343         ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
2344         listActionInfo.add(new ActionInfo(ActionType.nx_load_in_port, new BigInteger[]{BigInteger.ZERO}));
2345         listActionInfo.add(new ActionInfo(ActionType.nx_resubmit, new String[] { Integer.toString(NwConstants.L3_FIB_TABLE) }));
2346         instructionInfo.add(new InstructionInfo(InstructionType.apply_actions, listActionInfo));
2347
2348         String flowRef = getFlowRefTs(dpId, NwConstants.NAPT_PFIB_TABLE, segmentId);
2349         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.NAPT_PFIB_TABLE, flowRef,
2350                 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
2351                 NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
2352
2353         LOG.debug("NAT Service : Returning NaptPFib Flow Entity {}", flowEntity);
2354         return flowEntity;
2355     }
2356
2357     @Override
2358     protected ExternalRoutersListener getDataTreeChangeListener()
2359     {
2360         return ExternalRoutersListener.this;
2361     }
2362
2363 }