From 85a0391d26963d4abfacb00ef3f285efaf6f2029 Mon Sep 17 00:00:00 2001 From: Josh Date: Fri, 17 Aug 2018 15:20:29 -0700 Subject: [PATCH] FIP support for Octavia VIPs This patch resolves the issue documented in the Jira issue referenced below. The basic solution is to use the OF packet-in event to learn the dpn where the NAT flows need to be programmed. Overview of code changes: 1. Refactor NatInterfaceStateChangeListener into two classes: - NatInterfaceStateChangeListener which just receives events - NatSouthboundEventHandlers which contains the logic invoked for when an interface state changes (or a garp is received) 2. Implementation of NatArpNotificationHandler which receives the garps and invokes the correct methods in NatSouthboundEventHandlers 3. neutron-vip-state yang model which is used together with VipStateTracker (DataObjectCache) to manage state of the discovered VIPs. This is required in cases where the associated Ocatavia Amphora VM changes to a different compute node. In this case the existing flows must be removed from the odl compute node. 4. Tweak VIP learning code to accept neutron ports that are owned by "Octavia", previously the code assumed no neutron port ever needed to be learned. Jira: NETVIRT-1402 Change-Id: I7867124f3cbbe88d1ce6d075e51e2b11f941aec2 Signed-off-by: Josh --- natservice/api/src/main/yang/odl-nat.yang | 16 + .../internal/FloatingIPListener.java | 8 +- .../internal/NatArpNotificationHandler.java | 140 +++++ .../NatInterfaceStateChangeListener.java | 516 +--------------- .../internal/NatSouthboundEventHandlers.java | 560 ++++++++++++++++++ .../natservice/internal/VipStateTracker.java | 58 ++ .../org/opendaylight/blueprint/natservice.xml | 5 + .../AbstractIpLearnNotificationHandler.java | 117 ++-- .../iplearn/ipv4/ArpNotificationHandler.java | 6 +- .../ipv6/Ipv6NaNotificationHandler.java | 6 +- 10 files changed, 868 insertions(+), 564 deletions(-) create mode 100644 natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatArpNotificationHandler.java create mode 100644 natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatSouthboundEventHandlers.java create mode 100644 natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/VipStateTracker.java diff --git a/natservice/api/src/main/yang/odl-nat.yang b/natservice/api/src/main/yang/odl-nat.yang index 2496f79216..d06444c502 100644 --- a/natservice/api/src/main/yang/odl-nat.yang +++ b/natservice/api/src/main/yang/odl-nat.yang @@ -208,4 +208,20 @@ module odl-nat { } } } + + container neutron-vip-states { + config false; + list vip-state { + key ip; + leaf ip { + type string; + } + leaf dpn-id { + type uint64; + } + leaf ifc-name { + type string; + } + } + } } diff --git a/natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/FloatingIPListener.java b/natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/FloatingIPListener.java index 2909fac1b7..6420bddd8b 100644 --- a/natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/FloatingIPListener.java +++ b/natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/FloatingIPListener.java @@ -392,7 +392,7 @@ public class FloatingIPListener extends AsyncDataTreeChangeListenerBase portIid = identifier.firstIdentifierOf(RouterPorts.class); coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + mapping.key(), () -> Collections.singletonList( txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, - tx -> createNATFlowEntries(interfaceName, mapping, portIid, routerId, tx))), + tx -> createNATFlowEntries(interfaceName, mapping, portIid, routerId, null, tx))), NatConstants.NAT_DJC_MAX_RETRIES); } @@ -426,7 +426,7 @@ public class FloatingIPListener extends AsyncDataTreeChangeListenerBase portIid, final String routerName, + final InstanceIdentifier portIid, final String routerName, BigInteger dpnId, TypedReadWriteTransaction confTx) throws ExecutionException, InterruptedException { if (!validateIpMapping(mapping)) { LOG.error("createNATFlowEntries : Not a valid ip addresses in the mapping {}", mapping); @@ -434,7 +434,9 @@ public class FloatingIPListener extends AsyncDataTreeChangeListenerBase staticMacEntries = elanInterface.getStaticMacEntries(); + if (null == staticMacEntries) { + return false; + } + + for (StaticMacEntries staticMacEntry : staticMacEntries) { + if (Objects.equals(staticMacEntry.getIpPrefix(), ip)) { + return true; + } + } + return false; + } +} diff --git a/natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatInterfaceStateChangeListener.java b/natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatInterfaceStateChangeListener.java index bb985ac393..49567a129c 100644 --- a/natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatInterfaceStateChangeListener.java +++ b/natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatInterfaceStateChangeListener.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 - 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved. + * Copyright (c) 2016 - 2018 Ericsson India Global Services Pvt Ltd. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, @@ -7,19 +7,8 @@ */ package org.opendaylight.netvirt.natservice.internal; -import static org.opendaylight.genius.infra.Datastore.CONFIGURATION; -import static org.opendaylight.genius.infra.Datastore.OPERATIONAL; - import com.google.common.base.Optional; -import com.google.common.collect.HashBasedTable; -import com.google.common.collect.Table; -import com.google.common.util.concurrent.ListenableFuture; import java.math.BigInteger; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; import javax.annotation.PostConstruct; import javax.inject.Inject; @@ -28,38 +17,14 @@ import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase; import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker; -import org.opendaylight.genius.infra.Datastore.Operational; -import org.opendaylight.genius.infra.ManagedNewTransactionRunner; -import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl; -import org.opendaylight.genius.infra.TypedReadWriteTransaction; -import org.opendaylight.genius.mdsalutil.FlowEntity; -import org.opendaylight.genius.mdsalutil.NwConstants; -import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager; -import org.opendaylight.infrautils.jobcoordinator.JobCoordinator; import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface; import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.vpn._interface.VpnInstanceNames; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.L2vlan; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.router.interfaces.RouterInterface; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntry; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.NaptSwitches; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProtocolTypes; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPorts; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.Ports; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMap; -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; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitch; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.intip.port.map.IpPort; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.intip.port.map.ip.port.IntIpProtoType; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetFixedIPsForNeutronPortInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetFixedIPsForNeutronPortOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NeutronvpnService; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.common.RpcResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -68,52 +33,15 @@ public class NatInterfaceStateChangeListener extends AsyncDataTreeChangeListenerBase { private static final Logger LOG = LoggerFactory.getLogger(NatInterfaceStateChangeListener.class); - private static final String NAT_DS = "NATDS"; private final DataBroker dataBroker; - private final ManagedNewTransactionRunner txRunner; - private final OdlInterfaceRpcService odlInterfaceRpcService; - private final JobCoordinator coordinator; - private final FloatingIPListener floatingIPListener; - private final NeutronvpnService neutronVpnService; - private final IMdsalApiManager mdsalManager; - private final NaptManager naptManager; - Table stateTable = HashBasedTable.create(); - - enum IntfTransitionState { - STATE_UP, - STATE_DOWN, - STATE_IGNORE - } - - private void initialize() { - // Interface State Transition Table - // Up Down Unknown - // --------------------------------------------------------------- - /* Up { STATE_IGNORE, STATE_DOWN, STATE_DOWN }, */ - /* Down { STATE_UP, STATE_IGNORE, STATE_IGNORE }, */ - /* Unknown { STATE_UP, STATE_DOWN, STATE_IGNORE }, */ - stateTable.put(Interface.OperStatus.Up, Interface.OperStatus.Down, IntfTransitionState.STATE_DOWN); - stateTable.put(Interface.OperStatus.Down, Interface.OperStatus.Up, IntfTransitionState.STATE_UP); - stateTable.put(Interface.OperStatus.Unknown, Interface.OperStatus.Up, IntfTransitionState.STATE_UP); - stateTable.put(Interface.OperStatus.Unknown, Interface.OperStatus.Down, IntfTransitionState.STATE_DOWN); - stateTable.put(Interface.OperStatus.Up, Interface.OperStatus.Unknown, IntfTransitionState.STATE_DOWN); - } + private final NatSouthboundEventHandlers southboundEventHandlers; @Inject public NatInterfaceStateChangeListener(final DataBroker dataBroker, - final OdlInterfaceRpcService odlInterfaceRpcService, final JobCoordinator coordinator, - final FloatingIPListener floatingIPListener,final NeutronvpnService neutronvpnService, - final IMdsalApiManager mdsalManager, final NaptManager naptManager) { + final NatSouthboundEventHandlers southboundEventHandlers) { super(Interface.class, NatInterfaceStateChangeListener.class); this.dataBroker = dataBroker; - this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker); - this.odlInterfaceRpcService = odlInterfaceRpcService; - this.coordinator = coordinator; - this.floatingIPListener = floatingIPListener; - this.neutronVpnService = neutronvpnService; - this.mdsalManager = mdsalManager; - this.naptManager = naptManager; - initialize(); + this.southboundEventHandlers = southboundEventHandlers; } @Override @@ -159,13 +87,7 @@ public class NatInterfaceStateChangeListener // VpnInterfaceManager RouterInterface routerInterface = NatUtil.getConfiguredRouterInterface(dataBroker, interfaceName); if (routerInterface != null) { - String routerName = routerInterface.getRouterName(); - NatInterfaceStateAddWorker natIfaceStateAddWorker = new NatInterfaceStateAddWorker(interfaceName, - intfDpnId, routerName); - coordinator.enqueueJob(NAT_DS + "-" + intrf.getName(), natIfaceStateAddWorker); - - NatFlowAddWorker natFlowAddWorker = new NatFlowAddWorker(interfaceName, routerName); - coordinator.enqueueJob(NAT_DS + "-" + interfaceName, natFlowAddWorker, NatConstants.NAT_DJC_MAX_RETRIES); + this.southboundEventHandlers.handleAdd(interfaceName, intfDpnId, routerInterface); } else { LOG.info("add : Router-Interface Mapping not found for Interface : {}", interfaceName); } @@ -213,14 +135,7 @@ public class NatInterfaceStateChangeListener } RouterInterface routerInterface = NatUtil.getConfiguredRouterInterface(dataBroker, interfaceName); if (routerInterface != null) { - String routerName = routerInterface.getRouterName(); - NatInterfaceStateRemoveWorker natIfaceStateRemoveWorker = new NatInterfaceStateRemoveWorker(interfaceName, - intfDpnId, routerName); - coordinator.enqueueJob(NAT_DS + "-" + interfaceName, natIfaceStateRemoveWorker); - - NatFlowRemoveWorker natFlowRemoveWorker = new NatFlowRemoveWorker(intrf, intfDpnId, routerName); - coordinator.enqueueJob(NAT_DS + "-" + interfaceName, natFlowRemoveWorker, - NatConstants.NAT_DJC_MAX_RETRIES); + this.southboundEventHandlers.handleRemove(intrf.getName(), intfDpnId, routerInterface); } else { LOG.info("remove : Router-Interface Mapping not found for Interface : {}", interfaceName); } @@ -268,426 +183,9 @@ public class NatInterfaceStateChangeListener } RouterInterface routerInterface = NatUtil.getConfiguredRouterInterface(dataBroker, interfaceName); if (routerInterface != null) { - String routerName = routerInterface.getRouterName(); - NatInterfaceStateUpdateWorker natIfaceStateupdateWorker = new NatInterfaceStateUpdateWorker(original, - update, intfDpnId, routerName); - coordinator.enqueueJob(NAT_DS + "-" + update.getName(), natIfaceStateupdateWorker); - NatFlowUpdateWorker natFlowUpdateWorker = new NatFlowUpdateWorker(original, update, routerName); - coordinator.enqueueJob(NAT_DS + "-" + update.getName(), natFlowUpdateWorker, - NatConstants.NAT_DJC_MAX_RETRIES); + this.southboundEventHandlers.handleUpdate(original, update, intfDpnId, routerInterface); } else { LOG.info("update : Router-Interface Mapping not found for Interface : {}", interfaceName); } } - - void handleRouterInterfacesUpEvent(String routerName, String interfaceName, BigInteger dpId, - TypedReadWriteTransaction operTx) throws ExecutionException, InterruptedException { - LOG.debug("handleRouterInterfacesUpEvent : Handling UP event for router interface {} in Router {} on Dpn {}", - interfaceName, routerName, dpId); - NatUtil.addToNeutronRouterDpnsMap(routerName, interfaceName, dpId, operTx); - NatUtil.addToDpnRoutersMap(routerName, interfaceName, dpId, operTx); - } - - void handleRouterInterfacesDownEvent(String routerName, String interfaceName, BigInteger dpnId, - TypedReadWriteTransaction operTx) - throws ExecutionException, InterruptedException { - LOG.debug("handleRouterInterfacesDownEvent : Handling DOWN event for router Interface {} in Router {}", - interfaceName, routerName); - NatUtil.removeFromNeutronRouterDpnsMap(routerName, dpnId, operTx); - NatUtil.removeFromDpnRoutersMap(dataBroker, routerName, interfaceName, dpnId, odlInterfaceRpcService, - operTx); - } - - private IntfTransitionState getTransitionState(Interface.OperStatus original , Interface.OperStatus updated) { - IntfTransitionState transitionState = stateTable.get(original, updated); - - if (transitionState == null) { - return IntfTransitionState.STATE_IGNORE; - } - return transitionState; - } - - private class NatInterfaceStateAddWorker implements Callable>> { - private String interfaceName; - private String routerName; - private BigInteger intfDpnId; - - NatInterfaceStateAddWorker(String interfaceName, BigInteger intfDpnId, String routerName) { - this.interfaceName = interfaceName; - this.routerName = routerName; - this.intfDpnId = intfDpnId; - } - - @Override - @SuppressWarnings("checkstyle:IllegalCatch") - public List> call() { - List> futures = new ArrayList<>(); - try { - LOG.trace("call : Received interface {} PORT UP OR ADD event ", interfaceName); - String dpnLock = NatConstants.NAT_DJC_PREFIX + intfDpnId; - synchronized (dpnLock.intern()) { - futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, tx -> - handleRouterInterfacesUpEvent(routerName, interfaceName, intfDpnId, tx))); - } - } catch (Exception e) { - LOG.error("call : Exception caught in Interface {} Operational State Up event", - interfaceName, e); - } - return futures; - } - } - - private class NatInterfaceStateRemoveWorker implements Callable>> { - private String interfaceName; - private String routerName; - private BigInteger intfDpnId; - - NatInterfaceStateRemoveWorker(String interfaceName, BigInteger intfDpnId, String routerName) { - this.interfaceName = interfaceName; - this.routerName = routerName; - this.intfDpnId = intfDpnId; - } - - @Override - @SuppressWarnings("checkstyle:IllegalCatch") - public List> call() { - List> futures = new ArrayList<>(); - try { - LOG.trace("call : Received interface {} PORT DOWN or REMOVE event", interfaceName); - String dpnLock = NatConstants.NAT_DJC_PREFIX + intfDpnId; - synchronized (dpnLock.intern()) { - futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, tx -> - handleRouterInterfacesDownEvent(routerName, interfaceName, intfDpnId, tx))); - } - } catch (Exception e) { - LOG.error("call : Exception observed in handling deletion of VPN Interface {}.", interfaceName, e); - } - return futures; - } - } - - private class NatInterfaceStateUpdateWorker implements Callable>> { - private Interface original; - private Interface update; - private BigInteger intfDpnId; - private String routerName; - - NatInterfaceStateUpdateWorker(Interface original, Interface update, BigInteger intfDpnId, String routerName) { - this.original = original; - this.update = update; - this.intfDpnId = intfDpnId; - this.routerName = routerName; - } - - @Override - @SuppressWarnings("checkstyle:IllegalCatch") - public List> call() { - List> futures = new ArrayList<>(); - try { - final String interfaceName = update.getName(); - LOG.trace("call : Received interface {} state change event", interfaceName); - LOG.debug("call : DPN ID {} for the interface {} ", intfDpnId, interfaceName); - String dpnLock = NatConstants.NAT_DJC_PREFIX + intfDpnId; - synchronized (dpnLock.intern()) { - IntfTransitionState state = getTransitionState(original.getOperStatus(), update.getOperStatus()); - if (state.equals(IntfTransitionState.STATE_IGNORE)) { - LOG.info("NAT Service: Interface {} state original {} updated {} not handled", - interfaceName, original.getOperStatus(), update.getOperStatus()); - return futures; - } - futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, tx -> { - if (state.equals(IntfTransitionState.STATE_DOWN)) { - LOG.debug("call : DPN {} connnected to the interface {} has gone down." - + "Hence clearing the dpn-vpninterfaces-list entry from the" - + " neutron-router-dpns model in the ODL:L3VPN", intfDpnId, interfaceName); - // If the interface state is unknown, it means that the corresponding DPN has gone down. - // So remove the dpn-vpninterfaces-list from the neutron-router-dpns model. - NatUtil.removeFromNeutronRouterDpnsMap(routerName, interfaceName, - intfDpnId, tx); - } else if (state.equals(IntfTransitionState.STATE_UP)) { - LOG.debug("call : DPN {} connnected to the interface {} has come up. Hence adding" - + " the dpn-vpninterfaces-list entry from the neutron-router-dpns model" - + " in the ODL:L3VPN", intfDpnId, interfaceName); - handleRouterInterfacesUpEvent(routerName, interfaceName, intfDpnId, tx); - } - })); - } - } catch (Exception e) { - LOG.error("call : Exception observed in handling updation of VPN Interface {}.", update.getName(), e); - } - return futures; - } - } - - private void processInterfaceAdded(String portName, String routerId, List> futures) { - LOG.trace("processInterfaceAdded : Processing Interface Add Event for interface {}", portName); - List intExtPortMapList = getIntExtPortMapListForPortName(portName, routerId); - if (intExtPortMapList == null || intExtPortMapList.isEmpty()) { - LOG.debug("processInterfaceAdded : Ip Mapping list is empty/null for portname {}", portName); - return; - } - InstanceIdentifier portIid = NatUtil.buildRouterPortsIdentifier(routerId); - ListenableFuture future = txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> { - for (InternalToExternalPortMap intExtPortMap : intExtPortMapList) { - floatingIPListener.createNATFlowEntries(portName, intExtPortMap, portIid, routerId, tx); - } - }); - futures.add(future); - try { - future.get(); - } catch (InterruptedException | ExecutionException e) { - LOG.error("Error processing interface addition", e); - } - } - - private List getIntExtPortMapListForPortName(String portName, String routerId) { - InstanceIdentifier portToIpMapIdentifier = NatUtil.buildPortToIpMapIdentifier(routerId, portName); - Optional port = - SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker, - LogicalDatastoreType.CONFIGURATION, portToIpMapIdentifier); - if (!port.isPresent()) { - LOG.info("getIntExtPortMapListForPortName : Unable to read router port entry for router ID {} " - + "and port name {}", routerId, portName); - return null; - } - return port.get().getInternalToExternalPortMap(); - } - - private BigInteger getNaptSwitchforRouter(DataBroker broker, String routerName) { - InstanceIdentifier rtrNaptSw = InstanceIdentifier.builder(NaptSwitches.class) - .child(RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build(); - Optional routerToNaptSwitchData = - SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker, - LogicalDatastoreType.CONFIGURATION, rtrNaptSw); - if (routerToNaptSwitchData.isPresent()) { - RouterToNaptSwitch routerToNaptSwitchInstance = routerToNaptSwitchData.get(); - return routerToNaptSwitchInstance.getPrimarySwitchId(); - } - return null; - } - - private void removeNatFlow(BigInteger dpnId, short tableId, Long routerId, String ipAddress, int ipPort) { - - String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, tableId, String.valueOf(routerId), ipAddress, ipPort); - FlowEntity snatFlowEntity = NatUtil.buildFlowEntity(dpnId, tableId, switchFlowRef); - - mdsalManager.removeFlow(snatFlowEntity); - LOG.debug("removeNatFlow : Removed the flow in table {} for the switch with the DPN ID {} for " - + "router {} ip {} port {}", tableId, dpnId, routerId, ipAddress, ipPort); - } - - private List getFixedIpsForPort(String interfname) { - LOG.debug("getFixedIpsForPort : getFixedIpsForPort method is called for interface {}", interfname); - try { - Future> result = - neutronVpnService.getFixedIPsForNeutronPort(new GetFixedIPsForNeutronPortInputBuilder() - .setPortId(new Uuid(interfname)).build()); - - RpcResult rpcResult = result.get(); - if (!rpcResult.isSuccessful()) { - LOG.error("getFixedIpsForPort : RPC Call to GetFixedIPsForNeutronPortOutput returned with Errors {}", - rpcResult.getErrors()); - } else { - return rpcResult.getResult().getFixedIPs(); - } - } catch (InterruptedException | ExecutionException | NullPointerException ex) { - LOG.error("getFixedIpsForPort : Exception while receiving fixedIps for port {}", interfname, ex); - } - return null; - } - - private void processInterfaceRemoved(String portName, BigInteger dpnId, String routerId, - List> futures) { - LOG.trace("processInterfaceRemoved : Processing Interface Removed Event for interface {} on DPN ID {}", - portName, dpnId); - List intExtPortMapList = getIntExtPortMapListForPortName(portName, routerId); - if (intExtPortMapList == null || intExtPortMapList.isEmpty()) { - LOG.debug("processInterfaceRemoved : Ip Mapping list is empty/null for portName {}", portName); - return; - } - InstanceIdentifier portIid = NatUtil.buildRouterPortsIdentifier(routerId); - ListenableFuture future = txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> { - for (InternalToExternalPortMap intExtPortMap : intExtPortMapList) { - LOG.trace("processInterfaceRemoved : Removing DNAT Flow entries for dpnId {} ", dpnId); - floatingIPListener.removeNATFlowEntries(portName, intExtPortMap, portIid, routerId, dpnId, tx); - } - }); - futures.add(future); - try { - future.get(); - } catch (InterruptedException | ExecutionException e) { - LOG.error("Error processing interface removal", e); - } - } - - // TODO Clean up the exception handling - @SuppressWarnings("checkstyle:IllegalCatch") - private void removeSnatEntriesForPort(String interfaceName, String routerName) { - Long routerId = NatUtil.getVpnId(dataBroker, routerName); - if (routerId == NatConstants.INVALID_ID) { - LOG.error("removeSnatEntriesForPort : routerId not found for routername {}", routerName); - return; - } - BigInteger naptSwitch = getNaptSwitchforRouter(dataBroker, routerName); - if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) { - LOG.error("removeSnatEntriesForPort : NaptSwitch is not elected for router {} with Id {}", - routerName, routerId); - return; - } - //getInternalIp for port - List fixedIps = getFixedIpsForPort(interfaceName); - if (fixedIps == null) { - LOG.warn("removeSnatEntriesForPort : Internal Ips not found for InterfaceName {} in router {} with id {}", - interfaceName, routerName, routerId); - return; - } - - for (String internalIp : fixedIps) { - LOG.debug("removeSnatEntriesForPort : Internal Ip retrieved for interface {} is {} in router with Id {}", - interfaceName, internalIp, routerId); - IpPort ipPort = NatUtil.getInternalIpPortInfo(dataBroker, routerId, internalIp); - if (ipPort == null) { - LOG.debug("removeSnatEntriesForPort : no snatint-ip-port-map found for ip:{}", internalIp); - continue; - } - - for (IntIpProtoType protoType: ipPort.getIntIpProtoType()) { - ProtocolTypes protocol = protoType.getProtocol(); - for (Integer portnum : protoType.getPorts()) { - //build and remove the flow in outbound table - try { - removeNatFlow(naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE, routerId, internalIp, portnum); - } catch (Exception ex) { - LOG.error("removeSnatEntriesForPort : Failed to remove snat flow for internalIP {} with " - + "Port {} protocol {} for routerId {} in OUTBOUNDTABLE of NaptSwitch {}", - internalIp, portnum, protocol, routerId, naptSwitch, ex); - } - //Get the external IP address and the port from the model - NAPTEntryEvent.Protocol proto = protocol.toString().equals(ProtocolTypes.TCP.toString()) - ? NAPTEntryEvent.Protocol.TCP : NAPTEntryEvent.Protocol.UDP; - IpPortExternal ipPortExternal = NatUtil.getExternalIpPortMap(dataBroker, routerId, - internalIp, String.valueOf(portnum), proto); - if (ipPortExternal == null) { - LOG.error("removeSnatEntriesForPort : Mapping for internalIp {} with port {} is not found in " - + "router with Id {}", internalIp, portnum, routerId); - return; - } - String externalIpAddress = ipPortExternal.getIpAddress(); - Integer portNumber = ipPortExternal.getPortNum(); - - //build and remove the flow in inboundtable - try { - removeNatFlow(naptSwitch, NwConstants.INBOUND_NAPT_TABLE, routerId, - externalIpAddress, portNumber); - } catch (Exception ex) { - LOG.error("removeSnatEntriesForPort : Failed to remove snat flow internalIP {} with " - + "Port {} protocol {} for routerId {} in INBOUNDTABLE of naptSwitch {}", - externalIpAddress, portNumber, protocol, routerId, naptSwitch, ex); - } - - String internalIpPort = internalIp + ":" + portnum; - // delete the entry from IntExtIpPortMap DS - try { - naptManager.removeFromIpPortMapDS(routerId, internalIpPort, proto); - naptManager.removePortFromPool(internalIpPort, externalIpAddress); - } catch (Exception ex) { - LOG.error("removeSnatEntriesForPort : releaseIpExtPortMapping failed, Removal of " - + "ipportmap {} for router {} failed", internalIpPort, routerId, ex); - } - } - } - // delete the entry from SnatIntIpPortMap DS - LOG.debug("removeSnatEntriesForPort : Removing InternalIp:{} on router {}", internalIp, routerId); - naptManager.removeFromSnatIpPortDS(routerId, internalIp); - } - } - - private class NatFlowAddWorker implements Callable>> { - private String interfaceName; - private String routerName; - - NatFlowAddWorker(String interfaceName,String routerName) { - this.interfaceName = interfaceName; - this.routerName = routerName; - } - - @Override - @SuppressWarnings("checkstyle:IllegalCatch") - public List> call() { - final List> futures = new ArrayList<>(); - LOG.trace("call : Interface {} up event received", interfaceName); - try { - LOG.trace("call : Port added event received for interface {} ", interfaceName); - processInterfaceAdded(interfaceName, routerName, futures); - } catch (Exception ex) { - LOG.error("call : Exception caught in Interface {} Operational State Up event", - interfaceName, ex); - } - return futures; - } - } - - private class NatFlowUpdateWorker implements Callable>> { - private Interface original; - private Interface update; - private String routerName; - - NatFlowUpdateWorker(Interface original, Interface update, String routerName) { - this.original = original; - this.update = update; - this.routerName = routerName; - } - - @Override - @SuppressWarnings("checkstyle:IllegalCatch") - public List> call() { - final List> futures = new ArrayList<>(); - String interfaceName = update.getName(); - IntfTransitionState state = getTransitionState(original.getOperStatus(), update.getOperStatus()); - if (state.equals(IntfTransitionState.STATE_IGNORE)) { - LOG.info("NAT Service: Interface {} state original {} updated {} not handled", - interfaceName, original.getOperStatus(), update.getOperStatus()); - return futures; - } - if (state.equals(IntfTransitionState.STATE_UP)) { - LOG.debug("call : Port UP event received for interface {} ", interfaceName); - } else if (state.equals(IntfTransitionState.STATE_DOWN)) { - LOG.debug("call : Port DOWN event received for interface {} ", interfaceName); - try { - removeSnatEntriesForPort(interfaceName, routerName); - } catch (Exception ex) { - LOG.error("call : Exception caught in Interface {} OperationalStateDown", interfaceName, ex); - } - } - return futures; - } - } - - private class NatFlowRemoveWorker implements Callable>> { - private Interface delintrf; - private String routerName; - private BigInteger intfDpnId; - - NatFlowRemoveWorker(Interface delintrf, BigInteger intfDpnId, String routerName) { - this.delintrf = delintrf; - this.routerName = routerName; - this.intfDpnId = intfDpnId; - } - - @Override - @SuppressWarnings("checkstyle:IllegalCatch") - public List> call() { - final List> futures = new ArrayList<>(); - final String interfaceName = delintrf.getName(); - LOG.trace("call : Interface {} removed event received", delintrf); - try { - LOG.trace("call : Port removed event received for interface {} ", interfaceName); - processInterfaceRemoved(interfaceName, intfDpnId, routerName, futures); - removeSnatEntriesForPort(interfaceName, routerName); - } catch (Exception e) { - LOG.error("call : Exception caught in Interface {} OperationalStateRemove", interfaceName, e); - } - return futures; - } - } } diff --git a/natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatSouthboundEventHandlers.java b/natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatSouthboundEventHandlers.java new file mode 100644 index 0000000000..caa14eb5d0 --- /dev/null +++ b/natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatSouthboundEventHandlers.java @@ -0,0 +1,560 @@ +/* + * Copyright (c) 2016 - 2018 Ericsson India Global Services Pvt Ltd. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.netvirt.natservice.internal; + +import static org.opendaylight.genius.infra.Datastore.CONFIGURATION; +import static org.opendaylight.genius.infra.Datastore.OPERATIONAL; + +import com.google.common.base.Optional; +import com.google.common.collect.HashBasedTable; +import com.google.common.collect.Table; +import com.google.common.util.concurrent.FluentFuture; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.MoreExecutors; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker; +import org.opendaylight.genius.infra.Datastore.Operational; +import org.opendaylight.genius.infra.ManagedNewTransactionRunner; +import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl; +import org.opendaylight.genius.infra.TypedReadWriteTransaction; +import org.opendaylight.genius.mdsalutil.FlowEntity; +import org.opendaylight.genius.mdsalutil.NwConstants; +import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager; +import org.opendaylight.infrautils.jobcoordinator.JobCoordinator; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid; +import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.router.interfaces.RouterInterface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.NaptSwitches; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProtocolTypes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPorts; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.Ports; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMap; +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; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitch; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.neutron.vip.states.VipState; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.intip.port.map.IpPort; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.intip.port.map.ip.port.IntIpProtoType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetFixedIPsForNeutronPortInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetFixedIPsForNeutronPortOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NeutronvpnService; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Singleton +public class NatSouthboundEventHandlers { + + private static final Logger LOG = LoggerFactory.getLogger(NatSouthboundEventHandlers.class); + private static final String NAT_DS = "NATDS"; + private final DataBroker dataBroker; + private final ManagedNewTransactionRunner txRunner; + private final OdlInterfaceRpcService odlInterfaceRpcService; + private final JobCoordinator coordinator; + private final FloatingIPListener floatingIPListener; + private final NeutronvpnService neutronVpnService; + private final IMdsalApiManager mdsalManager; + private final NaptManager naptManager; + private final VipStateTracker vipStateTracker; + Table stateTable = HashBasedTable.create(); + + enum IntfTransitionState { + STATE_UP, + STATE_DOWN, + STATE_IGNORE + } + + private void initialize() { + stateTable.put(Interface.OperStatus.Up, Interface.OperStatus.Down, IntfTransitionState.STATE_DOWN); + stateTable.put(Interface.OperStatus.Down, Interface.OperStatus.Up, IntfTransitionState.STATE_UP); + stateTable.put(Interface.OperStatus.Unknown, Interface.OperStatus.Up, IntfTransitionState.STATE_UP); + stateTable.put(Interface.OperStatus.Unknown, Interface.OperStatus.Down, IntfTransitionState.STATE_DOWN); + stateTable.put(Interface.OperStatus.Up, Interface.OperStatus.Unknown, IntfTransitionState.STATE_DOWN); + } + + @Inject + public NatSouthboundEventHandlers(final DataBroker dataBroker, + final OdlInterfaceRpcService odlInterfaceRpcService, final JobCoordinator coordinator, + final FloatingIPListener floatingIPListener,final NeutronvpnService neutronvpnService, + final IMdsalApiManager mdsalManager, final NaptManager naptManager, final VipStateTracker vipStateTracker) { + this.dataBroker = dataBroker; + this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker); + this.odlInterfaceRpcService = odlInterfaceRpcService; + this.coordinator = coordinator; + this.floatingIPListener = floatingIPListener; + this.neutronVpnService = neutronvpnService; + this.mdsalManager = mdsalManager; + this.naptManager = naptManager; + this.vipStateTracker = vipStateTracker; + initialize(); + } + + public void handleAdd(String interfaceName, BigInteger intfDpnId, RouterInterface routerInterface) { + handleAdd(interfaceName, intfDpnId, routerInterface, null); + } + + public void handleAdd(String interfaceName, BigInteger intfDpnId, + RouterInterface routerInterface, VipState vipState) { + String routerName = routerInterface.getRouterName(); + NatInterfaceStateAddWorker natIfaceStateAddWorker = new NatInterfaceStateAddWorker(interfaceName, + intfDpnId, routerName); + coordinator.enqueueJob(NAT_DS + "-" + interfaceName, natIfaceStateAddWorker); + + NatFlowAddWorker natFlowAddWorker = new NatFlowAddWorker(interfaceName, routerName, intfDpnId, vipState); + coordinator.enqueueJob(NAT_DS + "-" + interfaceName, natFlowAddWorker, NatConstants.NAT_DJC_MAX_RETRIES); + } + + public void handleRemove(String interfaceName, BigInteger intfDpnId, RouterInterface routerInterface) { + String routerName = routerInterface.getRouterName(); + NatInterfaceStateRemoveWorker natIfaceStateRemoveWorker = new NatInterfaceStateRemoveWorker(interfaceName, + intfDpnId, routerName); + coordinator.enqueueJob(NAT_DS + "-" + interfaceName, natIfaceStateRemoveWorker); + + NatFlowRemoveWorker natFlowRemoveWorker = new NatFlowRemoveWorker(interfaceName, intfDpnId, routerName); + coordinator.enqueueJob(NAT_DS + "-" + interfaceName, natFlowRemoveWorker, + NatConstants.NAT_DJC_MAX_RETRIES); + } + + public void handleUpdate(Interface original, Interface update, + BigInteger intfDpnId, RouterInterface routerInterface) { + String routerName = routerInterface.getRouterName(); + NatInterfaceStateUpdateWorker natIfaceStateupdateWorker = new NatInterfaceStateUpdateWorker(original, + update, intfDpnId, routerName); + coordinator.enqueueJob(NAT_DS + "-" + update.getName(), natIfaceStateupdateWorker); + NatFlowUpdateWorker natFlowUpdateWorker = new NatFlowUpdateWorker(original, update, routerName); + coordinator.enqueueJob(NAT_DS + "-" + update.getName(), natFlowUpdateWorker, + NatConstants.NAT_DJC_MAX_RETRIES); + } + + void handleRouterInterfacesUpEvent(String routerName, String interfaceName, BigInteger dpId, + TypedReadWriteTransaction operTx) throws ExecutionException, InterruptedException { + LOG.debug("handleRouterInterfacesUpEvent : Handling UP event for router interface {} in Router {} on Dpn {}", + interfaceName, routerName, dpId); + NatUtil.addToNeutronRouterDpnsMap(routerName, interfaceName, dpId, operTx); + NatUtil.addToDpnRoutersMap(routerName, interfaceName, dpId, operTx); + } + + void handleRouterInterfacesDownEvent(String routerName, String interfaceName, BigInteger dpnId, + TypedReadWriteTransaction operTx) + throws ExecutionException, InterruptedException { + LOG.debug("handleRouterInterfacesDownEvent : Handling DOWN event for router Interface {} in Router {}", + interfaceName, routerName); + NatUtil.removeFromNeutronRouterDpnsMap(routerName, dpnId, operTx); + NatUtil.removeFromDpnRoutersMap(dataBroker, routerName, interfaceName, dpnId, odlInterfaceRpcService, + operTx); + } + + private IntfTransitionState getTransitionState(Interface.OperStatus original , Interface.OperStatus updated) { + IntfTransitionState transitionState = stateTable.get(original, updated); + + if (transitionState == null) { + return IntfTransitionState.STATE_IGNORE; + } + return transitionState; + } + + private class NatInterfaceStateAddWorker implements Callable>> { + private String interfaceName; + private String routerName; + private BigInteger intfDpnId; + + NatInterfaceStateAddWorker(String interfaceName, BigInteger intfDpnId, String routerName) { + this.interfaceName = interfaceName; + this.routerName = routerName; + this.intfDpnId = intfDpnId; + } + + @Override + @SuppressWarnings("checkstyle:IllegalCatch") + public List> call() { + List> futures = new ArrayList<>(); + try { + LOG.trace("call : Received interface {} PORT UP OR ADD event ", interfaceName); + String dpnLock = NatConstants.NAT_DJC_PREFIX + intfDpnId; + synchronized (dpnLock.intern()) { + futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, tx -> + handleRouterInterfacesUpEvent(routerName, interfaceName, intfDpnId, tx))); + } + } catch (Exception e) { + LOG.error("call : Exception caught in Interface {} Operational State Up event", + interfaceName, e); + } + return futures; + } + } + + private class NatInterfaceStateRemoveWorker implements Callable>> { + private String interfaceName; + private String routerName; + private BigInteger intfDpnId; + + NatInterfaceStateRemoveWorker(String interfaceName, BigInteger intfDpnId, String routerName) { + this.interfaceName = interfaceName; + this.routerName = routerName; + this.intfDpnId = intfDpnId; + } + + @Override + @SuppressWarnings("checkstyle:IllegalCatch") + public List> call() { + List> futures = new ArrayList<>(); + try { + LOG.trace("call : Received interface {} PORT DOWN or REMOVE event", interfaceName); + String dpnLock = NatConstants.NAT_DJC_PREFIX + intfDpnId; + synchronized (dpnLock.intern()) { + futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, tx -> + handleRouterInterfacesDownEvent(routerName, interfaceName, intfDpnId, tx))); + } + } catch (Exception e) { + LOG.error("call : Exception observed in handling deletion of VPN Interface {}.", interfaceName, e); + } + return futures; + } + } + + private class NatInterfaceStateUpdateWorker implements Callable>> { + private Interface original; + private Interface update; + private BigInteger intfDpnId; + private String routerName; + + NatInterfaceStateUpdateWorker(Interface original, Interface update, BigInteger intfDpnId, String routerName) { + this.original = original; + this.update = update; + this.intfDpnId = intfDpnId; + this.routerName = routerName; + } + + @Override + @SuppressWarnings("checkstyle:IllegalCatch") + public List> call() { + List> futures = new ArrayList<>(); + try { + final String interfaceName = update.getName(); + LOG.trace("call : Received interface {} state change event", interfaceName); + LOG.debug("call : DPN ID {} for the interface {} ", intfDpnId, interfaceName); + String dpnLock = NatConstants.NAT_DJC_PREFIX + intfDpnId; + synchronized (dpnLock.intern()) { + IntfTransitionState state = getTransitionState(original.getOperStatus(), update.getOperStatus()); + if (state.equals(IntfTransitionState.STATE_IGNORE)) { + LOG.info("NAT Service: Interface {} state original {} updated {} not handled", + interfaceName, original.getOperStatus(), update.getOperStatus()); + return futures; + } + futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, tx -> { + if (state.equals(IntfTransitionState.STATE_DOWN)) { + LOG.debug("call : DPN {} connnected to the interface {} has gone down." + + "Hence clearing the dpn-vpninterfaces-list entry from the" + + " neutron-router-dpns model in the ODL:L3VPN", intfDpnId, interfaceName); + // If the interface state is unknown, it means that the corresponding DPN has gone down. + // So remove the dpn-vpninterfaces-list from the neutron-router-dpns model. + NatUtil.removeFromNeutronRouterDpnsMap(routerName, interfaceName, + intfDpnId, tx); + } else if (state.equals(IntfTransitionState.STATE_UP)) { + LOG.debug("call : DPN {} connnected to the interface {} has come up. Hence adding" + + " the dpn-vpninterfaces-list entry from the neutron-router-dpns model" + + " in the ODL:L3VPN", intfDpnId, interfaceName); + handleRouterInterfacesUpEvent(routerName, interfaceName, intfDpnId, tx); + } + })); + } + } catch (Exception e) { + LOG.error("call : Exception observed in handling updation of VPN Interface {}.", update.getName(), e); + } + return futures; + } + } + + private void processInterfaceAdded(String portName, String routerId, BigInteger dpnId, VipState vipState) { + LOG.trace("processInterfaceAdded : Processing Interface Add Event for interface {}", portName); + List intExtPortMapList = getIntExtPortMapListForPortName(portName, routerId); + if (intExtPortMapList == null || intExtPortMapList.isEmpty()) { + LOG.debug("processInterfaceAdded : Ip Mapping list is empty/null for portname {}", portName); + return; + } + InstanceIdentifier portIid = NatUtil.buildRouterPortsIdentifier(routerId); + FluentFuture future = txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> { + for (InternalToExternalPortMap intExtPortMap : intExtPortMapList) { + floatingIPListener.createNATFlowEntries(portName, intExtPortMap, portIid, routerId, dpnId, tx); + } + }); + future.transform((ignored) -> { + if (vipState != null) { + return this.vipStateTracker.writeVipState(vipState); + } + return null; + }, MoreExecutors.directExecutor()); + } + + private List getIntExtPortMapListForPortName(String portName, String routerId) { + InstanceIdentifier portToIpMapIdentifier = NatUtil.buildPortToIpMapIdentifier(routerId, portName); + Optional port = + SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker, + LogicalDatastoreType.CONFIGURATION, portToIpMapIdentifier); + if (!port.isPresent()) { + LOG.info("getIntExtPortMapListForPortName : Unable to read router port entry for router ID {} " + + "and port name {}", routerId, portName); + return null; + } + return port.get().getInternalToExternalPortMap(); + } + + private BigInteger getNaptSwitchforRouter(DataBroker broker, String routerName) { + InstanceIdentifier rtrNaptSw = InstanceIdentifier.builder(NaptSwitches.class) + .child(RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build(); + Optional routerToNaptSwitchData = + SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker, + LogicalDatastoreType.CONFIGURATION, rtrNaptSw); + if (routerToNaptSwitchData.isPresent()) { + RouterToNaptSwitch routerToNaptSwitchInstance = routerToNaptSwitchData.get(); + return routerToNaptSwitchInstance.getPrimarySwitchId(); + } + return null; + } + + private void removeNatFlow(BigInteger dpnId, short tableId, Long routerId, String ipAddress, int ipPort) { + + String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, tableId, String.valueOf(routerId), ipAddress, ipPort); + FlowEntity snatFlowEntity = NatUtil.buildFlowEntity(dpnId, tableId, switchFlowRef); + + mdsalManager.removeFlow(snatFlowEntity); + LOG.debug("removeNatFlow : Removed the flow in table {} for the switch with the DPN ID {} for " + + "router {} ip {} port {}", tableId, dpnId, routerId, ipAddress, ipPort); + } + + private List getFixedIpsForPort(String interfname) { + LOG.debug("getFixedIpsForPort : getFixedIpsForPort method is called for interface {}", interfname); + try { + Future> result = + neutronVpnService.getFixedIPsForNeutronPort(new GetFixedIPsForNeutronPortInputBuilder() + .setPortId(new Uuid(interfname)).build()); + + RpcResult rpcResult = result.get(); + if (!rpcResult.isSuccessful()) { + LOG.error("getFixedIpsForPort : RPC Call to GetFixedIPsForNeutronPortOutput returned with Errors {}", + rpcResult.getErrors()); + } else { + return rpcResult.getResult().getFixedIPs(); + } + } catch (InterruptedException | ExecutionException | NullPointerException ex) { + LOG.error("getFixedIpsForPort : Exception while receiving fixedIps for port {}", interfname, ex); + } + return null; + } + + private void processInterfaceRemoved(String portName, BigInteger dpnId, String routerId, + List> futures) { + LOG.trace("processInterfaceRemoved : Processing Interface Removed Event for interface {} on DPN ID {}", + portName, dpnId); + List intExtPortMapList = getIntExtPortMapListForPortName(portName, routerId); + if (intExtPortMapList == null || intExtPortMapList.isEmpty()) { + LOG.debug("processInterfaceRemoved : Ip Mapping list is empty/null for portName {}", portName); + return; + } + InstanceIdentifier portIid = NatUtil.buildRouterPortsIdentifier(routerId); + ListenableFuture future = txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> { + for (InternalToExternalPortMap intExtPortMap : intExtPortMapList) { + LOG.trace("processInterfaceRemoved : Removing DNAT Flow entries for dpnId {} ", dpnId); + floatingIPListener.removeNATFlowEntries(portName, intExtPortMap, portIid, routerId, dpnId, tx); + } + }); + futures.add(future); + try { + future.get(); + } catch (InterruptedException | ExecutionException e) { + LOG.error("Error processing interface removal", e); + } + } + + // TODO Clean up the exception handling + @SuppressWarnings("checkstyle:IllegalCatch") + private void removeSnatEntriesForPort(String interfaceName, String routerName) { + Long routerId = NatUtil.getVpnId(dataBroker, routerName); + if (routerId == NatConstants.INVALID_ID) { + LOG.error("removeSnatEntriesForPort : routerId not found for routername {}", routerName); + return; + } + BigInteger naptSwitch = getNaptSwitchforRouter(dataBroker, routerName); + if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) { + LOG.error("removeSnatEntriesForPort : NaptSwitch is not elected for router {} with Id {}", + routerName, routerId); + return; + } + //getInternalIp for port + List fixedIps = getFixedIpsForPort(interfaceName); + if (fixedIps == null) { + LOG.warn("removeSnatEntriesForPort : Internal Ips not found for InterfaceName {} in router {} with id {}", + interfaceName, routerName, routerId); + return; + } + + for (String internalIp : fixedIps) { + LOG.debug("removeSnatEntriesForPort : Internal Ip retrieved for interface {} is {} in router with Id {}", + interfaceName, internalIp, routerId); + IpPort ipPort = NatUtil.getInternalIpPortInfo(dataBroker, routerId, internalIp); + if (ipPort == null) { + LOG.debug("removeSnatEntriesForPort : no snatint-ip-port-map found for ip:{}", internalIp); + continue; + } + + for (IntIpProtoType protoType: ipPort.getIntIpProtoType()) { + ProtocolTypes protocol = protoType.getProtocol(); + for (Integer portnum : protoType.getPorts()) { + //build and remove the flow in outbound table + try { + removeNatFlow(naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE, routerId, internalIp, portnum); + } catch (Exception ex) { + LOG.error("removeSnatEntriesForPort : Failed to remove snat flow for internalIP {} with " + + "Port {} protocol {} for routerId {} in OUTBOUNDTABLE of NaptSwitch {}", + internalIp, portnum, protocol, routerId, naptSwitch, ex); + } + //Get the external IP address and the port from the model + NAPTEntryEvent.Protocol proto = protocol.toString().equals(ProtocolTypes.TCP.toString()) + ? NAPTEntryEvent.Protocol.TCP : NAPTEntryEvent.Protocol.UDP; + IpPortExternal ipPortExternal = NatUtil.getExternalIpPortMap(dataBroker, routerId, + internalIp, String.valueOf(portnum), proto); + if (ipPortExternal == null) { + LOG.error("removeSnatEntriesForPort : Mapping for internalIp {} with port {} is not found in " + + "router with Id {}", internalIp, portnum, routerId); + return; + } + String externalIpAddress = ipPortExternal.getIpAddress(); + Integer portNumber = ipPortExternal.getPortNum(); + + //build and remove the flow in inboundtable + try { + removeNatFlow(naptSwitch, NwConstants.INBOUND_NAPT_TABLE, routerId, + externalIpAddress, portNumber); + } catch (Exception ex) { + LOG.error("removeSnatEntriesForPort : Failed to remove snat flow internalIP {} with " + + "Port {} protocol {} for routerId {} in INBOUNDTABLE of naptSwitch {}", + externalIpAddress, portNumber, protocol, routerId, naptSwitch, ex); + } + + String internalIpPort = internalIp + ":" + portnum; + // delete the entry from IntExtIpPortMap DS + try { + naptManager.removeFromIpPortMapDS(routerId, internalIpPort, proto); + naptManager.removePortFromPool(internalIpPort, externalIpAddress); + } catch (Exception ex) { + LOG.error("removeSnatEntriesForPort : releaseIpExtPortMapping failed, Removal of " + + "ipportmap {} for router {} failed", internalIpPort, routerId, ex); + } + } + } + // delete the entry from SnatIntIpPortMap DS + LOG.debug("removeSnatEntriesForPort : Removing InternalIp:{} on router {}", internalIp, routerId); + naptManager.removeFromSnatIpPortDS(routerId, internalIp); + } + } + + private class NatFlowAddWorker implements Callable>> { + private String interfaceName; + private String routerName; + private BigInteger dpnId; + private VipState vipState; + + NatFlowAddWorker(String interfaceName,String routerName, BigInteger dpnId, VipState vipState) { + this.interfaceName = interfaceName; + this.routerName = routerName; + this.dpnId = dpnId; + this.vipState = vipState; + } + + @Override + @SuppressWarnings("checkstyle:IllegalCatch") + public List> call() { + final List> futures = new ArrayList<>(); + LOG.trace("call : Interface {} up event received", interfaceName); + try { + LOG.trace("call : Port added event received for interface {} ", interfaceName); + processInterfaceAdded(interfaceName, routerName, dpnId, vipState); + } catch (Exception ex) { + LOG.error("call : Exception caught in Interface {} Operational State Up event", + interfaceName, ex); + } + return futures; + } + } + + private class NatFlowUpdateWorker implements Callable>> { + private Interface original; + private Interface update; + private String routerName; + + NatFlowUpdateWorker(Interface original, Interface update, String routerName) { + this.original = original; + this.update = update; + this.routerName = routerName; + } + + @Override + @SuppressWarnings("checkstyle:IllegalCatch") + public List> call() { + final List> futures = new ArrayList<>(); + String interfaceName = update.getName(); + IntfTransitionState state = getTransitionState(original.getOperStatus(), update.getOperStatus()); + if (state.equals(IntfTransitionState.STATE_IGNORE)) { + LOG.info("NAT Service: Interface {} state original {} updated {} not handled", + interfaceName, original.getOperStatus(), update.getOperStatus()); + return futures; + } + if (state.equals(IntfTransitionState.STATE_UP)) { + LOG.debug("call : Port UP event received for interface {} ", interfaceName); + } else if (state.equals(IntfTransitionState.STATE_DOWN)) { + LOG.debug("call : Port DOWN event received for interface {} ", interfaceName); + try { + removeSnatEntriesForPort(interfaceName, routerName); + } catch (Exception ex) { + LOG.error("call : Exception caught in Interface {} OperationalStateDown", interfaceName, ex); + } + } + return futures; + } + } + + private class NatFlowRemoveWorker implements Callable>> { + private String interfaceName; + private String routerName; + private BigInteger intfDpnId; + + NatFlowRemoveWorker(String interfaceName, BigInteger intfDpnId, String routerName) { + this.interfaceName = interfaceName; + this.routerName = routerName; + this.intfDpnId = intfDpnId; + } + + @Override + @SuppressWarnings("checkstyle:IllegalCatch") + public List> call() { + final List> futures = new ArrayList<>(); + LOG.trace("call : Interface {} removed event received", interfaceName); + try { + LOG.trace("call : Port removed event received for interface {} ", interfaceName); + processInterfaceRemoved(interfaceName, intfDpnId, routerName, futures); + removeSnatEntriesForPort(interfaceName, routerName); + } catch (Exception e) { + LOG.error("call : Exception caught in Interface {} OperationalStateRemove", interfaceName, e); + } + return futures; + } + } +} diff --git a/natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/VipStateTracker.java b/natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/VipStateTracker.java new file mode 100644 index 0000000000..b1c29ad054 --- /dev/null +++ b/natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/VipStateTracker.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2018 Red Hat, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.netvirt.natservice.internal; + +import static org.opendaylight.genius.infra.Datastore.OPERATIONAL; + +import com.google.common.util.concurrent.FluentFuture; +import java.math.BigInteger; +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.genius.infra.ManagedNewTransactionRunner; +import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl; +import org.opendaylight.genius.mdsalutil.cache.DataObjectCache; +import org.opendaylight.infrautils.caches.CacheProvider; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.NeutronVipStates; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.neutron.vip.states.VipState; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.neutron.vip.states.VipStateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.neutron.vip.states.VipStateKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +@Singleton +public class VipStateTracker extends DataObjectCache { + + private ManagedNewTransactionRunner txRunner = null; + + @Inject + public VipStateTracker(DataBroker dataBroker, CacheProvider cacheProvider) { + super(VipState.class, + dataBroker, + LogicalDatastoreType.OPERATIONAL, + InstanceIdentifier.builder(NeutronVipStates.class).child(VipState.class).build(), + cacheProvider, + (iid, vipState) -> vipState.key().getIp(), + ip -> InstanceIdentifier.builder(NeutronVipStates.class) .child(VipState.class, new VipStateKey(ip)).build() + ); + this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker); + } + + public VipState buildVipState(String ip, String mac, BigInteger dpnId, String ifcName) { + return new VipStateBuilder().setIp(ip).setDpnId(dpnId).setIfcName(ifcName).build(); + } + + public FluentFuture writeVipState(VipState vipState) { + return txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, tx -> { + tx.put(InstanceIdentifier.builder(NeutronVipStates.class) + .child(VipState.class, vipState.key()).build(), + vipState, true); + }); + } +} diff --git a/natservice/impl/src/main/resources/org/opendaylight/blueprint/natservice.xml b/natservice/impl/src/main/resources/org/opendaylight/blueprint/natservice.xml index e5ba2c416e..0dae2be35f 100644 --- a/natservice/impl/src/main/resources/org/opendaylight/blueprint/natservice.xml +++ b/natservice/impl/src/main/resources/org/opendaylight/blueprint/natservice.xml @@ -32,6 +32,8 @@ interface="org.opendaylight.genius.datastoreutils.listeners.DataTreeEventCallbackRegistrar"/> + @@ -69,4 +71,7 @@ + + diff --git a/vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/iplearn/AbstractIpLearnNotificationHandler.java b/vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/iplearn/AbstractIpLearnNotificationHandler.java index ab1b8d6bfd..a5a563edba 100644 --- a/vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/iplearn/AbstractIpLearnNotificationHandler.java +++ b/vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/iplearn/AbstractIpLearnNotificationHandler.java @@ -21,6 +21,7 @@ import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager; import org.opendaylight.genius.mdsalutil.NWUtil; import org.opendaylight.netvirt.neutronvpn.api.enums.IpVersionChoice; +import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager; import org.opendaylight.netvirt.vpnmanager.VpnUtil; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix; @@ -34,6 +35,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.lea import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPort; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.config.rev161130.VpnConfig; +import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,14 +51,17 @@ public abstract class AbstractIpLearnNotificationHandler { protected final IInterfaceManager interfaceManager; protected final VpnConfig config; protected final VpnUtil vpnUtil; + protected final INeutronVpnManager neutronVpnManager; public AbstractIpLearnNotificationHandler(DataBroker dataBroker, IdManagerService idManager, - IInterfaceManager interfaceManager, VpnConfig vpnConfig, VpnUtil vpnUtil) { + IInterfaceManager interfaceManager, VpnConfig vpnConfig, + VpnUtil vpnUtil, INeutronVpnManager neutronVpnManager) { this.dataBroker = dataBroker; this.idManager = idManager; this.interfaceManager = interfaceManager; this.config = vpnConfig; this.vpnUtil = vpnUtil; + this.neutronVpnManager = neutronVpnManager; long duration = config.getIpLearnTimeout() * 10; long cacheSize = config.getMigrateIpCacheSize().longValue(); @@ -91,55 +96,71 @@ public abstract class AbstractIpLearnNotificationHandler { protected void processIpLearning(String srcInterface, IpAddress srcIP, MacAddress srcMac, BigInteger metadata, IpAddress dstIP, Uuid srcIpSubnetId) { - if (metadata != null && !Objects.equals(metadata, BigInteger.ZERO)) { - Optional> vpnList = vpnUtil.getVpnHandlingIpv4AssociatedWithInterface(srcInterface); - if (vpnList.isPresent()) { - String srcIpToQuery = srcIP.stringValue(); - String destIpToQuery = dstIP.stringValue(); - for (String vpnName : vpnList.get()) { - LOG.info("Received ARP/NA for sender MAC {} and sender IP {} via interface {}", - srcMac.getValue(), srcIpToQuery, srcInterface); - VpnPortipToPort vpnPortipToPort = - vpnUtil.getNeutronPortFromVpnPortFixedIp(vpnName, srcIpToQuery); - if (vpnPortipToPort != null) { - /* This is a well known neutron port and so should be ignored - * from being discovered - */ - continue; - } - if (srcIpSubnetId != null) { - Subnetmap snMap = vpnUtil.getSubnetmapFromItsUuid(srcIpSubnetId); - if (snMap != null && snMap.getVpnId() == null) { - /* If the subnet is not part of vpn then it should be ignored - * from being discovered. This use case will come for dual stack - * network. i.e V6 or V4 subnet only part of VPN. - */ - continue; - } - } - LearntVpnVipToPort learntVpnVipToPort = vpnUtil.getLearntVpnVipToPort(vpnName, srcIpToQuery); - if (learntVpnVipToPort != null) { - String oldPortName = learntVpnVipToPort.getPortName(); - String oldMac = learntVpnVipToPort.getMacAddress(); - if (!oldMac.equalsIgnoreCase(srcMac.getValue())) { - //MAC has changed for requested IP - LOG.info("ARP/NA Source IP/MAC data modified for IP {} with MAC {} and Port {}", - srcIpToQuery, srcMac, srcInterface); - synchronized ((vpnName + srcIpToQuery).intern()) { - vpnUtil.createLearntVpnVipToPortEvent(vpnName, srcIpToQuery, destIpToQuery, - oldPortName, oldMac, LearntVpnVipToPortEventAction.Delete, null); - putVpnIpToMigrateIpCache(vpnName, srcIpToQuery, srcMac); - } - } - } else if (!isIpInMigrateCache(vpnName, srcIpToQuery)) { - learnMacFromIncomingPacket(vpnName, srcInterface, srcIP, srcMac, dstIP); - } + + if (metadata == null || Objects.equals(metadata, BigInteger.ZERO)) { + return; + } + + Optional> vpnList = vpnUtil.getVpnHandlingIpv4AssociatedWithInterface(srcInterface); + if (!vpnList.isPresent()) { + LOG.info("IP LEARN NO_RESOLVE: VPN not configured. Ignoring responding to ARP/NA requests from this" + + " Interface {}.", srcInterface); + return; + } + + String srcIpToQuery = srcIP.stringValue(); + String destIpToQuery = dstIP.stringValue(); + for (String vpnName : vpnList.get()) { + LOG.info("Received ARP/NA for sender MAC {} and sender IP {} via interface {}", + srcMac.getValue(), srcIpToQuery, srcInterface); + VpnPortipToPort vpnPortipToPort = + vpnUtil.getNeutronPortFromVpnPortFixedIp(vpnName, srcIpToQuery); + if (vpnPortipToPort != null) { + /* This is a well known neutron port and so should be ignored + * from being discovered...unless it is an Octavia VIP + */ + String portName = vpnPortipToPort.getPortName(); + Port neutronPort = neutronVpnManager.getNeutronPort(portName); + + if (neutronPort == null) { + LOG.warn("{} should have been a neutron port but could not retrieve it. Aborting processing", + portName); + continue; } - } else { - LOG.info("IP LEARN NO_RESOLVE: VPN not configured. Ignoring responding to ARP/NA requests from this" - + " Interface {}.", srcInterface); - return; + if (!"Octavia".equals(neutronPort.getDeviceOwner())) { + LOG.debug("Neutron port {} is not an Octavia port, ignoring", portName); + continue; + } + } + + if (srcIpSubnetId != null) { + Subnetmap snMap = vpnUtil.getSubnetmapFromItsUuid(srcIpSubnetId); + if (snMap != null && snMap.getVpnId() == null) { + /* If the subnet is not part of vpn then it should be ignored + * from being discovered. This use case will come for dual stack + * network. i.e V6 or V4 subnet only part of VPN. + */ + continue; + } + } + + LearntVpnVipToPort learntVpnVipToPort = vpnUtil.getLearntVpnVipToPort(vpnName, srcIpToQuery); + if (learntVpnVipToPort != null) { + String oldPortName = learntVpnVipToPort.getPortName(); + String oldMac = learntVpnVipToPort.getMacAddress(); + if (!oldMac.equalsIgnoreCase(srcMac.getValue())) { + //MAC has changed for requested IP + LOG.info("ARP/NA Source IP/MAC data modified for IP {} with MAC {} and Port {}", + srcIpToQuery, srcMac, srcInterface); + synchronized ((vpnName + srcIpToQuery).intern()) { + vpnUtil.createLearntVpnVipToPortEvent(vpnName, srcIpToQuery, destIpToQuery, + oldPortName, oldMac, LearntVpnVipToPortEventAction.Delete, null); + putVpnIpToMigrateIpCache(vpnName, srcIpToQuery, srcMac); + } + } + } else if (!isIpInMigrateCache(vpnName, srcIpToQuery)) { + learnMacFromIncomingPacket(vpnName, srcInterface, srcIP, srcMac, dstIP); } } } diff --git a/vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/iplearn/ipv4/ArpNotificationHandler.java b/vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/iplearn/ipv4/ArpNotificationHandler.java index 610b116926..adba9dd4de 100644 --- a/vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/iplearn/ipv4/ArpNotificationHandler.java +++ b/vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/iplearn/ipv4/ArpNotificationHandler.java @@ -12,6 +12,7 @@ import javax.inject.Inject; import javax.inject.Singleton; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager; +import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager; import org.opendaylight.netvirt.vpnmanager.VpnUtil; import org.opendaylight.netvirt.vpnmanager.iplearn.AbstractIpLearnNotificationHandler; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; @@ -32,8 +33,9 @@ public class ArpNotificationHandler extends AbstractIpLearnNotificationHandler i @Inject public ArpNotificationHandler(DataBroker dataBroker, IdManagerService idManager, - IInterfaceManager interfaceManager, VpnConfig vpnConfig, VpnUtil vpnUtil) { - super(dataBroker, idManager, interfaceManager, vpnConfig, vpnUtil); + IInterfaceManager interfaceManager, VpnConfig vpnConfig, + VpnUtil vpnUtil, INeutronVpnManager neutronVpnManager) { + super(dataBroker, idManager, interfaceManager, vpnConfig, vpnUtil, neutronVpnManager); } @Override diff --git a/vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/iplearn/ipv6/Ipv6NaNotificationHandler.java b/vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/iplearn/ipv6/Ipv6NaNotificationHandler.java index cbc67ec47f..61170631f2 100644 --- a/vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/iplearn/ipv6/Ipv6NaNotificationHandler.java +++ b/vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/iplearn/ipv6/Ipv6NaNotificationHandler.java @@ -13,6 +13,7 @@ import javax.inject.Inject; import javax.inject.Singleton; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager; +import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager; import org.opendaylight.netvirt.vpnmanager.VpnUtil; import org.opendaylight.netvirt.vpnmanager.iplearn.AbstractIpLearnNotificationHandler; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; @@ -31,8 +32,9 @@ public class Ipv6NaNotificationHandler extends AbstractIpLearnNotificationHandle @Inject public Ipv6NaNotificationHandler(DataBroker dataBroker, IdManagerService idManager, - IInterfaceManager interfaceManager, VpnConfig vpnConfig, VpnUtil vpnUtil) { - super(dataBroker, idManager, interfaceManager, vpnConfig, vpnUtil); + IInterfaceManager interfaceManager, VpnConfig vpnConfig, + VpnUtil vpnUtil, INeutronVpnManager neutronVpnManager) { + super(dataBroker, idManager, interfaceManager, vpnConfig, vpnUtil, neutronVpnManager); } @Override -- 2.36.6