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