2 * Copyright (c) 2016 - 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
8 package org.opendaylight.netvirt.natservice.internal;
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;
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;
61 public class NatInterfaceStateChangeListener
62 extends AsyncDataTreeChangeListenerBase<Interface, NatInterfaceStateChangeListener> {
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();
75 enum IntfTransitionState {
81 private void initialize() {
82 // Interface State Transition Table
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);
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;
114 LOG.info("{} init", getClass().getSimpleName());
115 registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
119 protected InstanceIdentifier<Interface> getWildCardPath() {
120 return InstanceIdentifier.create(InterfacesState.class).child(Interface.class);
124 protected NatInterfaceStateChangeListener getDataTreeChangeListener() {
125 return NatInterfaceStateChangeListener.this;
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());
137 String interfaceName = intrf.getName();
138 BigInteger intfDpnId;
140 intfDpnId = NatUtil.getDpIdFromInterface(intrf);
141 } catch (Exception e) {
142 LOG.error("add : Exception occured while retriving dpnid for interface {}", intrf.getName(), e);
145 if (BigInteger.ZERO.equals(intfDpnId)) {
146 LOG.warn("add : Could not retrieve dp id for interface {} ", interfaceName);
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);
159 NatFlowAddWorker natFlowAddWorker = new NatFlowAddWorker(interfaceName, routerName);
160 coordinator.enqueueJob(NAT_DS + "-" + interfaceName, natFlowAddWorker, NatConstants.NAT_DJC_MAX_RETRIES);
162 LOG.info("add : Router-Interface Mapping not found for Interface : {}", interfaceName);
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());
175 String interfaceName = intrf.getName();
176 BigInteger intfDpnId = BigInteger.ZERO;
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);
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();
202 if (intfDpnId.equals(BigInteger.ZERO)) {
203 LOG.warn("remove : Could not retrieve dpnid for interface {} ", interfaceName);
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);
213 NatFlowRemoveWorker natFlowRemoveWorker = new NatFlowRemoveWorker(intrf, intfDpnId, routerName);
214 coordinator.enqueueJob(NAT_DS + "-" + interfaceName, natFlowRemoveWorker,
215 NatConstants.NAT_DJC_MAX_RETRIES);
217 LOG.info("remove : Router-Interface Mapping not found for Interface : {}", interfaceName);
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());
230 BigInteger intfDpnId = BigInteger.ZERO;
231 String interfaceName = update.getName();
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);
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();
257 if (intfDpnId.equals(BigInteger.ZERO)) {
258 LOG.warn("remove : Could not retrieve dpnid for interface {} ", interfaceName);
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);
271 LOG.info("update : Router-Interface Mapping not found for Interface : {}", interfaceName);
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);
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,
292 private IntfTransitionState getTransitionState(Interface.OperStatus original , Interface.OperStatus updated) {
293 IntfTransitionState transitionState = stateTable.get(original, updated);
295 if (transitionState == null) {
296 return IntfTransitionState.STATE_IGNORE;
298 return transitionState;
301 private class NatInterfaceStateAddWorker implements Callable<List<ListenableFuture<Void>>> {
302 private String interfaceName;
303 private String routerName;
304 private BigInteger intfDpnId;
306 NatInterfaceStateAddWorker(String interfaceName, BigInteger intfDpnId, String routerName) {
307 this.interfaceName = interfaceName;
308 this.routerName = routerName;
309 this.intfDpnId = intfDpnId;
313 @SuppressWarnings("checkstyle:IllegalCatch")
314 public List<ListenableFuture<Void>> call() {
315 List<ListenableFuture<Void>> futures = new ArrayList<>();
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",
329 private class NatInterfaceStateRemoveWorker implements Callable<List<ListenableFuture<Void>>> {
330 private String interfaceName;
331 private String routerName;
332 private BigInteger intfDpnId;
334 NatInterfaceStateRemoveWorker(String interfaceName, BigInteger intfDpnId, String routerName) {
335 this.interfaceName = interfaceName;
336 this.routerName = routerName;
337 this.intfDpnId = intfDpnId;
341 @SuppressWarnings("checkstyle:IllegalCatch")
342 public List<ListenableFuture<Void>> call() {
343 List<ListenableFuture<Void>> futures = new ArrayList<>();
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);
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;
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;
370 @SuppressWarnings("checkstyle:IllegalCatch")
371 public List<ListenableFuture<Void>> call() {
372 List<ListenableFuture<Void>> futures = new ArrayList<>();
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());
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);
397 futures.add(writeOperTxn.submit());
398 } catch (Exception e) {
399 LOG.error("call : Exception observed in handling updation of VPN Interface {}.", update.getName(), e);
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);
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);
417 //final submit call for installFlowInvTx
418 futures.add(NatUtil.waitForTransactionToComplete(installFlowInvTx));
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);
431 return port.get().getInternalToExternalPortMap();
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();
447 private void removeNatFlow(BigInteger dpnId, short tableId, Long routerId, String ipAddress, int ipPort) {
449 String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, tableId, String.valueOf(routerId), ipAddress, ipPort);
450 FlowEntity snatFlowEntity = NatUtil.buildFlowEntity(dpnId, tableId, switchFlowRef);
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);
457 private List<String> getFixedIpsForPort(String interfname) {
458 LOG.debug("getFixedIpsForPort : getFixedIpsForPort method is called for interface {}", interfname);
460 Future<RpcResult<GetFixedIPsForNeutronPortOutput>> result =
461 neutronVpnService.getFixedIPsForNeutronPort(new GetFixedIPsForNeutronPortInputBuilder()
462 .setPortId(new Uuid(interfname)).build());
464 RpcResult<GetFixedIPsForNeutronPortOutput> rpcResult = result.get();
465 if (!rpcResult.isSuccessful()) {
466 LOG.error("getFixedIpsForPort : RPC Call to GetFixedIPsForNeutronPortOutput returned with Errors {}",
467 rpcResult.getErrors());
469 return rpcResult.getResult().getFixedIPs();
471 } catch (InterruptedException | ExecutionException | NullPointerException ex) {
472 LOG.error("getFixedIpsForPort : Exception while receiving fixedIps for port {}", interfname, ex);
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 {}",
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);
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);
492 // final submit call for removeFlowInvTx
493 futures.add(NatUtil.waitForTransactionToComplete(removeFlowInvTx));
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);
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);
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);
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);
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
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);
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);
548 String externalIpAddress = ipPortExternal.getIpAddress();
549 Integer portNumber = ipPortExternal.getPortNum();
551 //build and remove the flow in inboundtable
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);
561 String internalIpPort = internalIp + ":" + portnum;
562 // delete the entry from IntExtIpPortMap DS
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);
572 // delete the entry from SnatIntIpPortMap DS
573 LOG.debug("removeSnatEntriesForPort : Removing InternalIp:{} on router {}", internalIp, routerId);
574 naptManager.removeFromSnatIpPortDS(routerId, internalIp);
578 private class NatFlowAddWorker implements Callable<List<ListenableFuture<Void>>> {
579 private String interfaceName;
580 private String routerName;
582 NatFlowAddWorker(String interfaceName,String routerName) {
583 this.interfaceName = interfaceName;
584 this.routerName = routerName;
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);
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",
603 private class NatFlowUpdateWorker implements Callable<List<ListenableFuture<Void>>> {
604 private Interface original;
605 private Interface update;
606 private String routerName;
608 NatFlowUpdateWorker(Interface original, Interface update, String routerName) {
609 this.original = original;
610 this.update = update;
611 this.routerName = routerName;
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());
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);
630 removeSnatEntriesForPort(interfaceName, routerName);
631 } catch (Exception ex) {
632 LOG.error("call : Exception caught in Interface {} OperationalStateDown", interfaceName, ex);
639 private class NatFlowRemoveWorker implements Callable<List<ListenableFuture<Void>>> {
640 private Interface delintrf;
641 private String routerName;
642 private BigInteger intfDpnId;
644 NatFlowRemoveWorker(Interface delintrf, BigInteger intfDpnId, String routerName) {
645 this.delintrf = delintrf;
646 this.routerName = routerName;
647 this.intfDpnId = intfDpnId;
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);
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);