*/
package org.opendaylight.netvirt.elan.internal;
-import com.google.common.base.Optional;
+import static org.opendaylight.mdsal.binding.util.Datastore.CONFIGURATION;
+import static org.opendaylight.mdsal.binding.util.Datastore.OPERATIONAL;
+
+import com.google.common.util.concurrent.ListenableFuture;
import java.math.BigInteger;
+import java.util.ArrayList;
import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
import javax.inject.Inject;
import javax.inject.Singleton;
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
import org.opendaylight.genius.mdsalutil.MetaDataUtil;
import org.opendaylight.genius.mdsalutil.NwConstants;
import org.opendaylight.genius.mdsalutil.packet.Ethernet;
import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
+import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunner;
+import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunnerImpl;
import org.opendaylight.netvirt.elan.cache.ElanInstanceCache;
import org.opendaylight.netvirt.elan.evpn.utils.EvpnUtils;
import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayUtils;
import org.opendaylight.netvirt.elan.utils.ElanUtils;
-import org.opendaylight.openflowplugin.libraries.liblldp.NetUtils;
import org.opendaylight.openflowplugin.libraries.liblldp.PacketException;
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.yang.types.rev130715.PhysAddress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingListener;
import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.Uint32;
+import org.opendaylight.yangtools.yang.common.Uint64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger LOG = LoggerFactory.getLogger(ElanPacketInHandler.class);
- private final DataBroker broker;
+ private final ManagedNewTransactionRunner txRunner;
private final IInterfaceManager interfaceManager;
private final ElanUtils elanUtils;
private final ElanL2GatewayUtils elanL2GatewayUtils;
private final EvpnUtils evpnUtils;
private final JobCoordinator jobCoordinator;
private final ElanInstanceCache elanInstanceCache;
+ private final ElanManagerCounters elanManagerCounters;
@Inject
public ElanPacketInHandler(DataBroker dataBroker, final IInterfaceManager interfaceManager, ElanUtils elanUtils,
EvpnUtils evpnUtils, ElanL2GatewayUtils elanL2GatewayUtils, JobCoordinator jobCoordinator,
- ElanInstanceCache elanInstanceCache) {
- broker = dataBroker;
+ ElanInstanceCache elanInstanceCache, ElanManagerCounters elanManagerCounters) {
+ this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
this.interfaceManager = interfaceManager;
this.elanUtils = elanUtils;
this.elanL2GatewayUtils = elanL2GatewayUtils;
this.evpnUtils = evpnUtils;
this.jobCoordinator = jobCoordinator;
this.elanInstanceCache = elanInstanceCache;
+ this.elanManagerCounters = elanManagerCounters;
}
@Override
public void onPacketReceived(PacketReceived notification) {
Class<? extends PacketInReason> pktInReason = notification.getPacketInReason();
- short tableId = notification.getTableId().getValue();
+ short tableId = notification.getTableId().getValue().toJava();
if (pktInReason == NoMatch.class && tableId == NwConstants.ELAN_SMAC_TABLE) {
- ElanManagerCounters.unknown_smac_pktin_rcv.inc();
+ elanManagerCounters.unknownSmacPktinRcv();
try {
byte[] data = notification.getPayload();
Ethernet res = new Ethernet();
- res.deserialize(data, 0, data.length * NetUtils.NUM_BITS_IN_A_BYTE);
+ res.deserialize(data, 0, data.length * Byte.SIZE);
byte[] srcMac = res.getSourceMACAddress();
final String macAddress = NWUtil.toStringMacAddress(srcMac);
- final BigInteger metadata = notification.getMatch().getMetadata().getMetadata();
- final long elanTag = MetaDataUtil.getElanTagFromMetadata(metadata);
+ final Uint64 metadata = notification.getMatch().getMetadata().getMetadata();
+ final Uint32 elanTag = Uint32.valueOf(MetaDataUtil.getElanTagFromMetadata(metadata));
- long portTag = MetaDataUtil.getLportFromMetadata(metadata).intValue();
+ Uint32 portTag = Uint32.valueOf(MetaDataUtil.getLportFromMetadata(metadata).longValue());
Optional<IfIndexInterface> interfaceInfoOp = elanUtils.getInterfaceInfoByInterfaceTag(portTag);
if (!interfaceInfoOp.isPresent()) {
}
String elanName = elanTagName.getName();
PhysAddress physAddress = new PhysAddress(macAddress);
- MacEntry oldMacEntry = elanUtils.getMacEntryForElanInstance(elanName, physAddress).orNull();
+ MacEntry oldMacEntry = elanUtils.getMacEntryForElanInstance(elanName, physAddress).orElse(null);
boolean isVlanOrFlatProviderIface = interfaceManager.isExternalInterface(interfaceName);
Optional<IpAddress> srcIpAddress = elanUtils.getSourceIpAddress(res);
BigInteger timeStamp = new BigInteger(String.valueOf(System.currentTimeMillis()));
if (!srcIpAddress.isPresent()) {
newMacEntry = new MacEntryBuilder().setInterface(interfaceName).setMacAddress(physAddress)
- .setKey(new MacEntryKey(physAddress))
+ .withKey(new MacEntryKey(physAddress))
.setControllerLearnedForwardingEntryTimestamp(timeStamp)
.setIsStaticAddress(false).build();
} else {
newMacEntry = new MacEntryBuilder().setInterface(interfaceName).setMacAddress(physAddress)
- .setIpPrefix(srcIpAddress.get()).setKey(new MacEntryKey(physAddress))
+ .setIpPrefix(srcIpAddress.get()).withKey(new MacEntryKey(physAddress))
.setControllerLearnedForwardingEntryTimestamp(timeStamp)
.setIsStaticAddress(false).build();
}
if (srcIpAddress.isPresent()) {
String prefix = srcIpAddress.get().getIpv4Address().getValue();
InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
- ElanInstance elanInstance = elanInstanceCache.get(elanName).orNull();
+ ElanInstance elanInstance = elanInstanceCache.get(elanName).orElse(null);
evpnUtils.advertisePrefix(elanInstance, macAddress, prefix, interfaceName, interfaceInfo.getDpId());
}
enqueueJobForMacSpecificTasks(macAddress, elanTag, interfaceName, elanName, physAddress, oldMacEntry,
newMacEntry, isVlanOrFlatProviderIface);
- ElanInstance elanInstance = elanInstanceCache.get(elanName).orNull();
+ ElanInstance elanInstance = elanInstanceCache.get(elanName).orElse(null);
InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
if (interfaceInfo == null) {
LOG.trace("Interface:{} is not present under Config DS", interfaceName);
}
}
- private void enqueueJobForMacSpecificTasks(final String macAddress, final long elanTag, String interfaceName,
+ private void enqueueJobForMacSpecificTasks(final String macAddress, final Uint32 elanTag, String interfaceName,
String elanName, PhysAddress physAddress,
MacEntry oldMacEntry, MacEntry newMacEntry,
final boolean isVlanOrFlatProviderIface) {
- jobCoordinator.enqueueJob(ElanUtils.getElanMacKey(elanTag, macAddress), () -> {
- WriteTransaction writeTx = broker.newWriteOnlyTransaction();
- if (oldMacEntry != null && oldMacEntry.getInterface().equals(interfaceName)) {
- // This should never occur because of ovs temporary mac learning
- ElanManagerCounters.unknown_smac_pktin_forwarding_entries_removed.inc();
- } else if (oldMacEntry != null && !isVlanOrFlatProviderIface) {
- long macTimeStamp = oldMacEntry.getControllerLearnedForwardingEntryTimestamp().longValue();
- if (System.currentTimeMillis() > macTimeStamp + 1000) {
- InstanceIdentifier<MacEntry> macEntryId = ElanUtils
- .getInterfaceMacEntriesIdentifierOperationalDataPath(interfaceName,
- physAddress);
- writeTx.delete(LogicalDatastoreType.OPERATIONAL, macEntryId);
- } else {
- // New FEs flood their packets on all interfaces. This
- // can lead
- // to many contradicting packet_ins. Ignore all packets
- // received
- // within 1s after the first packet_in
- ElanManagerCounters.unknown_smac_pktin_mac_migration_ignored_due_to_protection.inc();
+ jobCoordinator.enqueueJob(getElanMacKey(elanTag, macAddress),
+ () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, tx -> {
+ if (oldMacEntry != null && Objects.equals(oldMacEntry.getInterface(), interfaceName)) {
+ // This should never occur because of ovs temporary mac learning
+ elanManagerCounters.unknownSmacPktinForwardingEntriesRemoved();
+ } else if (oldMacEntry != null && !isVlanOrFlatProviderIface) {
+ long macTimeStamp = oldMacEntry.getControllerLearnedForwardingEntryTimestamp().longValue();
+ if (System.currentTimeMillis() > macTimeStamp + 1000) {
+ InstanceIdentifier<MacEntry> macEntryId = ElanUtils
+ .getInterfaceMacEntriesIdentifierOperationalDataPath(oldMacEntry.getInterface(),
+ physAddress);
+ tx.delete(macEntryId);
+ } else {
+ // New FEs flood their packets on all interfaces. This can lead
+ // to many contradicting packet_ins. Ignore all packets received
+ // within 1s after the first packet_in
+ elanManagerCounters.unknownSmacPktinMacMigrationIgnoredDueToProtection();
+ }
+ } else if (oldMacEntry != null) {
+ elanManagerCounters.unknownSmacPktinRemovedForRelearned();
}
- } else if (oldMacEntry != null) {
- ElanManagerCounters.unknown_smac_pktin_removed_for_relearned.inc();
- }
- // This check is required only to update elan-forwarding-tables when mac is learned
- // in ports (example: VM interfaces) other than on vlan provider port.
- if (!isVlanOrFlatProviderIface && oldMacEntry == null) {
- InstanceIdentifier<MacEntry> elanMacEntryId =
- ElanUtils.getMacEntryOperationalDataPath(elanName, physAddress);
- writeTx.put(LogicalDatastoreType.OPERATIONAL, elanMacEntryId, newMacEntry,
- WriteTransaction.CREATE_MISSING_PARENTS);
- }
- return Collections.singletonList(writeTx.submit());
- });
+ // This check is required only to update elan-forwarding-tables when mac is learned
+ // in ports (example: VM interfaces) other than on vlan provider port.
+ if (!isVlanOrFlatProviderIface && oldMacEntry == null) {
+ InstanceIdentifier<MacEntry> elanMacEntryId =
+ ElanUtils.getMacEntryOperationalDataPath(elanName, physAddress);
+ tx.mergeParentStructurePut(elanMacEntryId, newMacEntry);
+ }
+ })));
+ }
+
+ private static String getElanMacKey(Uint32 elanTag, String macAddress) {
+ return "MAC-" + macAddress + " ELAN_TAG-" + elanTag.toString();
+ }
+
+ private static String getElanMacDPNKey(Uint32 elanTag, String macAddress, Uint64 dpnId) {
+ return "MAC-" + macAddress + " ELAN_TAG-" + elanTag.toString() + "DPN_ID-" + dpnId.toString();
}
- private void enqueueJobForDPNSpecificTasks(final String macAddress, final long elanTag, String interfaceName,
+ private void enqueueJobForDPNSpecificTasks(final String macAddress, final Uint32 elanTag, String interfaceName,
PhysAddress physAddress, ElanInstance elanInstance,
InterfaceInfo interfaceInfo, MacEntry oldMacEntry,
MacEntry newMacEntry, boolean isVlanOrFlatProviderIface) {
- jobCoordinator.enqueueJob(ElanUtils.getElanMacDPNKey(elanTag, macAddress, interfaceInfo.getDpId()), () -> {
+ jobCoordinator.enqueueJob(getElanMacDPNKey(elanTag, macAddress, interfaceInfo.getDpId()), () -> {
macMigrationFlowsCleanup(interfaceName, elanInstance, oldMacEntry, isVlanOrFlatProviderIface);
- BigInteger dpId = interfaceManager.getDpnForInterface(interfaceName);
+ Uint64 dpId = interfaceManager.getDpnForInterface(interfaceName);
elanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), dpId,
Collections.singletonList(physAddress));
- ElanManagerCounters.unknown_smac_pktin_learned.inc();
- WriteTransaction flowWritetx = broker.newWriteOnlyTransaction();
- elanUtils.setupMacFlows(elanInstance, interfaceInfo, elanInstance.getMacTimeout(),
- macAddress, !isVlanOrFlatProviderIface, flowWritetx);
- InstanceIdentifier<MacEntry> macEntryId =
- ElanUtils.getInterfaceMacEntriesIdentifierOperationalDataPath(interfaceName, physAddress);
- flowWritetx.put(LogicalDatastoreType.OPERATIONAL, macEntryId, newMacEntry,
- WriteTransaction.CREATE_MISSING_PARENTS);
- return Collections.singletonList(flowWritetx.submit());
+ elanManagerCounters.unknownSmacPktinLearned();
+ List<ListenableFuture<?>> futures = new ArrayList<>();
+ futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
+ futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, operTx -> {
+ elanUtils.setupMacFlows(elanInstance, interfaceInfo, elanInstance.getMacTimeout().toJava(),
+ macAddress, !isVlanOrFlatProviderIface, tx);
+ InstanceIdentifier<MacEntry> macEntryId =
+ ElanUtils.getInterfaceMacEntriesIdentifierOperationalDataPath(interfaceName, physAddress);
+ operTx.mergeParentStructurePut(macEntryId, newMacEntry);
+ }));
+ }));
+ return futures;
});
}
private void macMigrationFlowsCleanup(String interfaceName, ElanInstance elanInstance, MacEntry macEntry,
boolean isVlanOrFlatProviderIface) {
- if (macEntry != null && !macEntry.getInterface().equals(interfaceName)
+ if (macEntry != null && !Objects.equals(macEntry.getInterface(), interfaceName)
&& !isVlanOrFlatProviderIface) {
tryAndRemoveInvalidMacEntry(elanInstance.getElanInstanceName(), macEntry);
- ElanManagerCounters.unknown_smac_pktin_flows_removed_for_relearned.inc();
+ elanManagerCounters.unknownSmacPktinFlowsRemovedForRelearned();
}
}
* Static MAC having been added on a wrong ELAN.
*/
private void tryAndRemoveInvalidMacEntry(String elanName, MacEntry macEntry) {
- ElanInstance elanInfo = elanInstanceCache.get(elanName).orNull();
+ ElanInstance elanInfo = elanInstanceCache.get(elanName).orElse(null);
if (elanInfo == null) {
LOG.warn("MAC {} is been added (either statically or dynamically) for an invalid Elan {}. "
+ "Manual cleanup may be necessary", macEntry.getMacAddress(), elanName);
macEntry.getMacAddress(), macEntry.getInterface());
return;
}
- WriteTransaction flowDeletetx = broker.newWriteOnlyTransaction();
- elanUtils.deleteMacFlows(elanInfo, oldInterfaceLport, macEntry, flowDeletetx);
- flowDeletetx.submit();
+ LoggingFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
+ tx -> elanUtils.deleteMacFlows(elanInfo, oldInterfaceLport, macEntry, tx)), LOG,
+ "Error deleting invalid MAC entry");
elanL2GatewayUtils.removeMacsFromElanExternalDevices(elanInfo,
Collections.singletonList(macEntry.getMacAddress()));
}