Use documenting constants for put()
[netvirt.git] / vpnservice / elanmanager / elanmanager-impl / src / main / java / org / opendaylight / netvirt / elan / internal / ElanPacketInHandler.java
index d80186e0002bf917b19f2a14c71effe0ff852e85..7f9a3a238ad803b807332d0f21112e08c90e5c9a 100755 (executable)
@@ -8,15 +8,9 @@
 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;
@@ -25,14 +19,14 @@ import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 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;
@@ -57,12 +51,15 @@ public class ElanPacketInHandler implements PacketProcessingListener {
     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
@@ -82,113 +79,59 @@ public class ElanPacketInHandler implements PacketProcessingListener {
                 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);
@@ -196,6 +139,78 @@ public class ElanPacketInHandler implements PacketProcessingListener {
         }
     }
 
+    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
@@ -212,14 +227,15 @@ public class ElanPacketInHandler implements PacketProcessingListener {
         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()));
     }
 
 }