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