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