}
}
}
+
+ 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;
+ }
+ }
+ }
}
InstanceIdentifier<RouterPorts> 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);
}
}
void createNATFlowEntries(String interfaceName, final InternalToExternalPortMap mapping,
- final InstanceIdentifier<RouterPorts> portIid, final String routerName,
+ final InstanceIdentifier<RouterPorts> portIid, final String routerName, BigInteger dpnId,
TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
if (!validateIpMapping(mapping)) {
LOG.error("createNATFlowEntries : Not a valid ip addresses in the mapping {}", mapping);
}
//Get the DPN on which this interface resides
- BigInteger dpnId = NatUtil.getDpnForInterface(interfaceManager, interfaceName);
+ if (dpnId == null) {
+ dpnId = NatUtil.getDpnForInterface(interfaceManager, interfaceName);
+ }
if (dpnId.equals(BigInteger.ZERO)) {
LOG.warn("createNATFlowEntries : No DPN for interface {}. NAT flow entries for ip mapping {} will "
--- /dev/null
+/*
+ * 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 java.util.List;
+import java.util.Objects;
+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.ReadFailedException;
+import org.opendaylight.netvirt.elanmanager.api.IElanService;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.ArpRequestReceived;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.ArpResponseReceived;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.MacChanged;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntries;
+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.neutron.vip.states.VipState;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Singleton
+public class NatArpNotificationHandler implements OdlArputilListener {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NatArpNotificationHandler.class);
+
+ private final DataBroker dataBroker;
+ private final IElanService elanService;
+ private final NatSouthboundEventHandlers southboundEventHandlers;
+ private final VipStateTracker vipStateTracker;
+
+ @Inject
+ public NatArpNotificationHandler(final DataBroker dataBroker,
+ final IElanService elanService,
+ final NatSouthboundEventHandlers southboundEventHandlers,
+ final VipStateTracker vipStateTracker) {
+ this.dataBroker = dataBroker;
+ this.elanService = elanService;
+ this.southboundEventHandlers = southboundEventHandlers;
+ this.vipStateTracker = vipStateTracker;
+ }
+
+ @Override
+ public void onArpResponseReceived(ArpResponseReceived notification) {
+
+ }
+
+ @Override
+ public void onMacChanged(MacChanged notification) {
+
+ }
+
+ @Override
+ public void onArpRequestReceived(ArpRequestReceived notification) {
+
+ LOG.debug("NatArpNotificationHandler received {}", notification);
+
+ IpAddress srcIp = notification.getSrcIpaddress();
+ if (srcIp == null || !Objects.equals(srcIp, notification.getDstIpaddress())) {
+ LOG.debug("NatArpNotificationHandler: ignoring ARP packet, not gratuitous {}", notification);
+ return;
+ }
+
+ //Since the point of all this is to learn VIPs those are by definition
+ //not the IP addresses assigned to a port by neutron configuration.
+ ElanInterface arpSenderIfc = elanService.getElanInterfaceByElanInterfaceName(notification.getInterface());
+ if (ipBelongsToElanInterface(arpSenderIfc, srcIp)) {
+ LOG.debug("NatArpNotificationHandler: ignoring GARP packet. No need to NAT a port's static IP. {}",
+ notification);
+ return;
+ }
+
+ ElanInterface targetIfc = null;
+ for (String ifcName : elanService.getElanInterfaces(arpSenderIfc.getElanInstanceName())) {
+ ElanInterface elanInterface = elanService.getElanInterfaceByElanInterfaceName(ifcName);
+ if (ipBelongsToElanInterface(elanInterface, srcIp)) {
+ targetIfc = elanInterface;
+ break;
+ }
+ }
+
+ if (null == targetIfc) {
+ LOG.warn("NatArpNotificationHandler: GARP does not correspond to an interface in this elan {}",
+ notification);
+ return;
+ }
+
+ RouterInterface routerInterface = NatUtil.getConfiguredRouterInterface(dataBroker, targetIfc.getName());
+ if (null == routerInterface) {
+ LOG.warn("NatArpNotificationHandler: Could not retrieve router ifc for {}", targetIfc);
+ return;
+ }
+
+ VipState newVipState = this.vipStateTracker.buildVipState(srcIp.getIpv4Address().getValue(),
+ notification.getSrcMac().getValue(), notification.getDpnId(), targetIfc.getName());
+ VipState cachedState = null;
+ try {
+ cachedState = this.vipStateTracker.get(newVipState.getIp()).orNull();
+ } catch (ReadFailedException e) {
+ LOG.warn("NatArpNotificationHandler failed to read vip state {}", notification, e);
+ }
+
+ if (null == cachedState) {
+ this.southboundEventHandlers.handleAdd(
+ targetIfc.getName(), notification.getDpnId(), routerInterface, newVipState);
+ } else if (!cachedState.getDpnId().equals(newVipState.getDpnId())) {
+ this.southboundEventHandlers.handleRemove(cachedState.getIfcName(),
+ cachedState.getDpnId(), routerInterface);
+ this.southboundEventHandlers.handleAdd(
+ targetIfc.getName(), notification.getDpnId(), routerInterface, newVipState);
+ }
+
+ }
+
+ private boolean ipBelongsToElanInterface(ElanInterface elanInterface, IpAddress ip) {
+ if (elanInterface == null) {
+ return false;
+ }
+
+ List<StaticMacEntries> staticMacEntries = elanInterface.getStaticMacEntries();
+ if (null == staticMacEntries) {
+ return false;
+ }
+
+ for (StaticMacEntries staticMacEntry : staticMacEntries) {
+ if (Objects.equals(staticMacEntry.getIpPrefix(), ip)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
/*
- * 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,
*/
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;
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;
extends AsyncDataTreeChangeListenerBase<Interface, NatInterfaceStateChangeListener> {
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<Interface.OperStatus, Interface.OperStatus, IntfTransitionState> 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
// 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);
}
}
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);
}
}
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<Operational> 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<Operational> 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<List<ListenableFuture<Void>>> {
- 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<ListenableFuture<Void>> call() {
- List<ListenableFuture<Void>> 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<List<ListenableFuture<Void>>> {
- 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<ListenableFuture<Void>> call() {
- List<ListenableFuture<Void>> 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<List<ListenableFuture<Void>>> {
- 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<ListenableFuture<Void>> call() {
- List<ListenableFuture<Void>> 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<ListenableFuture<Void>> futures) {
- LOG.trace("processInterfaceAdded : Processing Interface Add Event for interface {}", portName);
- List<InternalToExternalPortMap> intExtPortMapList = getIntExtPortMapListForPortName(portName, routerId);
- if (intExtPortMapList == null || intExtPortMapList.isEmpty()) {
- LOG.debug("processInterfaceAdded : Ip Mapping list is empty/null for portname {}", portName);
- return;
- }
- InstanceIdentifier<RouterPorts> portIid = NatUtil.buildRouterPortsIdentifier(routerId);
- ListenableFuture<Void> 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<InternalToExternalPortMap> getIntExtPortMapListForPortName(String portName, String routerId) {
- InstanceIdentifier<Ports> portToIpMapIdentifier = NatUtil.buildPortToIpMapIdentifier(routerId, portName);
- Optional<Ports> 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<RouterToNaptSwitch> rtrNaptSw = InstanceIdentifier.builder(NaptSwitches.class)
- .child(RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();
- Optional<RouterToNaptSwitch> 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<String> getFixedIpsForPort(String interfname) {
- LOG.debug("getFixedIpsForPort : getFixedIpsForPort method is called for interface {}", interfname);
- try {
- Future<RpcResult<GetFixedIPsForNeutronPortOutput>> result =
- neutronVpnService.getFixedIPsForNeutronPort(new GetFixedIPsForNeutronPortInputBuilder()
- .setPortId(new Uuid(interfname)).build());
-
- RpcResult<GetFixedIPsForNeutronPortOutput> 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<ListenableFuture<Void>> futures) {
- LOG.trace("processInterfaceRemoved : Processing Interface Removed Event for interface {} on DPN ID {}",
- portName, dpnId);
- List<InternalToExternalPortMap> intExtPortMapList = getIntExtPortMapListForPortName(portName, routerId);
- if (intExtPortMapList == null || intExtPortMapList.isEmpty()) {
- LOG.debug("processInterfaceRemoved : Ip Mapping list is empty/null for portName {}", portName);
- return;
- }
- InstanceIdentifier<RouterPorts> portIid = NatUtil.buildRouterPortsIdentifier(routerId);
- ListenableFuture<Void> 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<String> 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<List<ListenableFuture<Void>>> {
- private String interfaceName;
- private String routerName;
-
- NatFlowAddWorker(String interfaceName,String routerName) {
- this.interfaceName = interfaceName;
- this.routerName = routerName;
- }
-
- @Override
- @SuppressWarnings("checkstyle:IllegalCatch")
- public List<ListenableFuture<Void>> call() {
- final List<ListenableFuture<Void>> 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<List<ListenableFuture<Void>>> {
- 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<ListenableFuture<Void>> call() {
- final List<ListenableFuture<Void>> 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<List<ListenableFuture<Void>>> {
- 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<ListenableFuture<Void>> call() {
- final List<ListenableFuture<Void>> 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;
- }
- }
}
--- /dev/null
+/*
+ * 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<Interface.OperStatus, Interface.OperStatus, IntfTransitionState> 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<Operational> 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<Operational> 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<List<ListenableFuture<Void>>> {
+ 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<ListenableFuture<Void>> call() {
+ List<ListenableFuture<Void>> 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<List<ListenableFuture<Void>>> {
+ 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<ListenableFuture<Void>> call() {
+ List<ListenableFuture<Void>> 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<List<ListenableFuture<Void>>> {
+ 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<ListenableFuture<Void>> call() {
+ List<ListenableFuture<Void>> 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<InternalToExternalPortMap> intExtPortMapList = getIntExtPortMapListForPortName(portName, routerId);
+ if (intExtPortMapList == null || intExtPortMapList.isEmpty()) {
+ LOG.debug("processInterfaceAdded : Ip Mapping list is empty/null for portname {}", portName);
+ return;
+ }
+ InstanceIdentifier<RouterPorts> portIid = NatUtil.buildRouterPortsIdentifier(routerId);
+ FluentFuture<Void> 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<InternalToExternalPortMap> getIntExtPortMapListForPortName(String portName, String routerId) {
+ InstanceIdentifier<Ports> portToIpMapIdentifier = NatUtil.buildPortToIpMapIdentifier(routerId, portName);
+ Optional<Ports> 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<RouterToNaptSwitch> rtrNaptSw = InstanceIdentifier.builder(NaptSwitches.class)
+ .child(RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();
+ Optional<RouterToNaptSwitch> 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<String> getFixedIpsForPort(String interfname) {
+ LOG.debug("getFixedIpsForPort : getFixedIpsForPort method is called for interface {}", interfname);
+ try {
+ Future<RpcResult<GetFixedIPsForNeutronPortOutput>> result =
+ neutronVpnService.getFixedIPsForNeutronPort(new GetFixedIPsForNeutronPortInputBuilder()
+ .setPortId(new Uuid(interfname)).build());
+
+ RpcResult<GetFixedIPsForNeutronPortOutput> 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<ListenableFuture<Void>> futures) {
+ LOG.trace("processInterfaceRemoved : Processing Interface Removed Event for interface {} on DPN ID {}",
+ portName, dpnId);
+ List<InternalToExternalPortMap> intExtPortMapList = getIntExtPortMapListForPortName(portName, routerId);
+ if (intExtPortMapList == null || intExtPortMapList.isEmpty()) {
+ LOG.debug("processInterfaceRemoved : Ip Mapping list is empty/null for portName {}", portName);
+ return;
+ }
+ InstanceIdentifier<RouterPorts> portIid = NatUtil.buildRouterPortsIdentifier(routerId);
+ ListenableFuture<Void> 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<String> 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<List<ListenableFuture<Void>>> {
+ 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<ListenableFuture<Void>> call() {
+ final List<ListenableFuture<Void>> 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<List<ListenableFuture<Void>>> {
+ 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<ListenableFuture<Void>> call() {
+ final List<ListenableFuture<Void>> 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<List<ListenableFuture<Void>>> {
+ 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<ListenableFuture<Void>> call() {
+ final List<ListenableFuture<Void>> 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;
+ }
+ }
+}
--- /dev/null
+/*
+ * 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<String, VipState> {
+
+ 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<Void> writeVipState(VipState vipState) {
+ return txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, tx -> {
+ tx.put(InstanceIdentifier.builder(NeutronVipStates.class)
+ .child(VipState.class, vipState.key()).build(),
+ vipState, true);
+ });
+ }
+}
interface="org.opendaylight.genius.datastoreutils.listeners.DataTreeEventCallbackRegistrar"/>
<reference id="metricProvider"
interface="org.opendaylight.infrautils.metrics.MetricProvider" />
+ <reference id="cacheProvider"
+ interface="org.opendaylight.infrautils.caches.CacheProvider"/>
<odl:rpc-service id="idManagerService"
interface="org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService" />
<service ref="natRpcServiceImpl"
interface="org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rpc.rev170209.OdlNatRpcService"/>
+ <service ref="natArpNotificationHandler" odl:type="default"
+ interface="org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilListener" />
+ <odl:notification-listener ref="natArpNotificationHandler" />
</blueprint>
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;
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;
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();
protected void processIpLearning(String srcInterface, IpAddress srcIP, MacAddress srcMac, BigInteger metadata,
IpAddress dstIP, Uuid srcIpSubnetId) {
- if (metadata != null && !Objects.equals(metadata, BigInteger.ZERO)) {
- Optional<List<String>> 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<List<String>> 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);
}
}
}
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;
@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
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;
@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