Use managed transactions in natservice-impl
[netvirt.git] / natservice / impl / src / main / java / org / opendaylight / netvirt / natservice / internal / NatInterfaceStateChangeListener.java
1 /*
2  * Copyright (c) 2016 - 2017 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.HashBasedTable;
12 import com.google.common.collect.Table;
13 import com.google.common.util.concurrent.ListenableFuture;
14 import java.math.BigInteger;
15 import java.util.ArrayList;
16 import java.util.List;
17 import java.util.concurrent.Callable;
18 import java.util.concurrent.ExecutionException;
19 import java.util.concurrent.Future;
20
21 import javax.annotation.PostConstruct;
22 import javax.inject.Inject;
23 import javax.inject.Singleton;
24 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
25 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
26 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
27 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
28 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
29 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
30 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
31 import org.opendaylight.genius.mdsalutil.FlowEntity;
32 import org.opendaylight.genius.mdsalutil.NwConstants;
33 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
34 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
35 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
36 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.vpn._interface.VpnInstanceNames;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.L2vlan;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.router.interfaces.RouterInterface;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntry;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.NaptSwitches;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProtocolTypes;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPorts;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.Ports;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMap;
49 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;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitch;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.intip.port.map.IpPort;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.intip.port.map.ip.port.IntIpProtoType;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetFixedIPsForNeutronPortInputBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetFixedIPsForNeutronPortOutput;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NeutronvpnService;
57 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
58 import org.opendaylight.yangtools.yang.common.RpcResult;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
61
62 @Singleton
63 public class NatInterfaceStateChangeListener
64     extends AsyncDataTreeChangeListenerBase<Interface, NatInterfaceStateChangeListener> {
65
66     private static final Logger LOG = LoggerFactory.getLogger(NatInterfaceStateChangeListener.class);
67     private static final String NAT_DS = "NATDS";
68     private final DataBroker dataBroker;
69     private final ManagedNewTransactionRunner txRunner;
70     private final OdlInterfaceRpcService odlInterfaceRpcService;
71     private final JobCoordinator coordinator;
72     private final FloatingIPListener floatingIPListener;
73     private final NeutronvpnService neutronVpnService;
74     private final IMdsalApiManager mdsalManager;
75     private final NaptManager naptManager;
76     Table<Interface.OperStatus, Interface.OperStatus, IntfTransitionState> stateTable = HashBasedTable.create();
77
78     enum IntfTransitionState {
79         STATE_UP,
80         STATE_DOWN,
81         STATE_IGNORE
82     }
83
84     private void initialize() {
85         //  Interface State Transition Table
86         //               Up                Down            Unknown
87         // ---------------------------------------------------------------
88         /* Up       { STATE_IGNORE,   STATE_DOWN,     STATE_DOWN }, */
89         /* Down     { STATE_UP,       STATE_IGNORE,   STATE_IGNORE }, */
90         /* Unknown  { STATE_UP,       STATE_DOWN,     STATE_IGNORE }, */
91         stateTable.put(Interface.OperStatus.Up, Interface.OperStatus.Down, IntfTransitionState.STATE_DOWN);
92         stateTable.put(Interface.OperStatus.Down, Interface.OperStatus.Up, IntfTransitionState.STATE_UP);
93         stateTable.put(Interface.OperStatus.Unknown, Interface.OperStatus.Up, IntfTransitionState.STATE_UP);
94         stateTable.put(Interface.OperStatus.Unknown, Interface.OperStatus.Down, IntfTransitionState.STATE_DOWN);
95         stateTable.put(Interface.OperStatus.Up, Interface.OperStatus.Unknown, IntfTransitionState.STATE_DOWN);
96     }
97
98     @Inject
99     public NatInterfaceStateChangeListener(final DataBroker dataBroker,
100             final OdlInterfaceRpcService odlInterfaceRpcService, final JobCoordinator coordinator,
101             final FloatingIPListener floatingIPListener,final NeutronvpnService neutronvpnService,
102             final IMdsalApiManager mdsalManager, final NaptManager naptManager) {
103         super(Interface.class, NatInterfaceStateChangeListener.class);
104         this.dataBroker = dataBroker;
105         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
106         this.odlInterfaceRpcService = odlInterfaceRpcService;
107         this.coordinator = coordinator;
108         this.floatingIPListener = floatingIPListener;
109         this.neutronVpnService = neutronvpnService;
110         this.mdsalManager = mdsalManager;
111         this.naptManager = naptManager;
112         initialize();
113     }
114
115     @Override
116     @PostConstruct
117     public void init() {
118         LOG.info("{} init", getClass().getSimpleName());
119         registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
120     }
121
122     @Override
123     protected InstanceIdentifier<Interface> getWildCardPath() {
124         return InstanceIdentifier.create(InterfacesState.class).child(Interface.class);
125     }
126
127     @Override
128     protected NatInterfaceStateChangeListener getDataTreeChangeListener() {
129         return NatInterfaceStateChangeListener.this;
130     }
131
132     @Override
133     // TODO Clean up the exception handling
134     @SuppressWarnings("checkstyle:IllegalCatch")
135     protected void add(InstanceIdentifier<Interface> identifier, Interface intrf) {
136         LOG.trace("add : Interface {} up event received", intrf);
137         if (!L2vlan.class.equals(intrf.getType())) {
138             LOG.debug("add : Interface {} is not Vlan Interface.Ignoring", intrf.getName());
139             return;
140         }
141         String interfaceName = intrf.getName();
142         BigInteger intfDpnId;
143         try {
144             intfDpnId = NatUtil.getDpIdFromInterface(intrf);
145         } catch (Exception e) {
146             LOG.error("add : Exception occured while retriving dpnid for interface {}", intrf.getName(), e);
147             return;
148         }
149         if (BigInteger.ZERO.equals(intfDpnId)) {
150             LOG.warn("add : Could not retrieve dp id for interface {} ", interfaceName);
151             return;
152         }
153         // We service only VM interfaces. We do not service Tunnel Interfaces here.
154         // Tunnel events are directly serviced by TunnelInterfacesStateListener present as part of
155         // VpnInterfaceManager
156         RouterInterface routerInterface = NatUtil.getConfiguredRouterInterface(dataBroker, interfaceName);
157         if (routerInterface != null) {
158             String routerName = routerInterface.getRouterName();
159             NatInterfaceStateAddWorker natIfaceStateAddWorker = new NatInterfaceStateAddWorker(interfaceName,
160                     intfDpnId, routerName);
161             coordinator.enqueueJob(NAT_DS + "-" + intrf.getName(), natIfaceStateAddWorker);
162
163             NatFlowAddWorker natFlowAddWorker = new NatFlowAddWorker(interfaceName, routerName);
164             coordinator.enqueueJob(NAT_DS + "-" + interfaceName, natFlowAddWorker, NatConstants.NAT_DJC_MAX_RETRIES);
165         } else {
166             LOG.info("add : Router-Interface Mapping not found for Interface : {}", interfaceName);
167         }
168     }
169
170     @Override
171     // TODO Clean up the exception handling
172     @SuppressWarnings("checkstyle:IllegalCatch")
173     protected void remove(InstanceIdentifier<Interface> identifier, Interface intrf) {
174         LOG.trace("remove : Interface {} removed event received", intrf);
175         if (!L2vlan.class.equals(intrf.getType())) {
176             LOG.debug("remove : Interface {} is not Vlan Interface.Ignoring", intrf.getName());
177             return;
178         }
179         String interfaceName = intrf.getName();
180         BigInteger intfDpnId = BigInteger.ZERO;
181         try {
182             intfDpnId = NatUtil.getDpIdFromInterface(intrf);
183         } catch (Exception e) {
184             LOG.error("remove : Exception occured while retriving dpnid for interface {}",  intrf.getName(), e);
185             InstanceIdentifier<VpnInterface> id = NatUtil.getVpnInterfaceIdentifier(interfaceName);
186             Optional<VpnInterface> cfgVpnInterface =
187                     SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(
188                             dataBroker, LogicalDatastoreType.CONFIGURATION, id);
189             if (!cfgVpnInterface.isPresent()) {
190                 LOG.warn("remove : Interface {} is not a VPN Interface, ignoring.", interfaceName);
191                 return;
192             }
193             for (VpnInstanceNames vpnInterfaceVpnInstance : cfgVpnInterface.get().getVpnInstanceNames()) {
194                 String vpnName  = vpnInterfaceVpnInstance.getVpnName();
195                 InstanceIdentifier<VpnInterfaceOpDataEntry> idOper = NatUtil
196                       .getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
197                 Optional<VpnInterfaceOpDataEntry> optVpnInterface =
198                       SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(
199                             dataBroker, LogicalDatastoreType.OPERATIONAL, idOper);
200                 if (optVpnInterface.isPresent()) {
201                     intfDpnId = optVpnInterface.get().getDpnId();
202                     break;
203                 }
204             }
205         }
206         if (intfDpnId.equals(BigInteger.ZERO)) {
207             LOG.warn("remove : Could not retrieve dpnid for interface {} ", interfaceName);
208             return;
209         }
210         RouterInterface routerInterface = NatUtil.getConfiguredRouterInterface(dataBroker, interfaceName);
211         if (routerInterface != null) {
212             String routerName = routerInterface.getRouterName();
213             NatInterfaceStateRemoveWorker natIfaceStateRemoveWorker = new NatInterfaceStateRemoveWorker(interfaceName,
214                     intfDpnId, routerName);
215             coordinator.enqueueJob(NAT_DS + "-" + interfaceName, natIfaceStateRemoveWorker);
216
217             NatFlowRemoveWorker natFlowRemoveWorker = new NatFlowRemoveWorker(intrf, intfDpnId, routerName);
218             coordinator.enqueueJob(NAT_DS + "-" + interfaceName, natFlowRemoveWorker,
219                     NatConstants.NAT_DJC_MAX_RETRIES);
220         } else {
221             LOG.info("remove : Router-Interface Mapping not found for Interface : {}", interfaceName);
222         }
223     }
224
225     @Override
226     // TODO Clean up the exception handling
227     @SuppressWarnings("checkstyle:IllegalCatch")
228     protected void update(InstanceIdentifier<Interface> identifier, Interface original, Interface update) {
229         LOG.trace("update : Operation Interface update event - Old: {}, New: {}", original, update);
230         if (!L2vlan.class.equals(update.getType())) {
231             LOG.debug("update : Interface {} is not Vlan Interface.Ignoring", update.getName());
232             return;
233         }
234         BigInteger intfDpnId = BigInteger.ZERO;
235         String interfaceName = update.getName();
236         try {
237             intfDpnId = NatUtil.getDpIdFromInterface(update);
238         } catch (Exception e) {
239             LOG.error("update : Exception occured while retriving dpnid for interface {}",  update.getName(), e);
240             InstanceIdentifier<VpnInterface> id = NatUtil.getVpnInterfaceIdentifier(interfaceName);
241             Optional<VpnInterface> cfgVpnInterface =
242                     SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(
243                             dataBroker, LogicalDatastoreType.CONFIGURATION, id);
244             if (!cfgVpnInterface.isPresent()) {
245                 LOG.warn("update : Interface {} is not a VPN Interface, ignoring.", interfaceName);
246                 return;
247             }
248             for (VpnInstanceNames vpnInterfaceVpnInstance : cfgVpnInterface.get().getVpnInstanceNames()) {
249                 String vpnName  = vpnInterfaceVpnInstance.getVpnName();
250                 InstanceIdentifier<VpnInterfaceOpDataEntry> idOper = NatUtil
251                       .getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
252                 Optional<VpnInterfaceOpDataEntry> optVpnInterface =
253                       SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(
254                             dataBroker, LogicalDatastoreType.OPERATIONAL, idOper);
255                 if (optVpnInterface.isPresent()) {
256                     intfDpnId = optVpnInterface.get().getDpnId();
257                     break;
258                 }
259             }
260         }
261         if (intfDpnId.equals(BigInteger.ZERO)) {
262             LOG.warn("remove : Could not retrieve dpnid for interface {} ", interfaceName);
263             return;
264         }
265         RouterInterface routerInterface = NatUtil.getConfiguredRouterInterface(dataBroker, interfaceName);
266         if (routerInterface != null) {
267             String routerName = routerInterface.getRouterName();
268             NatInterfaceStateUpdateWorker natIfaceStateupdateWorker = new NatInterfaceStateUpdateWorker(original,
269                     update, intfDpnId, routerName);
270             coordinator.enqueueJob(NAT_DS + "-" + update.getName(), natIfaceStateupdateWorker);
271             NatFlowUpdateWorker natFlowUpdateWorker = new NatFlowUpdateWorker(original, update, routerName);
272             coordinator.enqueueJob(NAT_DS + "-" + update.getName(), natFlowUpdateWorker,
273                     NatConstants.NAT_DJC_MAX_RETRIES);
274         } else {
275             LOG.info("update : Router-Interface Mapping not found for Interface : {}", interfaceName);
276         }
277     }
278
279     void handleRouterInterfacesUpEvent(String routerName, String interfaceName, BigInteger dpId,
280             WriteTransaction writeOperTxn) {
281         LOG.debug("handleRouterInterfacesUpEvent : Handling UP event for router interface {} in Router {} on Dpn {}",
282                 interfaceName, routerName, dpId);
283         NatUtil.addToNeutronRouterDpnsMap(dataBroker, routerName, interfaceName, dpId, writeOperTxn);
284         NatUtil.addToDpnRoutersMap(dataBroker, routerName, interfaceName, dpId, writeOperTxn);
285     }
286
287     void handleRouterInterfacesDownEvent(String routerName, String interfaceName, BigInteger dpnId,
288                                          WriteTransaction writeOperTxn) {
289         LOG.debug("handleRouterInterfacesDownEvent : Handling DOWN event for router Interface {} in Router {}",
290                 interfaceName, routerName);
291         NatUtil.removeFromNeutronRouterDpnsMap(dataBroker, routerName, interfaceName, dpnId, writeOperTxn);
292         NatUtil.removeFromDpnRoutersMap(dataBroker, routerName, interfaceName, dpnId, odlInterfaceRpcService,
293                 writeOperTxn);
294     }
295
296     private IntfTransitionState getTransitionState(Interface.OperStatus original , Interface.OperStatus updated) {
297         IntfTransitionState transitionState = stateTable.get(original, updated);
298
299         if (transitionState == null) {
300             return IntfTransitionState.STATE_IGNORE;
301         }
302         return transitionState;
303     }
304
305     private class NatInterfaceStateAddWorker implements Callable<List<ListenableFuture<Void>>> {
306         private String interfaceName;
307         private String routerName;
308         private BigInteger intfDpnId;
309
310         NatInterfaceStateAddWorker(String interfaceName, BigInteger intfDpnId, String routerName) {
311             this.interfaceName = interfaceName;
312             this.routerName = routerName;
313             this.intfDpnId = intfDpnId;
314         }
315
316         @Override
317         @SuppressWarnings("checkstyle:IllegalCatch")
318         public List<ListenableFuture<Void>> call() {
319             List<ListenableFuture<Void>> futures = new ArrayList<>();
320             try {
321                 LOG.trace("call : Received interface {} PORT UP OR ADD event ", interfaceName);
322                 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx ->
323                     handleRouterInterfacesUpEvent(routerName, interfaceName, intfDpnId, tx)));
324             } catch (Exception e) {
325                 LOG.error("call : Exception caught in Interface {} Operational State Up event",
326                         interfaceName, e);
327             }
328             return futures;
329         }
330     }
331
332     private class NatInterfaceStateRemoveWorker implements Callable<List<ListenableFuture<Void>>> {
333         private String interfaceName;
334         private String routerName;
335         private BigInteger intfDpnId;
336
337         NatInterfaceStateRemoveWorker(String interfaceName, BigInteger intfDpnId, String routerName) {
338             this.interfaceName = interfaceName;
339             this.routerName = routerName;
340             this.intfDpnId = intfDpnId;
341         }
342
343         @Override
344         @SuppressWarnings("checkstyle:IllegalCatch")
345         public List<ListenableFuture<Void>> call() {
346             List<ListenableFuture<Void>> futures = new ArrayList<>();
347             try {
348                 LOG.trace("call : Received interface {} PORT DOWN or REMOVE event", interfaceName);
349                 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx ->
350                         handleRouterInterfacesDownEvent(routerName, interfaceName, intfDpnId, tx)));
351             } catch (Exception e) {
352                 LOG.error("call : Exception observed in handling deletion of VPN Interface {}.", interfaceName, e);
353             }
354             return futures;
355         }
356     }
357
358     private class NatInterfaceStateUpdateWorker implements Callable<List<ListenableFuture<Void>>> {
359         private Interface original;
360         private Interface update;
361         private BigInteger intfDpnId;
362         private String routerName;
363
364         NatInterfaceStateUpdateWorker(Interface original, Interface update, BigInteger intfDpnId, String routerName) {
365             this.original = original;
366             this.update = update;
367             this.intfDpnId = intfDpnId;
368             this.routerName = routerName;
369         }
370
371         @Override
372         @SuppressWarnings("checkstyle:IllegalCatch")
373         public List<ListenableFuture<Void>> call() {
374             List<ListenableFuture<Void>> futures = new ArrayList<>();
375             try {
376                 final String interfaceName = update.getName();
377                 LOG.trace("call : Received interface {} state change event", interfaceName);
378                 LOG.debug("call : DPN ID {} for the interface {} ", intfDpnId, interfaceName);
379                 IntfTransitionState state = getTransitionState(original.getOperStatus(), update.getOperStatus());
380                 if (state.equals(IntfTransitionState.STATE_IGNORE)) {
381                     LOG.info("NAT Service: Interface {} state original {} updated {} not handled",
382                             interfaceName, original.getOperStatus(), update.getOperStatus());
383                     return futures;
384                 }
385                 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
386                     if (state.equals(IntfTransitionState.STATE_DOWN)) {
387                         LOG.debug("call : DPN {} connnected to the interface {} has gone down."
388                                 + "Hence clearing the dpn-vpninterfaces-list entry from the"
389                                 + " neutron-router-dpns model in the ODL:L3VPN", intfDpnId, interfaceName);
390                         // If the interface state is unknown, it means that the corresponding DPN has gone down.
391                         // So remove the dpn-vpninterfaces-list from the neutron-router-dpns model.
392                         NatUtil.removeFromNeutronRouterDpnsMap(dataBroker, routerName, intfDpnId, tx);
393                     } else if (state.equals(IntfTransitionState.STATE_UP)) {
394                         LOG.debug("call : DPN {} connnected to the interface {} has come up. Hence adding"
395                                 + " the dpn-vpninterfaces-list entry from the neutron-router-dpns model"
396                                 + " in the ODL:L3VPN", intfDpnId, interfaceName);
397                         handleRouterInterfacesUpEvent(routerName, interfaceName, intfDpnId, tx);
398                     }
399                 }));
400             } catch (Exception e) {
401                 LOG.error("call : Exception observed in handling updation of VPN Interface {}.", update.getName(), e);
402             }
403             return futures;
404         }
405     }
406
407     private void processInterfaceAdded(String portName, String routerId, List<ListenableFuture<Void>> futures) {
408         LOG.trace("processInterfaceAdded : Processing Interface Add Event for interface {}", portName);
409         List<InternalToExternalPortMap> intExtPortMapList = getIntExtPortMapListForPortName(portName, routerId);
410         if (intExtPortMapList == null || intExtPortMapList.isEmpty()) {
411             LOG.debug("processInterfaceAdded : Ip Mapping list is empty/null for portname {}", portName);
412             return;
413         }
414         InstanceIdentifier<RouterPorts> portIid = NatUtil.buildRouterPortsIdentifier(routerId);
415         ListenableFuture<Void> future = txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
416             for (InternalToExternalPortMap intExtPortMap : intExtPortMapList) {
417                 floatingIPListener.createNATFlowEntries(portName, intExtPortMap, portIid, routerId, tx);
418             }
419         });
420         futures.add(future);
421         try {
422             future.get();
423         } catch (InterruptedException | ExecutionException e) {
424             LOG.error("Error processing interface addition", e);
425         }
426     }
427
428     private List<InternalToExternalPortMap> getIntExtPortMapListForPortName(String portName, String routerId) {
429         InstanceIdentifier<Ports> portToIpMapIdentifier = NatUtil.buildPortToIpMapIdentifier(routerId, portName);
430         Optional<Ports> port =
431                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
432                         LogicalDatastoreType.CONFIGURATION, portToIpMapIdentifier);
433         if (!port.isPresent()) {
434             LOG.info("getIntExtPortMapListForPortName : Unable to read router port entry for router ID {} "
435                     + "and port name {}", routerId, portName);
436             return null;
437         }
438         return port.get().getInternalToExternalPortMap();
439     }
440
441     private BigInteger getNaptSwitchforRouter(DataBroker broker, String routerName) {
442         InstanceIdentifier<RouterToNaptSwitch> rtrNaptSw = InstanceIdentifier.builder(NaptSwitches.class)
443             .child(RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();
444         Optional<RouterToNaptSwitch> routerToNaptSwitchData =
445                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
446                         LogicalDatastoreType.CONFIGURATION, rtrNaptSw);
447         if (routerToNaptSwitchData.isPresent()) {
448             RouterToNaptSwitch routerToNaptSwitchInstance = routerToNaptSwitchData.get();
449             return routerToNaptSwitchInstance.getPrimarySwitchId();
450         }
451         return null;
452     }
453
454     private void removeNatFlow(BigInteger dpnId, short tableId, Long routerId, String ipAddress, int ipPort) {
455
456         String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, tableId, String.valueOf(routerId), ipAddress, ipPort);
457         FlowEntity snatFlowEntity = NatUtil.buildFlowEntity(dpnId, tableId, switchFlowRef);
458
459         mdsalManager.removeFlow(snatFlowEntity);
460         LOG.debug("removeNatFlow : Removed the flow in table {} for the switch with the DPN ID {} for "
461             + "router {} ip {} port {}", tableId, dpnId, routerId, ipAddress, ipPort);
462     }
463
464     private List<String> getFixedIpsForPort(String interfname) {
465         LOG.debug("getFixedIpsForPort : getFixedIpsForPort method is called for interface {}", interfname);
466         try {
467             Future<RpcResult<GetFixedIPsForNeutronPortOutput>> result =
468                 neutronVpnService.getFixedIPsForNeutronPort(new GetFixedIPsForNeutronPortInputBuilder()
469                     .setPortId(new Uuid(interfname)).build());
470
471             RpcResult<GetFixedIPsForNeutronPortOutput> rpcResult = result.get();
472             if (!rpcResult.isSuccessful()) {
473                 LOG.error("getFixedIpsForPort : RPC Call to GetFixedIPsForNeutronPortOutput returned with Errors {}",
474                     rpcResult.getErrors());
475             } else {
476                 return rpcResult.getResult().getFixedIPs();
477             }
478         } catch (InterruptedException | ExecutionException | NullPointerException ex) {
479             LOG.error("getFixedIpsForPort : Exception while receiving fixedIps for port {}", interfname, ex);
480         }
481         return null;
482     }
483
484     private void processInterfaceRemoved(String portName, BigInteger dpnId, String routerId,
485             List<ListenableFuture<Void>> futures) {
486         LOG.trace("processInterfaceRemoved : Processing Interface Removed Event for interface {} on DPN ID {}",
487                 portName, dpnId);
488         List<InternalToExternalPortMap> intExtPortMapList = getIntExtPortMapListForPortName(portName, routerId);
489         if (intExtPortMapList == null || intExtPortMapList.isEmpty()) {
490             LOG.debug("processInterfaceRemoved : Ip Mapping list is empty/null for portName {}", portName);
491             return;
492         }
493         InstanceIdentifier<RouterPorts> portIid = NatUtil.buildRouterPortsIdentifier(routerId);
494         ListenableFuture<Void> future = txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
495             for (InternalToExternalPortMap intExtPortMap : intExtPortMapList) {
496                 LOG.trace("processInterfaceRemoved : Removing DNAT Flow entries for dpnId {} ", dpnId);
497                 floatingIPListener.removeNATFlowEntries(portName, intExtPortMap, portIid, routerId, dpnId, tx);
498             }
499         });
500         futures.add(future);
501         try {
502             future.get();
503         } catch (InterruptedException | ExecutionException e) {
504             LOG.error("Error processing interface removal", e);
505         }
506     }
507
508     // TODO Clean up the exception handling
509     @SuppressWarnings("checkstyle:IllegalCatch")
510     private void removeSnatEntriesForPort(String interfaceName, String routerName) {
511         Long routerId = NatUtil.getVpnId(dataBroker, routerName);
512         if (routerId == NatConstants.INVALID_ID) {
513             LOG.error("removeSnatEntriesForPort : routerId not found for routername {}", routerName);
514             return;
515         }
516         BigInteger naptSwitch = getNaptSwitchforRouter(dataBroker, routerName);
517         if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
518             LOG.error("removeSnatEntriesForPort : NaptSwitch is not elected for router {} with Id {}",
519                     routerName, routerId);
520             return;
521         }
522         //getInternalIp for port
523         List<String> fixedIps = getFixedIpsForPort(interfaceName);
524         if (fixedIps == null) {
525             LOG.warn("removeSnatEntriesForPort : Internal Ips not found for InterfaceName {} in router {} with id {}",
526                 interfaceName, routerName, routerId);
527             return;
528         }
529
530         for (String internalIp : fixedIps) {
531             LOG.debug("removeSnatEntriesForPort : Internal Ip retrieved for interface {} is {} in router with Id {}",
532                 interfaceName, internalIp, routerId);
533             IpPort ipPort = NatUtil.getInternalIpPortInfo(dataBroker, routerId, internalIp);
534             if (ipPort == null) {
535                 LOG.debug("removeSnatEntriesForPort : no snatint-ip-port-map found for ip:{}", internalIp);
536                 continue;
537             }
538
539             for (IntIpProtoType protoType: ipPort.getIntIpProtoType()) {
540                 ProtocolTypes protocol = protoType.getProtocol();
541                 for (Integer portnum : protoType.getPorts()) {
542                     //build and remove the flow in outbound table
543                     try {
544                         removeNatFlow(naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE, routerId, internalIp, portnum);
545                     } catch (Exception ex) {
546                         LOG.error("removeSnatEntriesForPort : Failed to remove snat flow for internalIP {} with "
547                                 + "Port {} protocol {} for routerId {} in OUTBOUNDTABLE of NaptSwitch {}",
548                             internalIp, portnum, protocol, routerId, naptSwitch, ex);
549                     }
550                     //Get the external IP address and the port from the model
551                     NAPTEntryEvent.Protocol proto = protocol.toString().equals(ProtocolTypes.TCP.toString())
552                         ? NAPTEntryEvent.Protocol.TCP : NAPTEntryEvent.Protocol.UDP;
553                     IpPortExternal ipPortExternal = NatUtil.getExternalIpPortMap(dataBroker, routerId,
554                         internalIp, String.valueOf(portnum), proto);
555                     if (ipPortExternal == null) {
556                         LOG.error("removeSnatEntriesForPort : Mapping for internalIp {} with port {} is not found in "
557                             + "router with Id {}", internalIp, portnum, routerId);
558                         return;
559                     }
560                     String externalIpAddress = ipPortExternal.getIpAddress();
561                     Integer portNumber = ipPortExternal.getPortNum();
562
563                     //build and remove the flow in inboundtable
564                     try {
565                         removeNatFlow(naptSwitch, NwConstants.INBOUND_NAPT_TABLE, routerId,
566                             externalIpAddress, portNumber);
567                     } catch (Exception ex) {
568                         LOG.error("removeSnatEntriesForPort : Failed to remove snat flow internalIP {} with "
569                                 + "Port {} protocol {} for routerId {} in INBOUNDTABLE of naptSwitch {}",
570                             externalIpAddress, portNumber, protocol, routerId, naptSwitch, ex);
571                     }
572
573                     String internalIpPort = internalIp + ":" + portnum;
574                     // delete the entry from IntExtIpPortMap DS
575                     try {
576                         naptManager.removeFromIpPortMapDS(routerId, internalIpPort, proto);
577                         naptManager.removePortFromPool(internalIpPort, externalIpAddress);
578                     } catch (Exception ex) {
579                         LOG.error("removeSnatEntriesForPort : releaseIpExtPortMapping failed, Removal of "
580                             + "ipportmap {} for router {} failed", internalIpPort, routerId, ex);
581                     }
582                 }
583             }
584             // delete the entry from SnatIntIpPortMap DS
585             LOG.debug("removeSnatEntriesForPort : Removing InternalIp:{} on router {}", internalIp, routerId);
586             naptManager.removeFromSnatIpPortDS(routerId, internalIp);
587         }
588     }
589
590     private class NatFlowAddWorker implements Callable<List<ListenableFuture<Void>>> {
591         private String interfaceName;
592         private String routerName;
593
594         NatFlowAddWorker(String interfaceName,String routerName) {
595             this.interfaceName = interfaceName;
596             this.routerName = routerName;
597         }
598
599         @Override
600         @SuppressWarnings("checkstyle:IllegalCatch")
601         public List<ListenableFuture<Void>> call() {
602             final List<ListenableFuture<Void>> futures = new ArrayList<>();
603             LOG.trace("call : Interface {} up event received", interfaceName);
604             try {
605                 LOG.trace("call : Port added event received for interface {} ", interfaceName);
606                 processInterfaceAdded(interfaceName, routerName, futures);
607             } catch (Exception ex) {
608                 LOG.error("call : Exception caught in Interface {} Operational State Up event",
609                         interfaceName, ex);
610             }
611             return futures;
612         }
613     }
614
615     private class NatFlowUpdateWorker implements Callable<List<ListenableFuture<Void>>> {
616         private Interface original;
617         private Interface update;
618         private String routerName;
619
620         NatFlowUpdateWorker(Interface original, Interface update, String routerName) {
621             this.original = original;
622             this.update = update;
623             this.routerName = routerName;
624         }
625
626         @Override
627         @SuppressWarnings("checkstyle:IllegalCatch")
628         public List<ListenableFuture<Void>> call() {
629             final List<ListenableFuture<Void>> futures = new ArrayList<>();
630             String interfaceName = update.getName();
631             IntfTransitionState state = getTransitionState(original.getOperStatus(), update.getOperStatus());
632             if (state.equals(IntfTransitionState.STATE_IGNORE)) {
633                 LOG.info("NAT Service: Interface {} state original {} updated {} not handled",
634                         interfaceName, original.getOperStatus(), update.getOperStatus());
635                 return futures;
636             }
637             if (state.equals(IntfTransitionState.STATE_UP)) {
638                 LOG.debug("call : Port UP event received for interface {} ", interfaceName);
639             } else if (state.equals(IntfTransitionState.STATE_DOWN)) {
640                 LOG.debug("call : Port DOWN event received for interface {} ", interfaceName);
641                 try {
642                     removeSnatEntriesForPort(interfaceName, routerName);
643                 } catch (Exception ex) {
644                     LOG.error("call : Exception caught in Interface {} OperationalStateDown", interfaceName, ex);
645                 }
646             }
647             return futures;
648         }
649     }
650
651     private class NatFlowRemoveWorker implements Callable<List<ListenableFuture<Void>>> {
652         private Interface delintrf;
653         private String routerName;
654         private BigInteger intfDpnId;
655
656         NatFlowRemoveWorker(Interface delintrf, BigInteger intfDpnId, String routerName) {
657             this.delintrf = delintrf;
658             this.routerName = routerName;
659             this.intfDpnId = intfDpnId;
660         }
661
662         @Override
663         @SuppressWarnings("checkstyle:IllegalCatch")
664         public List<ListenableFuture<Void>> call() {
665             final List<ListenableFuture<Void>> futures = new ArrayList<>();
666             final String interfaceName = delintrf.getName();
667             LOG.trace("call : Interface {} removed event received", delintrf);
668             try {
669                 LOG.trace("call : Port removed event received for interface {} ", interfaceName);
670                 processInterfaceRemoved(interfaceName, intfDpnId, routerName, futures);
671                 removeSnatEntriesForPort(interfaceName, routerName);
672             } catch (Exception e) {
673                 LOG.error("call : Exception caught in Interface {} OperationalStateRemove", interfaceName, e);
674             }
675             return futures;
676         }
677     }
678 }