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