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 static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
11 import static org.opendaylight.genius.infra.Datastore.OPERATIONAL;
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;
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;
67 public class NatInterfaceStateChangeListener
68 extends AsyncDataTreeChangeListenerBase<Interface, NatInterfaceStateChangeListener> {
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();
82 enum IntfTransitionState {
88 private void initialize() {
89 // Interface State Transition Table
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);
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;
122 LOG.info("{} init", getClass().getSimpleName());
123 registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
127 protected InstanceIdentifier<Interface> getWildCardPath() {
128 return InstanceIdentifier.create(InterfacesState.class).child(Interface.class);
132 protected NatInterfaceStateChangeListener getDataTreeChangeListener() {
133 return NatInterfaceStateChangeListener.this;
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());
145 String interfaceName = intrf.getName();
146 BigInteger intfDpnId;
148 intfDpnId = NatUtil.getDpIdFromInterface(intrf);
149 } catch (Exception e) {
150 LOG.error("add : Exception occured while retriving dpnid for interface {}", intrf.getName(), e);
153 if (BigInteger.ZERO.equals(intfDpnId)) {
154 LOG.warn("add : Could not retrieve dp id for interface {} ", interfaceName);
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);
167 NatFlowAddWorker natFlowAddWorker = new NatFlowAddWorker(interfaceName, routerName);
168 coordinator.enqueueJob(NAT_DS + "-" + interfaceName, natFlowAddWorker, NatConstants.NAT_DJC_MAX_RETRIES);
170 LOG.info("add : Router-Interface Mapping not found for Interface : {}", interfaceName);
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());
183 String interfaceName = intrf.getName();
184 BigInteger intfDpnId = BigInteger.ZERO;
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);
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();
210 if (intfDpnId.equals(BigInteger.ZERO)) {
211 LOG.warn("remove : Could not retrieve dpnid for interface {} ", interfaceName);
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);
221 NatFlowRemoveWorker natFlowRemoveWorker = new NatFlowRemoveWorker(intrf, intfDpnId, routerName);
222 coordinator.enqueueJob(NAT_DS + "-" + interfaceName, natFlowRemoveWorker,
223 NatConstants.NAT_DJC_MAX_RETRIES);
225 LOG.info("remove : Router-Interface Mapping not found for Interface : {}", interfaceName);
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());
238 BigInteger intfDpnId = BigInteger.ZERO;
239 String interfaceName = update.getName();
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);
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();
265 if (intfDpnId.equals(BigInteger.ZERO)) {
266 LOG.warn("remove : Could not retrieve dpnid for interface {} ", interfaceName);
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);
279 LOG.info("update : Router-Interface Mapping not found for Interface : {}", interfaceName);
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);
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,
301 private IntfTransitionState getTransitionState(Interface.OperStatus original , Interface.OperStatus updated) {
302 IntfTransitionState transitionState = stateTable.get(original, updated);
304 if (transitionState == null) {
305 return IntfTransitionState.STATE_IGNORE;
307 return transitionState;
310 private class NatInterfaceStateAddWorker implements Callable<List<ListenableFuture<Void>>> {
311 private String interfaceName;
312 private String routerName;
313 private BigInteger intfDpnId;
315 NatInterfaceStateAddWorker(String interfaceName, BigInteger intfDpnId, String routerName) {
316 this.interfaceName = interfaceName;
317 this.routerName = routerName;
318 this.intfDpnId = intfDpnId;
322 @SuppressWarnings("checkstyle:IllegalCatch")
323 public List<ListenableFuture<Void>> call() {
324 List<ListenableFuture<Void>> futures = new ArrayList<>();
326 LOG.trace("call : Received interface {} PORT UP OR ADD event ", interfaceName);
327 String dpnLock = NatConstants.NAT_DJC_PREFIX + intfDpnId;
328 synchronized (dpnLock.intern()) {
329 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, tx ->
330 handleRouterInterfacesUpEvent(routerName, interfaceName, intfDpnId, tx)));
332 } catch (Exception e) {
333 LOG.error("call : Exception caught in Interface {} Operational State Up event",
340 private class NatInterfaceStateRemoveWorker implements Callable<List<ListenableFuture<Void>>> {
341 private String interfaceName;
342 private String routerName;
343 private BigInteger intfDpnId;
345 NatInterfaceStateRemoveWorker(String interfaceName, BigInteger intfDpnId, String routerName) {
346 this.interfaceName = interfaceName;
347 this.routerName = routerName;
348 this.intfDpnId = intfDpnId;
352 @SuppressWarnings("checkstyle:IllegalCatch")
353 public List<ListenableFuture<Void>> call() {
354 List<ListenableFuture<Void>> futures = new ArrayList<>();
356 LOG.trace("call : Received interface {} PORT DOWN or REMOVE event", interfaceName);
357 String dpnLock = NatConstants.NAT_DJC_PREFIX + intfDpnId;
358 synchronized (dpnLock.intern()) {
359 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, tx ->
360 handleRouterInterfacesDownEvent(routerName, interfaceName, intfDpnId, tx)));
362 } catch (Exception e) {
363 LOG.error("call : Exception observed in handling deletion of VPN Interface {}.", interfaceName, e);
369 private class NatInterfaceStateUpdateWorker implements Callable<List<ListenableFuture<Void>>> {
370 private Interface original;
371 private Interface update;
372 private BigInteger intfDpnId;
373 private String routerName;
375 NatInterfaceStateUpdateWorker(Interface original, Interface update, BigInteger intfDpnId, String routerName) {
376 this.original = original;
377 this.update = update;
378 this.intfDpnId = intfDpnId;
379 this.routerName = routerName;
383 @SuppressWarnings("checkstyle:IllegalCatch")
384 public List<ListenableFuture<Void>> call() {
385 List<ListenableFuture<Void>> futures = new ArrayList<>();
387 final String interfaceName = update.getName();
388 LOG.trace("call : Received interface {} state change event", interfaceName);
389 LOG.debug("call : DPN ID {} for the interface {} ", intfDpnId, interfaceName);
390 String dpnLock = NatConstants.NAT_DJC_PREFIX + intfDpnId;
391 synchronized (dpnLock.intern()) {
392 IntfTransitionState state = getTransitionState(original.getOperStatus(), update.getOperStatus());
393 if (state.equals(IntfTransitionState.STATE_IGNORE)) {
394 LOG.info("NAT Service: Interface {} state original {} updated {} not handled",
395 interfaceName, original.getOperStatus(), update.getOperStatus());
398 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, tx -> {
399 if (state.equals(IntfTransitionState.STATE_DOWN)) {
400 LOG.debug("call : DPN {} connnected to the interface {} has gone down."
401 + "Hence clearing the dpn-vpninterfaces-list entry from the"
402 + " neutron-router-dpns model in the ODL:L3VPN", intfDpnId, interfaceName);
403 // If the interface state is unknown, it means that the corresponding DPN has gone down.
404 // So remove the dpn-vpninterfaces-list from the neutron-router-dpns model.
405 NatUtil.removeFromNeutronRouterDpnsMap(routerName, interfaceName,
407 } else if (state.equals(IntfTransitionState.STATE_UP)) {
408 LOG.debug("call : DPN {} connnected to the interface {} has come up. Hence adding"
409 + " the dpn-vpninterfaces-list entry from the neutron-router-dpns model"
410 + " in the ODL:L3VPN", intfDpnId, interfaceName);
411 handleRouterInterfacesUpEvent(routerName, interfaceName, intfDpnId, tx);
415 } catch (Exception e) {
416 LOG.error("call : Exception observed in handling updation of VPN Interface {}.", update.getName(), e);
422 private void processInterfaceAdded(String portName, String routerId, List<ListenableFuture<Void>> futures) {
423 LOG.trace("processInterfaceAdded : Processing Interface Add Event for interface {}", portName);
424 List<InternalToExternalPortMap> intExtPortMapList = getIntExtPortMapListForPortName(portName, routerId);
425 if (intExtPortMapList == null || intExtPortMapList.isEmpty()) {
426 LOG.debug("processInterfaceAdded : Ip Mapping list is empty/null for portname {}", portName);
429 InstanceIdentifier<RouterPorts> portIid = NatUtil.buildRouterPortsIdentifier(routerId);
430 ListenableFuture<Void> future = txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
431 for (InternalToExternalPortMap intExtPortMap : intExtPortMapList) {
432 floatingIPListener.createNATFlowEntries(portName, intExtPortMap, portIid, routerId, tx);
438 } catch (InterruptedException | ExecutionException e) {
439 LOG.error("Error processing interface addition", e);
443 private List<InternalToExternalPortMap> getIntExtPortMapListForPortName(String portName, String routerId) {
444 InstanceIdentifier<Ports> portToIpMapIdentifier = NatUtil.buildPortToIpMapIdentifier(routerId, portName);
445 Optional<Ports> port =
446 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
447 LogicalDatastoreType.CONFIGURATION, portToIpMapIdentifier);
448 if (!port.isPresent()) {
449 LOG.info("getIntExtPortMapListForPortName : Unable to read router port entry for router ID {} "
450 + "and port name {}", routerId, portName);
453 return port.get().getInternalToExternalPortMap();
456 private BigInteger getNaptSwitchforRouter(DataBroker broker, String routerName) {
457 InstanceIdentifier<RouterToNaptSwitch> rtrNaptSw = InstanceIdentifier.builder(NaptSwitches.class)
458 .child(RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();
459 Optional<RouterToNaptSwitch> routerToNaptSwitchData =
460 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
461 LogicalDatastoreType.CONFIGURATION, rtrNaptSw);
462 if (routerToNaptSwitchData.isPresent()) {
463 RouterToNaptSwitch routerToNaptSwitchInstance = routerToNaptSwitchData.get();
464 return routerToNaptSwitchInstance.getPrimarySwitchId();
469 private void removeNatFlow(BigInteger dpnId, short tableId, Long routerId, String ipAddress, int ipPort) {
471 String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, tableId, String.valueOf(routerId), ipAddress, ipPort);
472 FlowEntity snatFlowEntity = NatUtil.buildFlowEntity(dpnId, tableId, switchFlowRef);
474 mdsalManager.removeFlow(snatFlowEntity);
475 LOG.debug("removeNatFlow : Removed the flow in table {} for the switch with the DPN ID {} for "
476 + "router {} ip {} port {}", tableId, dpnId, routerId, ipAddress, ipPort);
479 private List<String> getFixedIpsForPort(String interfname) {
480 LOG.debug("getFixedIpsForPort : getFixedIpsForPort method is called for interface {}", interfname);
482 Future<RpcResult<GetFixedIPsForNeutronPortOutput>> result =
483 neutronVpnService.getFixedIPsForNeutronPort(new GetFixedIPsForNeutronPortInputBuilder()
484 .setPortId(new Uuid(interfname)).build());
486 RpcResult<GetFixedIPsForNeutronPortOutput> rpcResult = result.get();
487 if (!rpcResult.isSuccessful()) {
488 LOG.error("getFixedIpsForPort : RPC Call to GetFixedIPsForNeutronPortOutput returned with Errors {}",
489 rpcResult.getErrors());
491 return rpcResult.getResult().getFixedIPs();
493 } catch (InterruptedException | ExecutionException | NullPointerException ex) {
494 LOG.error("getFixedIpsForPort : Exception while receiving fixedIps for port {}", interfname, ex);
499 private void processInterfaceRemoved(String portName, BigInteger dpnId, String routerId,
500 List<ListenableFuture<Void>> futures) {
501 LOG.trace("processInterfaceRemoved : Processing Interface Removed Event for interface {} on DPN ID {}",
503 List<InternalToExternalPortMap> intExtPortMapList = getIntExtPortMapListForPortName(portName, routerId);
504 if (intExtPortMapList == null || intExtPortMapList.isEmpty()) {
505 LOG.debug("processInterfaceRemoved : Ip Mapping list is empty/null for portName {}", portName);
508 InstanceIdentifier<RouterPorts> portIid = NatUtil.buildRouterPortsIdentifier(routerId);
509 ListenableFuture<Void> future = txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
510 for (InternalToExternalPortMap intExtPortMap : intExtPortMapList) {
511 LOG.trace("processInterfaceRemoved : Removing DNAT Flow entries for dpnId {} ", dpnId);
512 floatingIPListener.removeNATFlowEntries(portName, intExtPortMap, portIid, routerId, dpnId, tx);
518 } catch (InterruptedException | ExecutionException e) {
519 LOG.error("Error processing interface removal", e);
523 // TODO Clean up the exception handling
524 @SuppressWarnings("checkstyle:IllegalCatch")
525 private void removeSnatEntriesForPort(String interfaceName, String routerName) {
526 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
527 if (routerId == NatConstants.INVALID_ID) {
528 LOG.error("removeSnatEntriesForPort : routerId not found for routername {}", routerName);
531 BigInteger naptSwitch = getNaptSwitchforRouter(dataBroker, routerName);
532 if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
533 LOG.error("removeSnatEntriesForPort : NaptSwitch is not elected for router {} with Id {}",
534 routerName, routerId);
537 //getInternalIp for port
538 List<String> fixedIps = getFixedIpsForPort(interfaceName);
539 if (fixedIps == null) {
540 LOG.warn("removeSnatEntriesForPort : Internal Ips not found for InterfaceName {} in router {} with id {}",
541 interfaceName, routerName, routerId);
545 for (String internalIp : fixedIps) {
546 LOG.debug("removeSnatEntriesForPort : Internal Ip retrieved for interface {} is {} in router with Id {}",
547 interfaceName, internalIp, routerId);
548 IpPort ipPort = NatUtil.getInternalIpPortInfo(dataBroker, routerId, internalIp);
549 if (ipPort == null) {
550 LOG.debug("removeSnatEntriesForPort : no snatint-ip-port-map found for ip:{}", internalIp);
554 for (IntIpProtoType protoType: ipPort.getIntIpProtoType()) {
555 ProtocolTypes protocol = protoType.getProtocol();
556 for (Integer portnum : protoType.getPorts()) {
557 //build and remove the flow in outbound table
559 removeNatFlow(naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE, routerId, internalIp, portnum);
560 } catch (Exception ex) {
561 LOG.error("removeSnatEntriesForPort : Failed to remove snat flow for internalIP {} with "
562 + "Port {} protocol {} for routerId {} in OUTBOUNDTABLE of NaptSwitch {}",
563 internalIp, portnum, protocol, routerId, naptSwitch, ex);
565 //Get the external IP address and the port from the model
566 NAPTEntryEvent.Protocol proto = protocol.toString().equals(ProtocolTypes.TCP.toString())
567 ? NAPTEntryEvent.Protocol.TCP : NAPTEntryEvent.Protocol.UDP;
568 IpPortExternal ipPortExternal = NatUtil.getExternalIpPortMap(dataBroker, routerId,
569 internalIp, String.valueOf(portnum), proto);
570 if (ipPortExternal == null) {
571 LOG.error("removeSnatEntriesForPort : Mapping for internalIp {} with port {} is not found in "
572 + "router with Id {}", internalIp, portnum, routerId);
575 String externalIpAddress = ipPortExternal.getIpAddress();
576 Integer portNumber = ipPortExternal.getPortNum();
578 //build and remove the flow in inboundtable
580 removeNatFlow(naptSwitch, NwConstants.INBOUND_NAPT_TABLE, routerId,
581 externalIpAddress, portNumber);
582 } catch (Exception ex) {
583 LOG.error("removeSnatEntriesForPort : Failed to remove snat flow internalIP {} with "
584 + "Port {} protocol {} for routerId {} in INBOUNDTABLE of naptSwitch {}",
585 externalIpAddress, portNumber, protocol, routerId, naptSwitch, ex);
588 String internalIpPort = internalIp + ":" + portnum;
589 // delete the entry from IntExtIpPortMap DS
591 naptManager.removeFromIpPortMapDS(routerId, internalIpPort, proto);
592 naptManager.removePortFromPool(internalIpPort, externalIpAddress);
593 } catch (Exception ex) {
594 LOG.error("removeSnatEntriesForPort : releaseIpExtPortMapping failed, Removal of "
595 + "ipportmap {} for router {} failed", internalIpPort, routerId, ex);
599 // delete the entry from SnatIntIpPortMap DS
600 LOG.debug("removeSnatEntriesForPort : Removing InternalIp:{} on router {}", internalIp, routerId);
601 naptManager.removeFromSnatIpPortDS(routerId, internalIp);
605 private class NatFlowAddWorker implements Callable<List<ListenableFuture<Void>>> {
606 private String interfaceName;
607 private String routerName;
609 NatFlowAddWorker(String interfaceName,String routerName) {
610 this.interfaceName = interfaceName;
611 this.routerName = routerName;
615 @SuppressWarnings("checkstyle:IllegalCatch")
616 public List<ListenableFuture<Void>> call() {
617 final List<ListenableFuture<Void>> futures = new ArrayList<>();
618 LOG.trace("call : Interface {} up event received", interfaceName);
620 LOG.trace("call : Port added event received for interface {} ", interfaceName);
621 processInterfaceAdded(interfaceName, routerName, futures);
622 } catch (Exception ex) {
623 LOG.error("call : Exception caught in Interface {} Operational State Up event",
630 private class NatFlowUpdateWorker implements Callable<List<ListenableFuture<Void>>> {
631 private Interface original;
632 private Interface update;
633 private String routerName;
635 NatFlowUpdateWorker(Interface original, Interface update, String routerName) {
636 this.original = original;
637 this.update = update;
638 this.routerName = routerName;
642 @SuppressWarnings("checkstyle:IllegalCatch")
643 public List<ListenableFuture<Void>> call() {
644 final List<ListenableFuture<Void>> futures = new ArrayList<>();
645 String interfaceName = update.getName();
646 IntfTransitionState state = getTransitionState(original.getOperStatus(), update.getOperStatus());
647 if (state.equals(IntfTransitionState.STATE_IGNORE)) {
648 LOG.info("NAT Service: Interface {} state original {} updated {} not handled",
649 interfaceName, original.getOperStatus(), update.getOperStatus());
652 if (state.equals(IntfTransitionState.STATE_UP)) {
653 LOG.debug("call : Port UP event received for interface {} ", interfaceName);
654 } else if (state.equals(IntfTransitionState.STATE_DOWN)) {
655 LOG.debug("call : Port DOWN event received for interface {} ", interfaceName);
657 removeSnatEntriesForPort(interfaceName, routerName);
658 } catch (Exception ex) {
659 LOG.error("call : Exception caught in Interface {} OperationalStateDown", interfaceName, ex);
666 private class NatFlowRemoveWorker implements Callable<List<ListenableFuture<Void>>> {
667 private Interface delintrf;
668 private String routerName;
669 private BigInteger intfDpnId;
671 NatFlowRemoveWorker(Interface delintrf, BigInteger intfDpnId, String routerName) {
672 this.delintrf = delintrf;
673 this.routerName = routerName;
674 this.intfDpnId = intfDpnId;
678 @SuppressWarnings("checkstyle:IllegalCatch")
679 public List<ListenableFuture<Void>> call() {
680 final List<ListenableFuture<Void>> futures = new ArrayList<>();
681 final String interfaceName = delintrf.getName();
682 LOG.trace("call : Interface {} removed event received", delintrf);
684 LOG.trace("call : Port removed event received for interface {} ", interfaceName);
685 processInterfaceRemoved(interfaceName, intfDpnId, routerName, futures);
686 removeSnatEntriesForPort(interfaceName, routerName);
687 } catch (Exception e) {
688 LOG.error("call : Exception caught in Interface {} OperationalStateRemove", interfaceName, e);