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