package org.opendaylight.netvirt.elan.internal;
import com.google.common.base.Optional;
-import com.google.common.util.concurrent.ListenableFuture;
import java.math.BigInteger;
-import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.Callable;
-
import org.opendaylight.controller.liblldp.NetUtils;
import org.opendaylight.controller.liblldp.PacketException;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
-import org.opendaylight.genius.mdsalutil.MDSALUtil;
import org.opendaylight.genius.mdsalutil.MetaDataUtil;
import org.opendaylight.genius.mdsalutil.NWUtil;
import org.opendaylight.genius.mdsalutil.NwConstants;
import org.opendaylight.genius.mdsalutil.packet.Ethernet;
-//import org.opendaylight.netvirt.elan.ElanException;
+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.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.genius.interfacemanager.meta.rev160406._if.indexes._interface.map.IfIndexInterface;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
private final IInterfaceManager interfaceManager;
private final ElanUtils elanUtils;
private final ElanL2GatewayUtils elanL2GatewayUtils;
+ private final EvpnUtils evpnUtils;
- public ElanPacketInHandler(DataBroker dataBroker, final IInterfaceManager interfaceManager, ElanUtils elanUtils) {
+ public ElanPacketInHandler(DataBroker dataBroker, final IInterfaceManager interfaceManager, ElanUtils elanUtils,
+ EvpnUtils evpnUtils) {
broker = dataBroker;
this.interfaceManager = interfaceManager;
this.elanUtils = elanUtils;
this.elanL2GatewayUtils = elanUtils.getElanL2GatewayUtils();
+ this.evpnUtils = evpnUtils;
}
@Override
final BigInteger metadata = notification.getMatch().getMetadata().getMetadata();
final long elanTag = MetaDataUtil.getElanTagFromMetadata(metadata);
+ long portTag = MetaDataUtil.getLportFromMetadata(metadata).intValue();
+
+ Optional<IfIndexInterface> interfaceInfoOp = elanUtils.getInterfaceInfoByInterfaceTag(portTag);
+ if (!interfaceInfoOp.isPresent()) {
+ LOG.warn("There is no interface for given portTag {}", portTag);
+ return;
+ }
+ String interfaceName = interfaceInfoOp.get().getInterfaceName();
+ LOG.debug("Received a packet with srcMac: {} ElanTag: {} PortTag: {} InterfaceName: {}", macAddress,
+ elanTag, portTag, interfaceName);
+ ElanTagName elanTagName = elanUtils.getElanInfoByElanTag(elanTag);
+ if (elanTagName == null) {
+ LOG.warn("not able to find elanTagName in elan-tag-name-map for elan tag {}", elanTag);
+ return;
+ }
+ String elanName = elanTagName.getName();
+ PhysAddress physAddress = new PhysAddress(macAddress);
+ MacEntry oldMacEntry = elanUtils.getMacEntryForElanInstance(elanName, physAddress).orNull();
+ boolean isVlanOrFlatProviderIface = interfaceManager.isExternalInterface(interfaceName);
+
+ Optional<IpAddress> srcIpAddress = elanUtils.getSourceIpAddress(res);
+ MacEntry newMacEntry = null;
+ BigInteger timeStamp = new BigInteger(String.valueOf(System.currentTimeMillis()));
+ if (!srcIpAddress.isPresent()) {
+ newMacEntry = new MacEntryBuilder().setInterface(interfaceName).setMacAddress(physAddress)
+ .setKey(new MacEntryKey(physAddress))
+ .setControllerLearnedForwardingEntryTimestamp(timeStamp)
+ .setIsStaticAddress(false).build();
+ } else {
+ newMacEntry = new MacEntryBuilder().setInterface(interfaceName).setMacAddress(physAddress)
+ .setIpPrefix(srcIpAddress.get()).setKey(new MacEntryKey(physAddress))
+ .setControllerLearnedForwardingEntryTimestamp(timeStamp)
+ .setIsStaticAddress(false).build();
+ }
+ if (srcIpAddress.isPresent()) {
+ String prefix = srcIpAddress.get().getIpv4Address().getValue();
+ InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
+ ElanInstance elanInstance = elanUtils.getElanInstanceByName(broker, elanName);
+ evpnUtils.advertisePrefix(elanInstance, macAddress, prefix, interfaceName, interfaceInfo.getDpId());
+ }
final DataStoreJobCoordinator portDataStoreCoordinator = DataStoreJobCoordinator.getInstance();
- portDataStoreCoordinator.enqueueJob(ElanUtils.getElanMacKey(elanTag, macAddress),
- new Callable<List<ListenableFuture<Void>>>() {
- @Override
- public List<ListenableFuture<Void>> call() throws Exception {
-
- long portTag = MetaDataUtil.getLportFromMetadata(metadata).intValue();
-
- Optional<IfIndexInterface> interfaceInfoOp =
- elanUtils.getInterfaceInfoByInterfaceTag(portTag);
- if (!interfaceInfoOp.isPresent()) {
- LOG.warn("There is no interface for given portTag {}", portTag);
- return Collections.emptyList();
- }
- String interfaceName = interfaceInfoOp.get().getInterfaceName();
- LOG.debug("Received a packet with srcMac: {} ElanTag: {} PortTag: {} InterfaceName: {}",
- macAddress, elanTag, portTag, interfaceName);
- ElanTagName elanTagName = elanUtils.getElanInfoByElanTag(elanTag);
- if (elanTagName == null) {
- LOG.warn("not able to find elanTagName in elan-tag-name-map for elan tag {}", elanTag);
- return Collections.emptyList();
- }
- String elanName = elanTagName.getName();
- PhysAddress physAddress = new PhysAddress(macAddress);
- MacEntry macEntry = elanUtils.getInterfaceMacEntriesOperationalDataPath(interfaceName,
- physAddress);
- if (macEntry != null && macEntry.getInterface().equals(interfaceName)) {
- BigInteger macTimeStamp = macEntry.getControllerLearnedForwardingEntryTimestamp();
- if (System.currentTimeMillis() > macTimeStamp.longValue() + 10000) {
- /*
- * Protection time expired. Even though the MAC has been
- * learnt (it is in the cache) the packets are punted to
- * controller. Which means, the the flows were not
- * successfully created in the DPN, but the MAC entry
- * has been added successfully in the cache.
- *
- * So, the cache has to be cleared and the flows and
- * cache should be recreated (clearing of cache is
- * required so that the timestamp is updated).
- */
- InstanceIdentifier<MacEntry> macEntryId = ElanUtils
- .getInterfaceMacEntriesIdentifierOperationalDataPath(interfaceName,
- physAddress);
- ElanUtils.delete(broker, LogicalDatastoreType.OPERATIONAL, macEntryId);
- ElanManagerCounters.unknown_smac_pktin_removed_for_retry.inc();
- } else {
- // Protection time running. Ignore packets for 2 seconds
- ElanManagerCounters.unknown_smac_pktin_ignored_due_protection.inc();
- return Collections.emptyList();
- }
- } else if (macEntry != null) {
- // MAC address has moved. Overwrite the mapping and replace
- // MAC flows
- long macTimeStamp = macEntry.getControllerLearnedForwardingEntryTimestamp().longValue();
- if (System.currentTimeMillis() > macTimeStamp + 10000) {
-
- InstanceIdentifier<MacEntry> macEntryId = ElanUtils
- .getInterfaceMacEntriesIdentifierOperationalDataPath(interfaceName,
- physAddress);
- ElanUtils.delete(broker, LogicalDatastoreType.OPERATIONAL, macEntryId);
- tryAndRemoveInvalidMacEntry(elanName, macEntry);
- ElanManagerCounters.unknown_smac_pktin_removed_for_relearned.inc();
- } 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();
- return Collections.emptyList();
- }
- }
- BigInteger timeStamp = new BigInteger(String.valueOf(System.currentTimeMillis()));
- macEntry = new MacEntryBuilder().setInterface(interfaceName).setMacAddress(physAddress)
- .setKey(new MacEntryKey(physAddress))
- .setControllerLearnedForwardingEntryTimestamp(timeStamp)
- .setIsStaticAddress(false).build();
- InstanceIdentifier<MacEntry> macEntryId = ElanUtils
- .getInterfaceMacEntriesIdentifierOperationalDataPath(interfaceName, physAddress);
- MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, macEntryId,
- macEntry);
- InstanceIdentifier<MacEntry> elanMacEntryId =
- ElanUtils.getMacEntryOperationalDataPath(elanName, physAddress);
- MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, elanMacEntryId,
- macEntry);
- ElanInstance elanInstance = ElanUtils.getElanInstanceByName(broker, elanName);
- WriteTransaction flowWritetx = broker.newWriteOnlyTransaction();
-
- boolean isVlanOrFlatProviderIface =
- ElanUtils.isVlan(elanInstance)
- && interfaceName.endsWith(":" + elanInstance.getSegmentationId())
- || ElanUtils.isFlat(elanInstance) && interfaceName.endsWith(":flat");
-
- elanUtils.setupMacFlows(elanInstance, interfaceManager.getInterfaceInfo(interfaceName),
- elanInstance.getMacTimeout(), macAddress,
- !isVlanOrFlatProviderIface, flowWritetx);
- List<ListenableFuture<Void>> futures = new ArrayList<>();
- futures.add(flowWritetx.submit());
- BigInteger dpId = interfaceManager.getDpnForInterface(interfaceName);
- elanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), dpId,
- Arrays.asList(physAddress));
-
- ElanManagerCounters.unknown_smac_pktin_learned.inc();
- return futures;
- }
- });
+ enqueueJobForMacSpecificTasks(macAddress, elanTag, interfaceName, elanName, physAddress, oldMacEntry,
+ newMacEntry, isVlanOrFlatProviderIface, portDataStoreCoordinator);
+
+ ElanInstance elanInstance = ElanUtils.getElanInstanceByName(broker, elanName);
+ InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
+ if (interfaceInfo == null) {
+ LOG.trace("Interface:{} is not present under Config DS", interfaceName);
+ return;
+ }
+ enqueueJobForDPNSpecificTasks(macAddress, elanTag, interfaceName, physAddress, elanInstance,
+ interfaceInfo, oldMacEntry, newMacEntry, isVlanOrFlatProviderIface, portDataStoreCoordinator);
+
} catch (PacketException e) {
LOG.error("Failed to decode packet: {}", notification, e);
}
}
+ private void enqueueJobForMacSpecificTasks(final String macAddress, final long elanTag, String interfaceName,
+ String elanName, PhysAddress physAddress,
+ MacEntry oldMacEntry, MacEntry newMacEntry,
+ final boolean isVlanOrFlatProviderIface,
+ final DataStoreJobCoordinator portDataStoreCoordinator) {
+ portDataStoreCoordinator.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();
+ }
+ } 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());
+ });
+ }
+
+ private void enqueueJobForDPNSpecificTasks(final String macAddress, final long elanTag, String interfaceName,
+ PhysAddress physAddress, ElanInstance elanInstance,
+ InterfaceInfo interfaceInfo, MacEntry oldMacEntry,
+ MacEntry newMacEntry, boolean isVlanOrFlatProviderIface,
+ final DataStoreJobCoordinator portDataStoreCoordinator) {
+ portDataStoreCoordinator
+ .enqueueJob(ElanUtils.getElanMacDPNKey(elanTag, macAddress, interfaceInfo.getDpId()), () -> {
+ macMigrationFlowsCleanup(interfaceName, elanInstance, oldMacEntry, isVlanOrFlatProviderIface);
+ BigInteger 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());
+ });
+ }
+
+ private void macMigrationFlowsCleanup(String interfaceName, ElanInstance elanInstance, MacEntry macEntry,
+ boolean isVlanOrFlatProviderIface) {
+ if (macEntry != null && !macEntry.getInterface().equals(interfaceName)
+ && !isVlanOrFlatProviderIface) {
+ tryAndRemoveInvalidMacEntry(elanInstance.getElanInstanceName(), macEntry);
+ ElanManagerCounters.unknown_smac_pktin_flows_removed_for_relearned.inc();
+ }
+ }
+
/*
* Though this method is a little costlier because it uses try-catch
* construct, it is used only in rare scenarios like MAC movement or invalid
InterfaceInfo oldInterfaceLport = interfaceManager.getInterfaceInfo(macEntry.getInterface());
if (oldInterfaceLport == null) {
LOG.warn("MAC {} is been added (either statically or dynamically) on an invalid Logical Port {}. "
- + "Manual cleanup may be necessary",
- macEntry.getMacAddress(), macEntry.getInterface());
+ + "Manual cleanup may be necessary",
+ macEntry.getMacAddress(), macEntry.getInterface());
return;
}
WriteTransaction flowDeletetx = broker.newWriteOnlyTransaction();
elanUtils.deleteMacFlows(elanInfo, oldInterfaceLport, macEntry, flowDeletetx);
flowDeletetx.submit();
- elanL2GatewayUtils.removeMacsFromElanExternalDevices(elanInfo, Arrays.asList(macEntry.getMacAddress()));
+ elanL2GatewayUtils.removeMacsFromElanExternalDevices(elanInfo,
+ Collections.singletonList(macEntry.getMacAddress()));
}
}