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.infra.ManagedNewTransactionRunner;
30 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
31 import org.opendaylight.genius.mdsalutil.FlowEntity;
32 import org.opendaylight.genius.mdsalutil.NwConstants;
33 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
34 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
35 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
36 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.vpn._interface.VpnInstanceNames;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.L2vlan;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.router.interfaces.RouterInterface;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntry;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.NaptSwitches;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProtocolTypes;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPorts;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.Ports;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMap;
49 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;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitch;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.intip.port.map.IpPort;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.intip.port.map.ip.port.IntIpProtoType;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetFixedIPsForNeutronPortInputBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetFixedIPsForNeutronPortOutput;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NeutronvpnService;
57 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
58 import org.opendaylight.yangtools.yang.common.RpcResult;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
63 public class NatInterfaceStateChangeListener
64 extends AsyncDataTreeChangeListenerBase<Interface, NatInterfaceStateChangeListener> {
66 private static final Logger LOG = LoggerFactory.getLogger(NatInterfaceStateChangeListener.class);
67 private static final String NAT_DS = "NATDS";
68 private final DataBroker dataBroker;
69 private final ManagedNewTransactionRunner txRunner;
70 private final OdlInterfaceRpcService odlInterfaceRpcService;
71 private final JobCoordinator coordinator;
72 private final FloatingIPListener floatingIPListener;
73 private final NeutronvpnService neutronVpnService;
74 private final IMdsalApiManager mdsalManager;
75 private final NaptManager naptManager;
76 Table<Interface.OperStatus, Interface.OperStatus, IntfTransitionState> stateTable = HashBasedTable.create();
78 enum IntfTransitionState {
84 private void initialize() {
85 // Interface State Transition Table
87 // ---------------------------------------------------------------
88 /* Up { STATE_IGNORE, STATE_DOWN, STATE_DOWN }, */
89 /* Down { STATE_UP, STATE_IGNORE, STATE_IGNORE }, */
90 /* Unknown { STATE_UP, STATE_DOWN, STATE_IGNORE }, */
91 stateTable.put(Interface.OperStatus.Up, Interface.OperStatus.Down, IntfTransitionState.STATE_DOWN);
92 stateTable.put(Interface.OperStatus.Down, Interface.OperStatus.Up, IntfTransitionState.STATE_UP);
93 stateTable.put(Interface.OperStatus.Unknown, Interface.OperStatus.Up, IntfTransitionState.STATE_UP);
94 stateTable.put(Interface.OperStatus.Unknown, Interface.OperStatus.Down, IntfTransitionState.STATE_DOWN);
95 stateTable.put(Interface.OperStatus.Up, Interface.OperStatus.Unknown, IntfTransitionState.STATE_DOWN);
99 public NatInterfaceStateChangeListener(final DataBroker dataBroker,
100 final OdlInterfaceRpcService odlInterfaceRpcService, final JobCoordinator coordinator,
101 final FloatingIPListener floatingIPListener,final NeutronvpnService neutronvpnService,
102 final IMdsalApiManager mdsalManager, final NaptManager naptManager) {
103 super(Interface.class, NatInterfaceStateChangeListener.class);
104 this.dataBroker = dataBroker;
105 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
106 this.odlInterfaceRpcService = odlInterfaceRpcService;
107 this.coordinator = coordinator;
108 this.floatingIPListener = floatingIPListener;
109 this.neutronVpnService = neutronvpnService;
110 this.mdsalManager = mdsalManager;
111 this.naptManager = naptManager;
118 LOG.info("{} init", getClass().getSimpleName());
119 registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
123 protected InstanceIdentifier<Interface> getWildCardPath() {
124 return InstanceIdentifier.create(InterfacesState.class).child(Interface.class);
128 protected NatInterfaceStateChangeListener getDataTreeChangeListener() {
129 return NatInterfaceStateChangeListener.this;
133 // TODO Clean up the exception handling
134 @SuppressWarnings("checkstyle:IllegalCatch")
135 protected void add(InstanceIdentifier<Interface> identifier, Interface intrf) {
136 LOG.trace("add : Interface {} up event received", intrf);
137 if (!L2vlan.class.equals(intrf.getType())) {
138 LOG.debug("add : Interface {} is not Vlan Interface.Ignoring", intrf.getName());
141 String interfaceName = intrf.getName();
142 BigInteger intfDpnId;
144 intfDpnId = NatUtil.getDpIdFromInterface(intrf);
145 } catch (Exception e) {
146 LOG.error("add : Exception occured while retriving dpnid for interface {}", intrf.getName(), e);
149 if (BigInteger.ZERO.equals(intfDpnId)) {
150 LOG.warn("add : Could not retrieve dp id for interface {} ", interfaceName);
153 // We service only VM interfaces. We do not service Tunnel Interfaces here.
154 // Tunnel events are directly serviced by TunnelInterfacesStateListener present as part of
155 // VpnInterfaceManager
156 RouterInterface routerInterface = NatUtil.getConfiguredRouterInterface(dataBroker, interfaceName);
157 if (routerInterface != null) {
158 String routerName = routerInterface.getRouterName();
159 NatInterfaceStateAddWorker natIfaceStateAddWorker = new NatInterfaceStateAddWorker(interfaceName,
160 intfDpnId, routerName);
161 coordinator.enqueueJob(NAT_DS + "-" + intrf.getName(), natIfaceStateAddWorker);
163 NatFlowAddWorker natFlowAddWorker = new NatFlowAddWorker(interfaceName, routerName);
164 coordinator.enqueueJob(NAT_DS + "-" + interfaceName, natFlowAddWorker, NatConstants.NAT_DJC_MAX_RETRIES);
166 LOG.info("add : Router-Interface Mapping not found for Interface : {}", interfaceName);
171 // TODO Clean up the exception handling
172 @SuppressWarnings("checkstyle:IllegalCatch")
173 protected void remove(InstanceIdentifier<Interface> identifier, Interface intrf) {
174 LOG.trace("remove : Interface {} removed event received", intrf);
175 if (!L2vlan.class.equals(intrf.getType())) {
176 LOG.debug("remove : Interface {} is not Vlan Interface.Ignoring", intrf.getName());
179 String interfaceName = intrf.getName();
180 BigInteger intfDpnId = BigInteger.ZERO;
182 intfDpnId = NatUtil.getDpIdFromInterface(intrf);
183 } catch (Exception e) {
184 LOG.error("remove : Exception occured while retriving dpnid for interface {}", intrf.getName(), e);
185 InstanceIdentifier<VpnInterface> id = NatUtil.getVpnInterfaceIdentifier(interfaceName);
186 Optional<VpnInterface> cfgVpnInterface =
187 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(
188 dataBroker, LogicalDatastoreType.CONFIGURATION, id);
189 if (!cfgVpnInterface.isPresent()) {
190 LOG.warn("remove : Interface {} is not a VPN Interface, ignoring.", interfaceName);
193 for (VpnInstanceNames vpnInterfaceVpnInstance : cfgVpnInterface.get().getVpnInstanceNames()) {
194 String vpnName = vpnInterfaceVpnInstance.getVpnName();
195 InstanceIdentifier<VpnInterfaceOpDataEntry> idOper = NatUtil
196 .getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
197 Optional<VpnInterfaceOpDataEntry> optVpnInterface =
198 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(
199 dataBroker, LogicalDatastoreType.OPERATIONAL, idOper);
200 if (optVpnInterface.isPresent()) {
201 intfDpnId = optVpnInterface.get().getDpnId();
206 if (intfDpnId.equals(BigInteger.ZERO)) {
207 LOG.warn("remove : Could not retrieve dpnid for interface {} ", interfaceName);
210 RouterInterface routerInterface = NatUtil.getConfiguredRouterInterface(dataBroker, interfaceName);
211 if (routerInterface != null) {
212 String routerName = routerInterface.getRouterName();
213 NatInterfaceStateRemoveWorker natIfaceStateRemoveWorker = new NatInterfaceStateRemoveWorker(interfaceName,
214 intfDpnId, routerName);
215 coordinator.enqueueJob(NAT_DS + "-" + interfaceName, natIfaceStateRemoveWorker);
217 NatFlowRemoveWorker natFlowRemoveWorker = new NatFlowRemoveWorker(intrf, intfDpnId, routerName);
218 coordinator.enqueueJob(NAT_DS + "-" + interfaceName, natFlowRemoveWorker,
219 NatConstants.NAT_DJC_MAX_RETRIES);
221 LOG.info("remove : Router-Interface Mapping not found for Interface : {}", interfaceName);
226 // TODO Clean up the exception handling
227 @SuppressWarnings("checkstyle:IllegalCatch")
228 protected void update(InstanceIdentifier<Interface> identifier, Interface original, Interface update) {
229 LOG.trace("update : Operation Interface update event - Old: {}, New: {}", original, update);
230 if (!L2vlan.class.equals(update.getType())) {
231 LOG.debug("update : Interface {} is not Vlan Interface.Ignoring", update.getName());
234 BigInteger intfDpnId = BigInteger.ZERO;
235 String interfaceName = update.getName();
237 intfDpnId = NatUtil.getDpIdFromInterface(update);
238 } catch (Exception e) {
239 LOG.error("update : Exception occured while retriving dpnid for interface {}", update.getName(), e);
240 InstanceIdentifier<VpnInterface> id = NatUtil.getVpnInterfaceIdentifier(interfaceName);
241 Optional<VpnInterface> cfgVpnInterface =
242 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(
243 dataBroker, LogicalDatastoreType.CONFIGURATION, id);
244 if (!cfgVpnInterface.isPresent()) {
245 LOG.warn("update : Interface {} is not a VPN Interface, ignoring.", interfaceName);
248 for (VpnInstanceNames vpnInterfaceVpnInstance : cfgVpnInterface.get().getVpnInstanceNames()) {
249 String vpnName = vpnInterfaceVpnInstance.getVpnName();
250 InstanceIdentifier<VpnInterfaceOpDataEntry> idOper = NatUtil
251 .getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
252 Optional<VpnInterfaceOpDataEntry> optVpnInterface =
253 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(
254 dataBroker, LogicalDatastoreType.OPERATIONAL, idOper);
255 if (optVpnInterface.isPresent()) {
256 intfDpnId = optVpnInterface.get().getDpnId();
261 if (intfDpnId.equals(BigInteger.ZERO)) {
262 LOG.warn("remove : Could not retrieve dpnid for interface {} ", interfaceName);
265 RouterInterface routerInterface = NatUtil.getConfiguredRouterInterface(dataBroker, interfaceName);
266 if (routerInterface != null) {
267 String routerName = routerInterface.getRouterName();
268 NatInterfaceStateUpdateWorker natIfaceStateupdateWorker = new NatInterfaceStateUpdateWorker(original,
269 update, intfDpnId, routerName);
270 coordinator.enqueueJob(NAT_DS + "-" + update.getName(), natIfaceStateupdateWorker);
271 NatFlowUpdateWorker natFlowUpdateWorker = new NatFlowUpdateWorker(original, update, routerName);
272 coordinator.enqueueJob(NAT_DS + "-" + update.getName(), natFlowUpdateWorker,
273 NatConstants.NAT_DJC_MAX_RETRIES);
275 LOG.info("update : Router-Interface Mapping not found for Interface : {}", interfaceName);
279 void handleRouterInterfacesUpEvent(String routerName, String interfaceName, BigInteger dpId,
280 WriteTransaction writeOperTxn) {
281 LOG.debug("handleRouterInterfacesUpEvent : Handling UP event for router interface {} in Router {} on Dpn {}",
282 interfaceName, routerName, dpId);
283 NatUtil.addToNeutronRouterDpnsMap(dataBroker, routerName, interfaceName, dpId, writeOperTxn);
284 NatUtil.addToDpnRoutersMap(dataBroker, routerName, interfaceName, dpId, writeOperTxn);
287 void handleRouterInterfacesDownEvent(String routerName, String interfaceName, BigInteger dpnId,
288 WriteTransaction writeOperTxn) {
289 LOG.debug("handleRouterInterfacesDownEvent : Handling DOWN event for router Interface {} in Router {}",
290 interfaceName, routerName);
291 NatUtil.removeFromNeutronRouterDpnsMap(dataBroker, routerName, interfaceName, dpnId, writeOperTxn);
292 NatUtil.removeFromDpnRoutersMap(dataBroker, routerName, interfaceName, dpnId, odlInterfaceRpcService,
296 private IntfTransitionState getTransitionState(Interface.OperStatus original , Interface.OperStatus updated) {
297 IntfTransitionState transitionState = stateTable.get(original, updated);
299 if (transitionState == null) {
300 return IntfTransitionState.STATE_IGNORE;
302 return transitionState;
305 private class NatInterfaceStateAddWorker implements Callable<List<ListenableFuture<Void>>> {
306 private String interfaceName;
307 private String routerName;
308 private BigInteger intfDpnId;
310 NatInterfaceStateAddWorker(String interfaceName, BigInteger intfDpnId, String routerName) {
311 this.interfaceName = interfaceName;
312 this.routerName = routerName;
313 this.intfDpnId = intfDpnId;
317 @SuppressWarnings("checkstyle:IllegalCatch")
318 public List<ListenableFuture<Void>> call() {
319 List<ListenableFuture<Void>> futures = new ArrayList<>();
321 LOG.trace("call : Received interface {} PORT UP OR ADD event ", interfaceName);
322 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx ->
323 handleRouterInterfacesUpEvent(routerName, interfaceName, intfDpnId, tx)));
324 } catch (Exception e) {
325 LOG.error("call : Exception caught in Interface {} Operational State Up event",
332 private class NatInterfaceStateRemoveWorker implements Callable<List<ListenableFuture<Void>>> {
333 private String interfaceName;
334 private String routerName;
335 private BigInteger intfDpnId;
337 NatInterfaceStateRemoveWorker(String interfaceName, BigInteger intfDpnId, String routerName) {
338 this.interfaceName = interfaceName;
339 this.routerName = routerName;
340 this.intfDpnId = intfDpnId;
344 @SuppressWarnings("checkstyle:IllegalCatch")
345 public List<ListenableFuture<Void>> call() {
346 List<ListenableFuture<Void>> futures = new ArrayList<>();
348 LOG.trace("call : Received interface {} PORT DOWN or REMOVE event", interfaceName);
349 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx ->
350 handleRouterInterfacesDownEvent(routerName, interfaceName, intfDpnId, tx)));
351 } catch (Exception e) {
352 LOG.error("call : Exception observed in handling deletion of VPN Interface {}.", interfaceName, e);
358 private class NatInterfaceStateUpdateWorker implements Callable<List<ListenableFuture<Void>>> {
359 private Interface original;
360 private Interface update;
361 private BigInteger intfDpnId;
362 private String routerName;
364 NatInterfaceStateUpdateWorker(Interface original, Interface update, BigInteger intfDpnId, String routerName) {
365 this.original = original;
366 this.update = update;
367 this.intfDpnId = intfDpnId;
368 this.routerName = routerName;
372 @SuppressWarnings("checkstyle:IllegalCatch")
373 public List<ListenableFuture<Void>> call() {
374 List<ListenableFuture<Void>> futures = new ArrayList<>();
376 final String interfaceName = update.getName();
377 LOG.trace("call : Received interface {} state change event", interfaceName);
378 LOG.debug("call : DPN ID {} for the interface {} ", intfDpnId, interfaceName);
379 IntfTransitionState state = getTransitionState(original.getOperStatus(), update.getOperStatus());
380 if (state.equals(IntfTransitionState.STATE_IGNORE)) {
381 LOG.info("NAT Service: Interface {} state original {} updated {} not handled",
382 interfaceName, original.getOperStatus(), update.getOperStatus());
385 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
386 if (state.equals(IntfTransitionState.STATE_DOWN)) {
387 LOG.debug("call : DPN {} connnected to the interface {} has gone down."
388 + "Hence clearing the dpn-vpninterfaces-list entry from the"
389 + " neutron-router-dpns model in the ODL:L3VPN", intfDpnId, interfaceName);
390 // If the interface state is unknown, it means that the corresponding DPN has gone down.
391 // So remove the dpn-vpninterfaces-list from the neutron-router-dpns model.
392 NatUtil.removeFromNeutronRouterDpnsMap(dataBroker, routerName, intfDpnId, tx);
393 } else if (state.equals(IntfTransitionState.STATE_UP)) {
394 LOG.debug("call : DPN {} connnected to the interface {} has come up. Hence adding"
395 + " the dpn-vpninterfaces-list entry from the neutron-router-dpns model"
396 + " in the ODL:L3VPN", intfDpnId, interfaceName);
397 handleRouterInterfacesUpEvent(routerName, interfaceName, intfDpnId, tx);
400 } catch (Exception e) {
401 LOG.error("call : Exception observed in handling updation of VPN Interface {}.", update.getName(), e);
407 private void processInterfaceAdded(String portName, String routerId, List<ListenableFuture<Void>> futures) {
408 LOG.trace("processInterfaceAdded : Processing Interface Add Event for interface {}", portName);
409 List<InternalToExternalPortMap> intExtPortMapList = getIntExtPortMapListForPortName(portName, routerId);
410 if (intExtPortMapList == null || intExtPortMapList.isEmpty()) {
411 LOG.debug("processInterfaceAdded : Ip Mapping list is empty/null for portname {}", portName);
414 InstanceIdentifier<RouterPorts> portIid = NatUtil.buildRouterPortsIdentifier(routerId);
415 ListenableFuture<Void> future = txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
416 for (InternalToExternalPortMap intExtPortMap : intExtPortMapList) {
417 floatingIPListener.createNATFlowEntries(portName, intExtPortMap, portIid, routerId, tx);
423 } catch (InterruptedException | ExecutionException e) {
424 LOG.error("Error processing interface addition", e);
428 private List<InternalToExternalPortMap> getIntExtPortMapListForPortName(String portName, String routerId) {
429 InstanceIdentifier<Ports> portToIpMapIdentifier = NatUtil.buildPortToIpMapIdentifier(routerId, portName);
430 Optional<Ports> port =
431 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
432 LogicalDatastoreType.CONFIGURATION, portToIpMapIdentifier);
433 if (!port.isPresent()) {
434 LOG.info("getIntExtPortMapListForPortName : Unable to read router port entry for router ID {} "
435 + "and port name {}", routerId, portName);
438 return port.get().getInternalToExternalPortMap();
441 private BigInteger getNaptSwitchforRouter(DataBroker broker, String routerName) {
442 InstanceIdentifier<RouterToNaptSwitch> rtrNaptSw = InstanceIdentifier.builder(NaptSwitches.class)
443 .child(RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();
444 Optional<RouterToNaptSwitch> routerToNaptSwitchData =
445 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
446 LogicalDatastoreType.CONFIGURATION, rtrNaptSw);
447 if (routerToNaptSwitchData.isPresent()) {
448 RouterToNaptSwitch routerToNaptSwitchInstance = routerToNaptSwitchData.get();
449 return routerToNaptSwitchInstance.getPrimarySwitchId();
454 private void removeNatFlow(BigInteger dpnId, short tableId, Long routerId, String ipAddress, int ipPort) {
456 String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, tableId, String.valueOf(routerId), ipAddress, ipPort);
457 FlowEntity snatFlowEntity = NatUtil.buildFlowEntity(dpnId, tableId, switchFlowRef);
459 mdsalManager.removeFlow(snatFlowEntity);
460 LOG.debug("removeNatFlow : Removed the flow in table {} for the switch with the DPN ID {} for "
461 + "router {} ip {} port {}", tableId, dpnId, routerId, ipAddress, ipPort);
464 private List<String> getFixedIpsForPort(String interfname) {
465 LOG.debug("getFixedIpsForPort : getFixedIpsForPort method is called for interface {}", interfname);
467 Future<RpcResult<GetFixedIPsForNeutronPortOutput>> result =
468 neutronVpnService.getFixedIPsForNeutronPort(new GetFixedIPsForNeutronPortInputBuilder()
469 .setPortId(new Uuid(interfname)).build());
471 RpcResult<GetFixedIPsForNeutronPortOutput> rpcResult = result.get();
472 if (!rpcResult.isSuccessful()) {
473 LOG.error("getFixedIpsForPort : RPC Call to GetFixedIPsForNeutronPortOutput returned with Errors {}",
474 rpcResult.getErrors());
476 return rpcResult.getResult().getFixedIPs();
478 } catch (InterruptedException | ExecutionException | NullPointerException ex) {
479 LOG.error("getFixedIpsForPort : Exception while receiving fixedIps for port {}", interfname, ex);
484 private void processInterfaceRemoved(String portName, BigInteger dpnId, String routerId,
485 List<ListenableFuture<Void>> futures) {
486 LOG.trace("processInterfaceRemoved : Processing Interface Removed Event for interface {} on DPN ID {}",
488 List<InternalToExternalPortMap> intExtPortMapList = getIntExtPortMapListForPortName(portName, routerId);
489 if (intExtPortMapList == null || intExtPortMapList.isEmpty()) {
490 LOG.debug("processInterfaceRemoved : Ip Mapping list is empty/null for portName {}", portName);
493 InstanceIdentifier<RouterPorts> portIid = NatUtil.buildRouterPortsIdentifier(routerId);
494 ListenableFuture<Void> future = txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
495 for (InternalToExternalPortMap intExtPortMap : intExtPortMapList) {
496 LOG.trace("processInterfaceRemoved : Removing DNAT Flow entries for dpnId {} ", dpnId);
497 floatingIPListener.removeNATFlowEntries(portName, intExtPortMap, portIid, routerId, dpnId, tx);
503 } catch (InterruptedException | ExecutionException e) {
504 LOG.error("Error processing interface removal", e);
508 // TODO Clean up the exception handling
509 @SuppressWarnings("checkstyle:IllegalCatch")
510 private void removeSnatEntriesForPort(String interfaceName, String routerName) {
511 Long routerId = NatUtil.getVpnId(dataBroker, routerName);
512 if (routerId == NatConstants.INVALID_ID) {
513 LOG.error("removeSnatEntriesForPort : routerId not found for routername {}", routerName);
516 BigInteger naptSwitch = getNaptSwitchforRouter(dataBroker, routerName);
517 if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
518 LOG.error("removeSnatEntriesForPort : NaptSwitch is not elected for router {} with Id {}",
519 routerName, routerId);
522 //getInternalIp for port
523 List<String> fixedIps = getFixedIpsForPort(interfaceName);
524 if (fixedIps == null) {
525 LOG.warn("removeSnatEntriesForPort : Internal Ips not found for InterfaceName {} in router {} with id {}",
526 interfaceName, routerName, routerId);
530 for (String internalIp : fixedIps) {
531 LOG.debug("removeSnatEntriesForPort : Internal Ip retrieved for interface {} is {} in router with Id {}",
532 interfaceName, internalIp, routerId);
533 IpPort ipPort = NatUtil.getInternalIpPortInfo(dataBroker, routerId, internalIp);
534 if (ipPort == null) {
535 LOG.debug("removeSnatEntriesForPort : no snatint-ip-port-map found for ip:{}", internalIp);
539 for (IntIpProtoType protoType: ipPort.getIntIpProtoType()) {
540 ProtocolTypes protocol = protoType.getProtocol();
541 for (Integer portnum : protoType.getPorts()) {
542 //build and remove the flow in outbound table
544 removeNatFlow(naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE, routerId, internalIp, portnum);
545 } catch (Exception ex) {
546 LOG.error("removeSnatEntriesForPort : Failed to remove snat flow for internalIP {} with "
547 + "Port {} protocol {} for routerId {} in OUTBOUNDTABLE of NaptSwitch {}",
548 internalIp, portnum, protocol, routerId, naptSwitch, ex);
550 //Get the external IP address and the port from the model
551 NAPTEntryEvent.Protocol proto = protocol.toString().equals(ProtocolTypes.TCP.toString())
552 ? NAPTEntryEvent.Protocol.TCP : NAPTEntryEvent.Protocol.UDP;
553 IpPortExternal ipPortExternal = NatUtil.getExternalIpPortMap(dataBroker, routerId,
554 internalIp, String.valueOf(portnum), proto);
555 if (ipPortExternal == null) {
556 LOG.error("removeSnatEntriesForPort : Mapping for internalIp {} with port {} is not found in "
557 + "router with Id {}", internalIp, portnum, routerId);
560 String externalIpAddress = ipPortExternal.getIpAddress();
561 Integer portNumber = ipPortExternal.getPortNum();
563 //build and remove the flow in inboundtable
565 removeNatFlow(naptSwitch, NwConstants.INBOUND_NAPT_TABLE, routerId,
566 externalIpAddress, portNumber);
567 } catch (Exception ex) {
568 LOG.error("removeSnatEntriesForPort : Failed to remove snat flow internalIP {} with "
569 + "Port {} protocol {} for routerId {} in INBOUNDTABLE of naptSwitch {}",
570 externalIpAddress, portNumber, protocol, routerId, naptSwitch, ex);
573 String internalIpPort = internalIp + ":" + portnum;
574 // delete the entry from IntExtIpPortMap DS
576 naptManager.removeFromIpPortMapDS(routerId, internalIpPort, proto);
577 naptManager.removePortFromPool(internalIpPort, externalIpAddress);
578 } catch (Exception ex) {
579 LOG.error("removeSnatEntriesForPort : releaseIpExtPortMapping failed, Removal of "
580 + "ipportmap {} for router {} failed", internalIpPort, routerId, ex);
584 // delete the entry from SnatIntIpPortMap DS
585 LOG.debug("removeSnatEntriesForPort : Removing InternalIp:{} on router {}", internalIp, routerId);
586 naptManager.removeFromSnatIpPortDS(routerId, internalIp);
590 private class NatFlowAddWorker implements Callable<List<ListenableFuture<Void>>> {
591 private String interfaceName;
592 private String routerName;
594 NatFlowAddWorker(String interfaceName,String routerName) {
595 this.interfaceName = interfaceName;
596 this.routerName = routerName;
600 @SuppressWarnings("checkstyle:IllegalCatch")
601 public List<ListenableFuture<Void>> call() {
602 final List<ListenableFuture<Void>> futures = new ArrayList<>();
603 LOG.trace("call : Interface {} up event received", interfaceName);
605 LOG.trace("call : Port added event received for interface {} ", interfaceName);
606 processInterfaceAdded(interfaceName, routerName, futures);
607 } catch (Exception ex) {
608 LOG.error("call : Exception caught in Interface {} Operational State Up event",
615 private class NatFlowUpdateWorker implements Callable<List<ListenableFuture<Void>>> {
616 private Interface original;
617 private Interface update;
618 private String routerName;
620 NatFlowUpdateWorker(Interface original, Interface update, String routerName) {
621 this.original = original;
622 this.update = update;
623 this.routerName = routerName;
627 @SuppressWarnings("checkstyle:IllegalCatch")
628 public List<ListenableFuture<Void>> call() {
629 final List<ListenableFuture<Void>> futures = new ArrayList<>();
630 String interfaceName = update.getName();
631 IntfTransitionState state = getTransitionState(original.getOperStatus(), update.getOperStatus());
632 if (state.equals(IntfTransitionState.STATE_IGNORE)) {
633 LOG.info("NAT Service: Interface {} state original {} updated {} not handled",
634 interfaceName, original.getOperStatus(), update.getOperStatus());
637 if (state.equals(IntfTransitionState.STATE_UP)) {
638 LOG.debug("call : Port UP event received for interface {} ", interfaceName);
639 } else if (state.equals(IntfTransitionState.STATE_DOWN)) {
640 LOG.debug("call : Port DOWN event received for interface {} ", interfaceName);
642 removeSnatEntriesForPort(interfaceName, routerName);
643 } catch (Exception ex) {
644 LOG.error("call : Exception caught in Interface {} OperationalStateDown", interfaceName, ex);
651 private class NatFlowRemoveWorker implements Callable<List<ListenableFuture<Void>>> {
652 private Interface delintrf;
653 private String routerName;
654 private BigInteger intfDpnId;
656 NatFlowRemoveWorker(Interface delintrf, BigInteger intfDpnId, String routerName) {
657 this.delintrf = delintrf;
658 this.routerName = routerName;
659 this.intfDpnId = intfDpnId;
663 @SuppressWarnings("checkstyle:IllegalCatch")
664 public List<ListenableFuture<Void>> call() {
665 final List<ListenableFuture<Void>> futures = new ArrayList<>();
666 final String interfaceName = delintrf.getName();
667 LOG.trace("call : Interface {} removed event received", delintrf);
669 LOG.trace("call : Port removed event received for interface {} ", interfaceName);
670 processInterfaceRemoved(interfaceName, intfDpnId, routerName, futures);
671 removeSnatEntriesForPort(interfaceName, routerName);
672 } catch (Exception e) {
673 LOG.error("call : Exception caught in Interface {} OperationalStateRemove", interfaceName, e);