Bump versions by 0.1.0 for next dev cycle
[vpnservice.git] / natservice / natservice-impl / src / main / java / org / opendaylight / vpnservice / natservice / internal / NaptSwitchHA.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.vpnservice.natservice.internal;
9
10 import com.google.common.base.Optional;
11 import org.opendaylight.bgpmanager.api.IBgpManager;
12 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
13 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
14 import org.opendaylight.vpnservice.mdsalutil.*;
15 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
16 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCase;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushVlanActionCase;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetFieldCase;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.FibRpcService;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeBase;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeGre;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeVxlan;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceInputBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceOutput;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetTunnelInterfaceNameInputBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetTunnelInterfaceNameOutput;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.*;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ext.routers.Routers;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ext.routers.RoutersKey;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMapping;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMappingKey;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.IpPortMapping;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.IpPortMappingKey;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolType;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMap;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.ip.port.map.IpPortExternal;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitch;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitchBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.VpnRpcService;
53 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
54 import org.opendaylight.yangtools.yang.common.RpcResult;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57
58 import java.math.BigInteger;
59 import java.util.ArrayList;
60 import java.util.List;
61 import java.util.Objects;
62 import java.util.concurrent.ExecutionException;
63 import java.util.concurrent.Future;
64
65 public class NaptSwitchHA {
66     private static final Logger LOG = LoggerFactory.getLogger(NaptSwitchHA.class);
67     private final DataBroker dataBroker;
68     private IMdsalApiManager mdsalManager;
69     private ItmRpcService itmManager;
70     private OdlInterfaceRpcService interfaceManager;
71     private IdManagerService idManager;
72     private NAPTSwitchSelector naptSwitchSelector;
73     private ExternalRoutersListener externalRouterListener;
74     private IBgpManager bgpManager;
75     private VpnRpcService vpnService;
76     private FibRpcService fibService;
77
78     public NaptSwitchHA(DataBroker broker,NAPTSwitchSelector selector){
79         dataBroker = broker;
80         naptSwitchSelector = selector;
81     }
82
83     public void setItmManager(ItmRpcService itmManager) {
84         this.itmManager = itmManager;
85     }
86
87     public void setMdsalManager(IMdsalApiManager mdsalManager) {
88         this.mdsalManager = mdsalManager;
89     }
90
91     public void setInterfaceManager(OdlInterfaceRpcService interfaceManager) {
92         this.interfaceManager = interfaceManager;
93     }
94
95     public void setIdManager(IdManagerService idManager) {
96         this.idManager = idManager;
97     }
98
99     void setExternalRoutersListener(ExternalRoutersListener externalRoutersListener) {
100         this.externalRouterListener = externalRoutersListener;
101     }
102
103     public void setBgpManager(IBgpManager bgpManager) {
104         this.bgpManager = bgpManager;
105     }
106
107     public void setVpnService(VpnRpcService vpnService) {
108         this.vpnService = vpnService;
109     }
110
111     public void setFibService(FibRpcService fibService) {
112         this.fibService = fibService;
113     }
114
115     /* This method checks the switch that gone down is a NaptSwitch for a router.
116        If it is a NaptSwitch
117           1) selects new NAPT switch
118           2) installs nat flows in new NAPT switch
119           table 21(FIB)->26(PSNAT)->group(resubmit/napttunnel)->36(Terminating)->46(outbound)->47(resubmit)->21
120           3) modify the group and miss entry flow in other vSwitches pointing to newNaptSwitch
121           4) Remove nat flows in oldNaptSwitch
122      */
123     /*public void handleNaptSwitchDown(BigInteger dpnId){
124
125         LOG.debug("handleNaptSwitchDown method is called with dpnId {}",dpnId);
126         BigInteger naptSwitch;
127         try {
128             NaptSwitches naptSwitches = NatUtil.getNaptSwitch(dataBroker);
129             if (naptSwitches == null || naptSwitches.getRouterToNaptSwitch() == null || naptSwitches.getRouterToNaptSwitch().isEmpty()) {
130                 LOG.debug("NaptSwitchDown: NaptSwitch is not allocated for none of the routers");
131                 return;
132             }
133             for (RouterToNaptSwitch routerToNaptSwitch : naptSwitches.getRouterToNaptSwitch()) {
134                 String routerName = routerToNaptSwitch.getRouterName();
135                 naptSwitch = routerToNaptSwitch.getPrimarySwitchId();
136                 boolean naptStatus = isNaptSwitchDown(routerName,dpnId,naptSwitch);
137                 if (!naptStatus) {
138                     LOG.debug("NaptSwitchDown: Switch with DpnId {} is not naptSwitch for router {}",
139                             dpnId, routerName);
140                 } else {
141                     removeSnatFlowsInOldNaptSwitch(routerName,naptSwitch);
142                     return;
143                 }
144             }
145         } catch (Exception ex) {
146             LOG.error("Exception in handleNaptSwitchDown method {}",ex);
147         }
148     }*/
149
150     protected void removeSnatFlowsInOldNaptSwitch(String routerName, BigInteger naptSwitch) {
151         //remove SNAT flows in old NAPT SWITCH
152         Long routerId = NatUtil.getVpnId(dataBroker, routerName);
153         if (routerId == NatConstants.INVALID_ID) {
154             LOG.error("Invalid routerId returned for routerName {}",routerName);
155             return;
156         }
157
158         //Remove the Terminating Service table entry which forwards the packet to Outbound NAPT Table
159         String tsFlowRef = externalRouterListener.getFlowRefTs(naptSwitch, NatConstants.TERMINATING_SERVICE_TABLE, routerId);
160         FlowEntity tsNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NatConstants.TERMINATING_SERVICE_TABLE, tsFlowRef);
161
162         LOG.info("Remove the flow in table {} for the old napt switch with the DPN ID {} and router ID {}"
163                 ,NatConstants.TERMINATING_SERVICE_TABLE, naptSwitch, routerId);
164         mdsalManager.removeFlow(tsNatFlowEntity);
165
166         //Remove the Outbound flow entry which forwards the packet to Outbound NAPT Table
167         String outboundNatFlowRef = externalRouterListener.getFlowRefOutbound(naptSwitch, NatConstants.OUTBOUND_NAPT_TABLE, routerId);
168         FlowEntity outboundNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch,
169                 NatConstants.OUTBOUND_NAPT_TABLE, outboundNatFlowRef);
170         LOG.info("Remove the flow in table {} for the old napt switch with the DPN ID {} and router ID {}"
171                 ,NatConstants.OUTBOUND_NAPT_TABLE, naptSwitch, routerId);
172         mdsalManager.removeFlow(outboundNatFlowEntity);
173
174         //Remove the NAPT_PFIB_TABLE(47) flow entry forwards the packet to Fib Table for inbound traffic matching on the router ID.
175         String naptPFibflowRef = externalRouterListener.getFlowRefTs(naptSwitch, NatConstants.NAPT_PFIB_TABLE, routerId);
176         FlowEntity naptPFibFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NatConstants.NAPT_PFIB_TABLE,naptPFibflowRef);
177         LOG.info("Remove the flow in table {} for the old napt switch with the DPN ID {} and router ID {}",
178                 NatConstants.NAPT_PFIB_TABLE, naptSwitch, routerId);
179         mdsalManager.removeFlow(naptPFibFlowEntity);
180
181         //Remove the NAPT_PFIB_TABLE(47) flow entry forwards the packet to Fib Table for outbound traffic matching on the vpn ID.
182         Long vpnId = getVpnIdForRouter(routerId);
183         if (vpnId != NatConstants.INVALID_ID) {
184             String naptFibflowRef = externalRouterListener.getFlowRefTs(naptSwitch, NatConstants.NAPT_PFIB_TABLE, vpnId);
185             FlowEntity naptFibFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NatConstants.NAPT_PFIB_TABLE,naptFibflowRef);
186             LOG.info("Remove the flow in table {} for the old napt switch with the DPN ID {} and vpnId {}",
187                     NatConstants.NAPT_PFIB_TABLE, naptSwitch, vpnId);
188             mdsalManager.removeFlow(naptFibFlowEntity);
189         } else {
190             LOG.error("Invalid vpnId retrieved for routerId {}",routerId);
191             return;
192         }
193
194         //Remove Fib entries and 36-> 44
195         Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
196         if (networkId != null) {
197             List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
198             if (externalIps != null) {
199                 externalRouterListener.clrRtsFromBgpAndDelFibTs(naptSwitch, routerId, networkId, externalIps, null);
200                 LOG.debug("Successfully removed fib entries in old naptswitch {} for router {} with networkId {} and externalIps {}",
201                         naptSwitch,routerId,networkId,externalIps);
202             } else {
203                 LOG.debug("ExternalIps not found for router {} with networkId {}", routerName, networkId);
204             }
205         } else {
206             LOG.debug("network not associated to router {}", routerId);
207         }
208
209         //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
210         IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
211         if (ipPortMapping == null || ipPortMapping.getIntextIpProtocolType() == null || ipPortMapping.getIntextIpProtocolType().isEmpty()) {
212             LOG.debug("No Internal Ip Port mapping associated to router {}, no flows need to be removed in" +
213                     "oldNaptSwitch {}", routerId, naptSwitch);
214             return;
215         }
216         BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
217         List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
218         for(IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
219             if (intextIpProtocolType.getIpPortMap() == null || intextIpProtocolType.getIpPortMap().isEmpty()) {
220                 LOG.debug("No {} session associated to router {},no flows need to be removed in oldNaptSwitch {}",
221                         intextIpProtocolType.getProtocol(),routerId,naptSwitch);
222                 break;
223             }
224             List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
225             for(IpPortMap ipPortMap : ipPortMaps) {
226                 String ipPortInternal = ipPortMap.getIpPortInternal();
227                 String[] ipPortParts = ipPortInternal.split(":");
228                 if(ipPortParts.length != 2) {
229                     LOG.error("Unable to retrieve the Internal IP and port");
230                     continue;
231                 }
232                 String internalIp = ipPortParts[0];
233                 String internalPort = ipPortParts[1];
234
235                 //Build and remove flow in outbound NAPT table
236                 String switchFlowRef = NatUtil.getNaptFlowRef(naptSwitch, NatConstants.OUTBOUND_NAPT_TABLE, String.valueOf(routerId),
237                         internalIp, Integer.valueOf(internalPort));
238                 FlowEntity outboundNaptFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NatConstants.OUTBOUND_NAPT_TABLE,
239                         cookieSnatFlow, switchFlowRef);
240
241                 LOG.info("Remove the flow in table {} for old napt switch with the DPN ID {} and router ID {}",
242                         NatConstants.OUTBOUND_NAPT_TABLE,naptSwitch, routerId);
243                 mdsalManager.removeFlow(outboundNaptFlowEntity);
244
245                 IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
246                 if (ipPortExternal == null) {
247                     LOG.debug("External Ipport mapping not found for internalIp {} with port {} for router", internalIp,
248                             internalPort, routerId);
249                     continue;
250                 }
251                 String externalIp = ipPortExternal.getIpAddress();
252                 int externalPort = ipPortExternal.getPortNum();
253
254                 //Build and remove flow in  inbound NAPT table
255                 switchFlowRef = NatUtil.getNaptFlowRef(naptSwitch, NatConstants.INBOUND_NAPT_TABLE, String.valueOf(routerId),
256                         externalIp, externalPort);
257                 FlowEntity inboundNaptFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NatConstants.INBOUND_NAPT_TABLE,
258                         cookieSnatFlow, switchFlowRef);
259
260                 LOG.info("Remove the flow in table {} for old napt switch with the DPN ID {} and router ID {}",
261                         NatConstants.INBOUND_NAPT_TABLE,naptSwitch, routerId);
262                 mdsalManager.removeFlow(inboundNaptFlowEntity);
263             }
264         }
265
266     }
267
268     /*public boolean isNaptSwitchDown(String routerName, BigInteger dpnId , BigInteger naptSwitch) {
269         if (!naptSwitch.equals(dpnId)) {
270             LOG.debug("DpnId {} is not a naptSwitch {} for Router {}",dpnId, naptSwitch, routerName);
271             return false;
272         }
273         LOG.debug("NaptSwitch {} is down for Router {}", naptSwitch, routerName);
274         //elect a new NaptSwitch
275         naptSwitch = naptSwitchSelector.selectNewNAPTSwitch(routerName);
276         if (naptSwitch.equals(BigInteger.ZERO)) {
277             LOG.info("No napt switch is elected since all the switches for router {} are down",routerName);
278             boolean naptUpdatedStatus = updateNaptSwitch(routerName,naptSwitch);
279             if(!naptUpdatedStatus) {
280                 LOG.debug("Failed to update naptSwitch {} for router {} in ds", naptSwitch,routerName);
281             }
282             return true;
283         }
284         //checking elected switch health status
285         if (!getSwitchStatus(naptSwitch)) {
286             LOG.error("Newly elected Napt switch {} for router {} is down", naptSwitch, routerName);
287             return true;
288         }
289         LOG.debug("New NaptSwitch {} is up for Router {} and can proceed for flow installation",naptSwitch, routerName);
290         Long routerId = NatUtil.getVpnId(dataBroker, routerName);
291         if (routerId == NatConstants.INVALID_ID) {
292             LOG.error("Invalid routerId returned for routerName {}", routerName);
293             return true;
294         }
295         //update napt model for new napt switch
296         boolean naptUpdated = updateNaptSwitch(routerName, naptSwitch);
297         if (naptUpdated) {
298             //update group of naptswitch point to table36/ordinary switch point to naptswitchtunnelport
299             updateNaptSwitchBucketStatus(routerName, naptSwitch);
300         } else {
301             LOG.error("Failed to update naptSwitch model for newNaptSwitch {} for router {}",naptSwitch, routerName);
302         }
303
304         installSnatFlows(routerName,routerId,naptSwitch);
305
306         boolean flowInstalledStatus = handleNatFlowsInNewNaptSwitch(routerId, dpnId, naptSwitch);
307         if (flowInstalledStatus) {
308             LOG.debug("Installed all active session flows in newNaptSwitch {} for routerName {}", naptSwitch, routerName);
309         } else {
310             LOG.error("Failed to install flows in newNaptSwitch {} for routerId {}", naptSwitch, routerId);
311         }
312         return true;
313     }*/
314
315     public boolean isNaptSwitchDown(String routerName, BigInteger dpnId , BigInteger naptSwitch,Long routerVpnId) {
316         if (!naptSwitch.equals(dpnId)) {
317             LOG.debug("DpnId {} is not a naptSwitch {} for Router {}",dpnId, naptSwitch, routerName);
318             return false;
319         }
320         LOG.debug("NaptSwitch {} is down for Router {}", naptSwitch, routerName);
321         //elect a new NaptSwitch
322         naptSwitch = naptSwitchSelector.selectNewNAPTSwitch(routerName);
323         if (naptSwitch.equals(BigInteger.ZERO)) {
324             LOG.info("No napt switch is elected since all the switches for router {} are down",routerName);
325             boolean naptUpdatedStatus = updateNaptSwitch(routerName,naptSwitch);
326             if(!naptUpdatedStatus) {
327                 LOG.debug("Failed to update naptSwitch {} for router {} in ds", naptSwitch,routerName);
328             }
329             return true;
330         }
331         //checking elected switch health status
332         if (!getSwitchStatus(naptSwitch)) {
333             LOG.error("Newly elected Napt switch {} for router {} is down", naptSwitch, routerName);
334             return true;
335         }
336         LOG.debug("New NaptSwitch {} is up for Router {} and can proceed for flow installation",naptSwitch, routerName);
337         Long routerId = NatUtil.getVpnId(dataBroker, routerName);
338         if (routerId == NatConstants.INVALID_ID) {
339             LOG.error("Invalid routerId returned for routerName {}", routerName);
340             return true;
341         }
342         //update napt model for new napt switch
343         boolean naptUpdated = updateNaptSwitch(routerName, naptSwitch);
344         if (naptUpdated) {
345             //update group of naptswitch point to table36/ordinary switch point to naptswitchtunnelport
346             updateNaptSwitchBucketStatus(routerName, naptSwitch);
347         } else {
348             LOG.error("Failed to update naptSwitch model for newNaptSwitch {} for router {}",naptSwitch, routerName);
349         }
350
351         installSnatFlows(routerName,routerId,naptSwitch,routerVpnId);
352
353         boolean flowInstalledStatus = handleNatFlowsInNewNaptSwitch(routerId, dpnId, naptSwitch,routerVpnId);
354         if (flowInstalledStatus) {
355             LOG.debug("Installed all active session flows in newNaptSwitch {} for routerName {}", naptSwitch, routerName);
356         } else {
357             LOG.error("Failed to install flows in newNaptSwitch {} for routerId {}", naptSwitch, routerId);
358         }
359         return true;
360     }
361
362     private String getExtNetworkVpnName(long routerId) {
363         Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
364         if(networkId == null) {
365             LOG.error("networkId is null for the router ID {}", routerId);
366         } else {
367             final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
368             if (vpnName != null) {
369                 LOG.debug("retrieved vpn name {} associated with ext nw {} in router {}",
370                         vpnName,networkId,routerId);
371                 return vpnName;
372             } else {
373                 LOG.error("No VPN associated with ext nw {} belonging to routerId {}",
374                         networkId, routerId);
375             }
376         }
377         return null;
378     }
379
380     public void updateNaptSwitchBucketStatus(String routerName, BigInteger naptSwitch) {
381         LOG.debug("updateNaptSwitchBucketStatus method is called");
382
383         List<BigInteger> dpnList = naptSwitchSelector.getDpnsForVpn(routerName);
384         //List<BigInteger> dpnList = getDpnListForRouter(routerName);
385         for (BigInteger dpn : dpnList) {
386             if (dpn.equals(naptSwitch)) {
387                 LOG.debug("Updating SNAT_TABLE missentry for DpnId {} which is naptSwitch for router {}",dpn,routerName);
388                 List<BucketInfo> bucketInfoList = handleGroupInPrimarySwitch();
389                 modifySnatGroupEntry(naptSwitch, bucketInfoList, routerName);
390             } else {
391                 LOG.debug("Updating SNAT_TABLE missentry for DpnId {} which is not naptSwitch for router {}",dpn,routerName);
392                 List<BucketInfo> bucketInfoList = handleGroupInNeighborSwitches(dpn, routerName, naptSwitch);
393                 if (bucketInfoList == null) {
394                     LOG.debug("Failed to populate bucketInfo for orinaryswitch {} whose naptSwitch {} for router {} ",
395                             dpn,naptSwitch,routerName);
396                     return;
397                 }
398                 modifySnatGroupEntry(naptSwitch, bucketInfoList, routerName);
399             }
400         }
401     }
402
403     /*private boolean handleNatFlowsInNewNaptSwitch(Long routerId,BigInteger oldNaptSwitch, BigInteger newNaptSwitch) {
404
405         LOG.debug("Proceeding to install flows in newNaptSwitch {} for routerId {}", newNaptSwitch,routerId);
406         IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker,routerId);
407         if (ipPortMapping == null || ipPortMapping.getIntextIpProtocolType() == null || ipPortMapping.getIntextIpProtocolType().isEmpty()) {
408             LOG.debug("No Internal Ip Port mapping associated to router {}, no flows need to be installed in" +
409                     "newNaptSwitch {}", routerId, newNaptSwitch);
410             return true;
411         }
412         //getvpnId
413         Long vpnId = getVpnIdForRouter(routerId);
414         if (vpnId == NatConstants.INVALID_ID) {
415             LOG.error("Invalid vpnId for routerId {}",routerId);
416             return false;
417         }
418         Long bgpVpnId = NatConstants.INVALID_ID;
419         for (IntextIpProtocolType protocolType : ipPortMapping.getIntextIpProtocolType()) {
420             if (protocolType.getIpPortMap() == null || protocolType.getIpPortMap().isEmpty()) {
421                 LOG.debug("No {} session associated to router {}", protocolType.getProtocol(), routerId);
422                 return true;
423             }
424             for (IpPortMap intIpPortMap : protocolType.getIpPortMap()) {
425                 String internalIpAddress = intIpPortMap.getIpPortInternal().split(":")[0];
426                 String intportnum = intIpPortMap.getIpPortInternal().split(":")[1];
427
428                 //Get the external IP address and the port from the model
429                 NAPTEntryEvent.Protocol proto = protocolType.getProtocol().toString().equals(ProtocolTypes.TCP.toString())
430                         ? NAPTEntryEvent.Protocol.TCP : NAPTEntryEvent.Protocol.UDP;
431                 IpPortExternal ipPortExternal = NatUtil.getExternalIpPortMap(dataBroker, routerId,
432                         internalIpAddress, intportnum, proto);
433                 if (ipPortExternal == null) {
434                     LOG.debug("External Ipport mapping is not found for internalIp {} with port {}", internalIpAddress, intportnum);
435                     continue;
436                 }
437                 String externalIpAddress = ipPortExternal.getIpAddress();
438                 Integer extportNumber = ipPortExternal.getPortNum();
439                 LOG.debug("ExternalIPport {}:{} mapping for internal ipport {}:{}",externalIpAddress,extportNumber,
440                         internalIpAddress,intportnum);
441
442                 SessionAddress sourceAddress = new SessionAddress(internalIpAddress,Integer.valueOf(intportnum));
443                 SessionAddress externalAddress = new SessionAddress(externalIpAddress,extportNumber);
444
445                 //checking naptSwitch status before installing flows
446                 if(getSwitchStatus(newNaptSwitch)) {
447                     //Install the flow in newNaptSwitch Outbound NAPT table.
448                     try {
449                         NaptEventHandler.buildAndInstallNatFlows(newNaptSwitch, NatConstants.OUTBOUND_NAPT_TABLE,
450                                 vpnId,  routerId, bgpVpnId ,sourceAddress, externalAddress, proto);
451                     } catch (Exception ex) {
452                         LOG.error("Failed to add flow in OUTBOUND_NAPT_TABLE for routerid {} dpnId {} ipport {}:{} proto {}" +
453                                 "extIpport {}:{}", routerId, newNaptSwitch, internalIpAddress
454                                 , intportnum, proto, externalAddress, extportNumber);
455                         return false;
456                     }
457                     LOG.debug("Succesfully installed a flow in SecondarySwitch {} Outbound NAPT table for router {} " +
458                             "ipport {}:{} proto {} extIpport {}:{}", newNaptSwitch,routerId, internalIpAddress
459                             , intportnum, proto, externalAddress, extportNumber);
460                     //Install the flow in newNaptSwitch Inbound NAPT table.
461                     try {
462                         NaptEventHandler.buildAndInstallNatFlows(newNaptSwitch, NatConstants.INBOUND_NAPT_TABLE,
463                                 vpnId, routerId, bgpVpnId,externalAddress, sourceAddress, proto);
464                     } catch (Exception ex) {
465                         LOG.error("Failed to add flow in INBOUND_NAPT_TABLE for routerid {} dpnId {} extIpport{}:{} proto {} ipport {}:{}",
466                                 routerId, newNaptSwitch, externalAddress, extportNumber,
467                                 proto, internalIpAddress, intportnum);
468                         return false;
469                     }
470                     LOG.debug("Succesfully installed a flow in SecondarySwitch {} Inbound NAPT table for router {} " +
471                             "ipport {}:{} proto {} extIpport {}:{}", newNaptSwitch,routerId, internalIpAddress
472                             , intportnum, proto, externalAddress, extportNumber);
473
474                 } else {
475                     LOG.error("NewNaptSwitch {} gone down while installing flows from oldNaptswitch {}",
476                             newNaptSwitch,oldNaptSwitch);
477                     return false;
478                 }
479             }
480         }
481         return true;
482     }*/
483
484     private boolean handleNatFlowsInNewNaptSwitch(Long routerId,BigInteger oldNaptSwitch, BigInteger newNaptSwitch,Long routerVpnId) {
485
486         LOG.debug("Proceeding to install flows in newNaptSwitch {} for routerId {}", newNaptSwitch,routerId);
487         IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker,routerId);
488         if (ipPortMapping == null || ipPortMapping.getIntextIpProtocolType() == null || ipPortMapping.getIntextIpProtocolType().isEmpty()) {
489             LOG.debug("No Internal Ip Port mapping associated to router {}, no flows need to be installed in" +
490                     "newNaptSwitch {}", routerId, newNaptSwitch);
491             return true;
492         }
493         //getvpnId
494         Long vpnId = getVpnIdForRouter(routerId);
495         if (vpnId == NatConstants.INVALID_ID) {
496             LOG.error("Invalid vpnId for routerId {}",routerId);
497             return false;
498         }
499         Long bgpVpnId;
500         if(routerId.equals(routerVpnId)) {
501             bgpVpnId = NatConstants.INVALID_ID;
502         } else {
503             bgpVpnId = routerVpnId;
504         }
505         LOG.debug("retrieved bgpVpnId {} for router {}",bgpVpnId,routerId);
506         for (IntextIpProtocolType protocolType : ipPortMapping.getIntextIpProtocolType()) {
507             if (protocolType.getIpPortMap() == null || protocolType.getIpPortMap().isEmpty()) {
508                 LOG.debug("No {} session associated to router {}", protocolType.getProtocol(), routerId);
509                 return true;
510             }
511             for (IpPortMap intIpPortMap : protocolType.getIpPortMap()) {
512                 String internalIpAddress = intIpPortMap.getIpPortInternal().split(":")[0];
513                 String intportnum = intIpPortMap.getIpPortInternal().split(":")[1];
514
515                 //Get the external IP address and the port from the model
516                 NAPTEntryEvent.Protocol proto = protocolType.getProtocol().toString().equals(ProtocolTypes.TCP.toString())
517                         ? NAPTEntryEvent.Protocol.TCP : NAPTEntryEvent.Protocol.UDP;
518                 IpPortExternal ipPortExternal = NatUtil.getExternalIpPortMap(dataBroker, routerId,
519                         internalIpAddress, intportnum, proto);
520                 if (ipPortExternal == null) {
521                     LOG.debug("External Ipport mapping is not found for internalIp {} with port {}", internalIpAddress, intportnum);
522                     continue;
523                 }
524                 String externalIpAddress = ipPortExternal.getIpAddress();
525                 Integer extportNumber = ipPortExternal.getPortNum();
526                 LOG.debug("ExternalIPport {}:{} mapping for internal ipport {}:{}",externalIpAddress,extportNumber,
527                         internalIpAddress,intportnum);
528
529                 SessionAddress sourceAddress = new SessionAddress(internalIpAddress,Integer.valueOf(intportnum));
530                 SessionAddress externalAddress = new SessionAddress(externalIpAddress,extportNumber);
531
532                 //checking naptSwitch status before installing flows
533                 if(getSwitchStatus(newNaptSwitch)) {
534                     //Install the flow in newNaptSwitch Outbound NAPT table.
535                     try {
536                         NaptEventHandler.buildAndInstallNatFlows(newNaptSwitch, NatConstants.OUTBOUND_NAPT_TABLE,
537                                 vpnId,  routerId, bgpVpnId, sourceAddress, externalAddress, proto);
538                     } catch (Exception ex) {
539                         LOG.error("Failed to add flow in OUTBOUND_NAPT_TABLE for routerid {} dpnId {} ipport {}:{} proto {}" +
540                                 "extIpport {}:{} BgpVpnId {} - {}", routerId, newNaptSwitch, internalIpAddress
541                                 , intportnum, proto, externalAddress, extportNumber,bgpVpnId,ex);
542                         return false;
543                     }
544                     LOG.debug("Successfully installed a flow in SecondarySwitch {} Outbound NAPT table for router {} " +
545                             "ipport {}:{} proto {} extIpport {}:{} BgpVpnId {}", newNaptSwitch,routerId, internalIpAddress
546                             , intportnum, proto, externalAddress, extportNumber,bgpVpnId);
547                     //Install the flow in newNaptSwitch Inbound NAPT table.
548                     try {
549                         NaptEventHandler.buildAndInstallNatFlows(newNaptSwitch, NatConstants.INBOUND_NAPT_TABLE,
550                                 vpnId, routerId, bgpVpnId, externalAddress, sourceAddress, proto);
551                     } catch (Exception ex) {
552                         LOG.error("Failed to add flow in INBOUND_NAPT_TABLE for routerid {} dpnId {} extIpport{}:{} proto {} " +
553                                         "ipport {}:{} BgpVpnId {}", routerId, newNaptSwitch, externalAddress, extportNumber, proto,
554                                 internalIpAddress, intportnum,bgpVpnId);
555                         return false;
556                     }
557                     LOG.debug("Successfully installed a flow in SecondarySwitch {} Inbound NAPT table for router {} " +
558                             "ipport {}:{} proto {} extIpport {}:{} BgpVpnId {}", newNaptSwitch,routerId, internalIpAddress
559                             , intportnum, proto, externalAddress, extportNumber,bgpVpnId);
560
561                 } else {
562                     LOG.error("NewNaptSwitch {} gone down while installing flows from oldNaptswitch {}",
563                             newNaptSwitch,oldNaptSwitch);
564                     return false;
565                 }
566             }
567         }
568         return true;
569     }
570
571     private Long getVpnIdForRouter(Long routerId) {
572         try {
573             //getvpnId
574             Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
575             if (networkId == null) {
576                 LOG.debug("network is not associated to router {}", routerId);
577             } else {
578                 Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
579                 if (vpnUuid == null) {
580                     LOG.debug("vpn is not associated for network {} in router {}", networkId, routerId);
581                 } else {
582                     Long vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
583                     if (vpnId > 0) {
584                         LOG.debug("retrieved vpnId {} for router {}",vpnId,routerId);
585                         return vpnId;
586                     } else {
587                         LOG.debug("retrieved invalid vpn Id");
588                     }
589                 }
590             }
591         } catch (Exception ex){
592             LOG.debug("Exception while retrieving vpnId for router {} - {}", routerId, ex);
593         }
594         return NatConstants.INVALID_ID;
595     }
596
597 /*
598     private List<BigInteger> getDpnListForRouter(String routerName) {
599         long bgpVpnId = NatUtil.getBgpVpnId(dataBroker, routerName);
600         if (bgpVpnId != NatConstants.INVALID_ID) {
601             return NatUtil.getDpnsForRouter(dataBroker, routerName);
602         }
603         List<BigInteger> dpnList = new ArrayList<BigInteger>();
604         List<VpnToDpnList> vpnDpnList = NatUtil.getVpnToDpnList(dataBroker, routerName);
605         if (vpnDpnList == null || vpnDpnList.isEmpty()) {
606             LOG.debug("NAT Service : Unable to get the switches for the router {} from the VPNInstanceOpData", routerName);
607             dpnList = NatUtil.getDpnsForRouter(dataBroker, routerName);
608             if(dpnList == null || dpnList.isEmpty()){
609                 LOG.debug("NAT Service : No switches are part of router {}", routerName);
610                 LOG.error("NAT Service : NAPT SWITCH SELECTION STOPPED DUE TO NO DPNS SCENARIO FOR ROUTER {}", routerName);
611             }
612         } else {
613             for (VpnToDpnList vpnToDpn : vpnDpnList) {
614                 dpnList.add(vpnToDpn.getDpnId());
615             }
616         }
617         return dpnList;
618     }
619 */
620
621     public boolean getSwitchStatus(BigInteger switchId){
622         NodeId nodeId = new NodeId("openflow:" + switchId);
623         LOG.debug("Querying switch with dpnId {} is up/down", nodeId);
624         InstanceIdentifier<Node> nodeInstanceId = InstanceIdentifier.builder(Nodes.class)
625                 .child(Node.class, new NodeKey(nodeId)).build();
626         Optional<Node> nodeOptional = NatUtil.read(dataBroker,LogicalDatastoreType.OPERATIONAL,nodeInstanceId);
627         if (nodeOptional.isPresent()) {
628             LOG.debug("Switch {} is up", nodeId);
629             return true;
630         }
631         LOG.debug("Switch {} is down", nodeId);
632         return false;
633     }
634
635     public List<BucketInfo> handleGroupInPrimarySwitch() {
636         List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
637         List<ActionInfo> listActionInfoPrimary = new ArrayList<ActionInfo>();
638         listActionInfoPrimary.add(new ActionInfo(ActionType.nx_resubmit,
639                 new String[]{String.valueOf(NatConstants.TERMINATING_SERVICE_TABLE)}));
640         BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
641         listBucketInfo.add(bucketPrimary);
642         return listBucketInfo;
643     }
644
645     public List<BucketInfo> handleGroupInNeighborSwitches(BigInteger dpnId, String routerName, BigInteger naptSwitch) {
646         List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
647         String ifNamePrimary;
648         Long routerId = NatUtil.getVpnId(dataBroker, routerName);
649         if (routerId == NatConstants.INVALID_ID) {
650             LOG.error("Invalid routerId returned for routerName {}",routerName);
651             return listBucketInfo;
652         }
653         ifNamePrimary = getTunnelInterfaceName(dpnId, naptSwitch);
654         if (ifNamePrimary != null) {
655             LOG.debug("TunnelInterface {} between ordinary switch {} and naptSwitch {}",ifNamePrimary,dpnId,naptSwitch);
656             List<ActionInfo> listActionInfoPrimary = getEgressActionsForInterface(ifNamePrimary, routerId);
657             BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
658             listBucketInfo.add(bucketPrimary);
659         } else {
660             LOG.debug("No TunnelInterface between ordinary switch {} and naptSwitch {}",dpnId,naptSwitch);
661         }
662         return listBucketInfo;
663     }
664
665     protected void installSnatGroupEntry(BigInteger dpnId, List<BucketInfo> bucketInfo, String routerName) {
666         GroupEntity groupEntity = null;
667         try {
668             long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
669             LOG.debug("install SnatMissEntry for groupId {} for dpnId {} for router {}", groupId, dpnId,routerName);
670             groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
671                     GroupTypes.GroupAll, bucketInfo);
672             mdsalManager.installGroup(groupEntity);
673             LOG.debug("installed the SNAT to NAPT GroupEntity:{}", groupEntity);
674         } catch (Exception ex) {
675             LOG.error("Failed to install group for groupEntity {} : {}",groupEntity,ex);
676         }
677     }
678
679     private void modifySnatGroupEntry(BigInteger dpnId, List<BucketInfo> bucketInfo, String routerName) {
680         installSnatGroupEntry(dpnId,bucketInfo,routerName);
681         LOG.debug("modified SnatMissEntry for dpnId {} of router {}",dpnId,routerName);
682     }
683
684     protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
685         Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
686         RpcResult<GetTunnelInterfaceNameOutput> rpcResult;
687
688         try {
689             Future<RpcResult<GetTunnelInterfaceNameOutput>> result = itmManager.getTunnelInterfaceName(
690                     new GetTunnelInterfaceNameInputBuilder().setSourceDpid(srcDpId).setDestinationDpid(dstDpId).
691 //                            .setTunnelType(tunType).
692                               build());
693             rpcResult = result.get();
694             if(!rpcResult.isSuccessful()) {
695                 tunType = TunnelTypeGre.class;
696                 result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
697                         .setSourceDpid(srcDpId)
698                         .setDestinationDpid(dstDpId)
699 //                        .setTunnelType(tunType)
700                         .build());
701                 rpcResult = result.get();
702                 if(!rpcResult.isSuccessful()) {
703                     LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
704                 } else {
705                     return rpcResult.getResult().getInterfaceName();
706                 }
707                 LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
708             } else {
709                 return rpcResult.getResult().getInterfaceName();
710             }
711         } catch (InterruptedException | ExecutionException e) {
712             LOG.warn("Exception when getting tunnel interface Id for tunnel between {} and  {} : {}",
713                     srcDpId, dstDpId, e);
714         }
715
716         return null;
717     }
718
719     protected List<ActionInfo> getEgressActionsForInterface(String ifName, long routerId) {
720         LOG.debug("getEgressActionsForInterface called for interface {}", ifName);
721         List<ActionInfo> listActionInfo = new ArrayList<ActionInfo>();
722         try {
723             Future<RpcResult<GetEgressActionsForInterfaceOutput>> result =
724                     interfaceManager.getEgressActionsForInterface(
725                             new GetEgressActionsForInterfaceInputBuilder().setIntfName(ifName).setTunnelKey(routerId).build());
726             RpcResult<GetEgressActionsForInterfaceOutput> rpcResult = result.get();
727             if(!rpcResult.isSuccessful()) {
728                 LOG.warn("RPC Call to Get egress actions for interface {} returned with Errors {}"
729                         , ifName, rpcResult.getErrors());
730             } else {
731                 List<Action> actions =
732                         rpcResult.getResult().getAction();
733                 for (Action action : actions) {
734                     org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action actionClass = action.getAction();
735                     if (actionClass instanceof OutputActionCase) {
736                         listActionInfo.add(new ActionInfo(ActionType.output,
737                                 new String[] {((OutputActionCase)actionClass).getOutputAction()
738                                         .getOutputNodeConnector().getValue()}));
739                     } else if (actionClass instanceof PushVlanActionCase) {
740                         listActionInfo.add(new ActionInfo(ActionType.push_vlan, new String[] {}));
741                     } else if (actionClass instanceof SetFieldCase) {
742                         if (((SetFieldCase)actionClass).getSetField().getVlanMatch() != null) {
743                             int vlanVid = ((SetFieldCase)actionClass).getSetField().getVlanMatch()
744                                     .getVlanId().getVlanId().getValue();
745                             listActionInfo.add(new ActionInfo(ActionType.set_field_vlan_vid,
746                                     new String[] { Long.toString(vlanVid) }));
747                         }
748                     }
749                 }
750             }
751         } catch (InterruptedException | ExecutionException e) {
752             LOG.warn("Exception when egress actions for interface {}", ifName, e);
753         }
754         return listActionInfo;
755     }
756
757     public boolean updateNaptSwitch(String routerName, BigInteger naptSwitchId) {
758         RouterToNaptSwitch naptSwitch = new RouterToNaptSwitchBuilder().setKey(new RouterToNaptSwitchKey(routerName))
759                 .setPrimarySwitchId(naptSwitchId).build();
760         try {
761             MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
762                     NatUtil.buildNaptSwitchRouterIdentifier(routerName), naptSwitch);
763         } catch (Exception ex) {
764             LOG.error("Failed to write naptSwitch {} for router {} in ds",
765                     naptSwitchId,routerName);
766             return false;
767         }
768         LOG.debug("Successfully updated naptSwitch {} for router {} in ds",
769                 naptSwitchId,routerName);
770         return true;
771     }
772
773     /*public FlowEntity buildSnatFlowEntity(BigInteger dpId, String routerName, long groupId, int addordel) {
774
775         FlowEntity flowEntity;
776         long routerId = NatUtil.getVpnId(dataBroker, routerName);
777         if (routerId == NatConstants.INVALID_ID) {
778             LOG.error("Invalid routerId returned for routerName {}",routerName);
779             return null;
780         }
781         List<MatchInfo> matches = new ArrayList<MatchInfo>();
782         matches.add(new MatchInfo(MatchFieldType.eth_type,
783                 new long[]{ 0x0800L }));
784         matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
785                 BigInteger.valueOf(routerId), MetaDataUtil.METADATA_MASK_VRFID }));
786
787         String flowRef = getFlowRefSnat(dpId, NatConstants.PSNAT_TABLE, routerName);
788
789         if (addordel == NatConstants.ADD_FLOW) {
790             List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
791             List<ActionInfo> actionsInfo = new ArrayList<ActionInfo>();
792
793             ActionInfo actionSetField = new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {
794                     BigInteger.valueOf(routerId)}) ;
795             actionsInfo.add(actionSetField);
796             LOG.debug("Setting the tunnel to the list of action infos {}", actionsInfo);
797             actionsInfo.add(new ActionInfo(ActionType.group, new String[] {String.valueOf(groupId)}));
798             instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfo));
799
800             flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PSNAT_TABLE, flowRef,
801                     NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
802                     NatConstants.COOKIE_SNAT_TABLE, matches, instructions);
803         } else {
804             flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PSNAT_TABLE, flowRef,
805                     NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
806                     NatConstants.COOKIE_SNAT_TABLE, matches, null);
807         }
808         return flowEntity;
809     }*/
810
811     public FlowEntity buildSnatFlowEntity(BigInteger dpId, String routerName, long groupId, long routerVpnId, int addordel) {
812
813         FlowEntity flowEntity;
814         List<MatchInfo> matches = new ArrayList<MatchInfo>();
815         matches.add(new MatchInfo(MatchFieldType.eth_type,
816                 new long[]{ 0x0800L }));
817         matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
818                 BigInteger.valueOf(routerVpnId), MetaDataUtil.METADATA_MASK_VRFID }));
819
820         String flowRef = getFlowRefSnat(dpId, NatConstants.PSNAT_TABLE, routerName);
821
822         if (addordel == NatConstants.ADD_FLOW) {
823             List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
824             List<ActionInfo> actionsInfo = new ArrayList<ActionInfo>();
825
826             ActionInfo actionSetField = new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {
827                     BigInteger.valueOf(routerVpnId)}) ;
828             actionsInfo.add(actionSetField);
829             LOG.debug("Setting the tunnel to the list of action infos {}", actionsInfo);
830             actionsInfo.add(new ActionInfo(ActionType.group, new String[] {String.valueOf(groupId)}));
831             instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfo));
832
833             flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PSNAT_TABLE, flowRef,
834                     NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
835                     NatConstants.COOKIE_SNAT_TABLE, matches, instructions);
836         } else {
837             flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PSNAT_TABLE, flowRef,
838                     NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
839                     NatConstants.COOKIE_SNAT_TABLE, matches, null);
840         }
841         return flowEntity;
842     }
843
844     private String getFlowRefSnat(BigInteger dpnId, short tableId, String routerID) {
845         return new StringBuilder().append(NatConstants.SNAT_FLOWID_PREFIX).append(dpnId).append(NatConstants.FLOWID_SEPARATOR).
846                 append(tableId).append(NatConstants.FLOWID_SEPARATOR).append(routerID).toString();
847     }
848
849     /*protected void installSnatFlows(String routerName,Long routerId,BigInteger naptSwitch) {
850         //36 -> 46 ..Install flow forwarding packet to table46 from table36
851         LOG.debug("installTerminatingServiceTblEntry in naptswitch with dpnId {} for routerName {}", naptSwitch, routerName);
852         externalRouterListener.installTerminatingServiceTblEntry(naptSwitch, routerName);
853
854         //Install default flows punting to controller in table 46(OutBoundNapt table)
855         LOG.debug("installOutboundMissEntry in naptswitch with dpnId {} for routerName {}", naptSwitch, routerName);
856         externalRouterListener.installOutboundMissEntry(routerName, naptSwitch);
857
858         //Table 47 point to table 21 for inbound traffic
859         LOG.debug("installNaptPfibEntry in naptswitch with dpnId {} for routerId {}", naptSwitch, routerId);
860         externalRouterListener.installNaptPfibEntry(naptSwitch, routerId);
861
862         String vpnName = getExtNetworkVpnName(routerId);
863         if(vpnName != null) {
864             //Table 47 point to table 21 for outbound traffic
865             long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
866             if(vpnId > 0) {
867                 LOG.debug("installNaptPfibEntry fin naptswitch with dpnId {} for vpnId {}", naptSwitch, vpnId);
868                 externalRouterListener.installNaptPfibEntry(naptSwitch, vpnId);
869             } else {
870                 LOG.debug("Associated vpnId not found for router {}",routerId);
871             }
872
873             //Install Fib entries for ExternalIps & program 36 -> 44
874             List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker,routerId);
875             if (externalIps != null) {
876                 for (String externalIp : externalIps) {
877                     LOG.debug("advToBgpAndInstallFibAndTsFlows in naptswitch id {} with vpnName {} and externalIp {}",
878                             naptSwitch, vpnName, externalIp);
879                     externalRouterListener.advToBgpAndInstallFibAndTsFlows(naptSwitch, NatConstants.INBOUND_NAPT_TABLE,
880                             vpnName, routerId, externalIp, vpnService, fibService, bgpManager, dataBroker, LOG);
881                     LOG.debug("Successfully added fib entries in naptswitch {} for router {} with external IP {}", naptSwitch,
882                             routerId, externalIp);
883                 }
884             } else {
885                 LOG.debug("External Ip not found for routerId {}",routerId);
886             }
887         } else {
888             LOG.debug("Associated vpnName not found for router {}",routerId);
889         }
890     }*/
891
892     protected void installSnatFlows(String routerName,Long routerId,BigInteger naptSwitch,Long routerVpnId) {
893
894         if(routerId.equals(routerVpnId)) {
895             LOG.debug("Installing flows for router with internalvpnId");
896             //36 -> 46 ..Install flow forwarding packet to table46 from table36
897             LOG.debug("installTerminatingServiceTblEntry in naptswitch with dpnId {} for routerName {} with routerId {}",
898                     naptSwitch, routerName,routerId);
899             externalRouterListener.installTerminatingServiceTblEntry(naptSwitch, routerName);
900
901             //Install default flows punting to controller in table 46(OutBoundNapt table)
902             LOG.debug("installOutboundMissEntry in naptswitch with dpnId {} for routerName {} with routerId {}",
903                     naptSwitch, routerName, routerId);
904             externalRouterListener.createOutboundTblEntry(naptSwitch, routerId);
905
906             //Table 47 point to table 21 for inbound traffic
907             LOG.debug("installNaptPfibEntry in naptswitch with dpnId {} for router {}", naptSwitch, routerId);
908             externalRouterListener.installNaptPfibEntry(naptSwitch, routerId);
909         } else {
910             //36 -> 46 ..Install flow forwarding packet to table46 from table36
911             LOG.debug("installTerminatingServiceTblEntry in naptswitch with dpnId {} for routerName {} with BgpVpnId {}",
912                     naptSwitch, routerName, routerVpnId);
913             externalRouterListener.installTerminatingServiceTblEntryWithUpdatedVpnId(naptSwitch, routerName, routerVpnId);
914
915             //Install default flows punting to controller in table 46(OutBoundNapt table)
916             LOG.debug("installOutboundMissEntry in naptswitch with dpnId {} for routerName {} with BgpVpnId {}",
917                     naptSwitch, routerName, routerVpnId);
918             externalRouterListener.createOutboundTblEntryWithBgpVpn(naptSwitch, routerId, routerVpnId);
919
920             //Table 47 point to table 21 for inbound traffic
921             LOG.debug("installNaptPfibEntry in naptswitch with dpnId {} for router {} with BgpVpnId {}",
922                     naptSwitch, routerId, routerVpnId);
923             externalRouterListener.installNaptPfibEntryWithBgpVpn(naptSwitch, routerId, routerVpnId);
924         }
925
926         String vpnName = getExtNetworkVpnName(routerId);
927         if(vpnName != null) {
928             //Table 47 point to table 21 for outbound traffic
929             long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
930             if(vpnId > 0) {
931                 LOG.debug("installNaptPfibEntry fin naptswitch with dpnId {} for BgpVpnId {}", naptSwitch, vpnId);
932                 externalRouterListener.installNaptPfibEntry(naptSwitch, vpnId);
933             } else {
934                 LOG.debug("Associated BgpvpnId not found for router {}",routerId);
935             }
936
937             //Install Fib entries for ExternalIps & program 36 -> 44
938             List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker,routerId);
939             if (externalIps != null) {
940                 for (String externalIp : externalIps) {
941                     LOG.debug("advToBgpAndInstallFibAndTsFlows in naptswitch id {} with vpnName {} and externalIp {}",
942                             naptSwitch, vpnName, externalIp);
943                     externalRouterListener.advToBgpAndInstallFibAndTsFlows(naptSwitch, NatConstants.INBOUND_NAPT_TABLE,
944                             vpnName, routerId, externalIp, vpnService, fibService, bgpManager, dataBroker, LOG);
945                     LOG.debug("Successfully added fib entries in naptswitch {} for router {} with external IP {}", naptSwitch,
946                             routerId, externalIp);
947                 }
948             } else {
949                 LOG.debug("External Ip not found for routerId {}",routerId);
950             }
951         } else {
952             LOG.debug("Associated vpnName not found for router {}",routerId);
953         }
954     }
955 }