Fix spotbugs logging complaints
[openflowplugin.git] / applications / topology-lldp-discovery / src / main / java / org / opendaylight / openflowplugin / applications / topology / lldp / utils / LLDPDiscoveryUtils.java
index da14b4e71d0afde604e69a7ec31daf5e0685f2c7..5681e18ceaf6acce49301403d8638f98457ce8c6 100644 (file)
@@ -7,54 +7,65 @@
  */
 package org.opendaylight.openflowplugin.applications.topology.lldp.utils;
 
-import org.apache.commons.lang3.ArrayUtils;
-import java.nio.charset.Charset;
+import com.google.common.base.Preconditions;
 import com.google.common.hash.HashCode;
-import org.opendaylight.controller.liblldp.Ethernet;
-import org.opendaylight.controller.liblldp.LLDP;
-import org.opendaylight.controller.liblldp.BitBufferHelper;
-import org.opendaylight.controller.liblldp.LLDPTLV;
-import org.opendaylight.controller.liblldp.NetUtils;
+import com.google.common.hash.HashFunction;
 import com.google.common.hash.Hasher;
 import com.google.common.hash.Hashing;
-import com.google.common.hash.HashFunction;
+import java.lang.management.ManagementFactory;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Optional;
+import org.apache.commons.lang3.ArrayUtils;
+import org.opendaylight.mdsal.eos.binding.api.Entity;
+import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipService;
+import org.opendaylight.mdsal.eos.common.api.EntityOwnershipState;
+import org.opendaylight.openflowplugin.applications.topology.lldp.LLDPActivator;
+import org.opendaylight.openflowplugin.libraries.liblldp.Ethernet;
+import org.opendaylight.openflowplugin.libraries.liblldp.LLDP;
+import org.opendaylight.openflowplugin.libraries.liblldp.LLDPTLV;
+import org.opendaylight.openflowplugin.libraries.liblldp.NetUtils;
+import org.opendaylight.openflowplugin.libraries.liblldp.PacketException;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
-import java.util.Arrays;
-import java.security.NoSuchAlgorithmException;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
-import java.lang.management.ManagementFactory;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.controller.liblldp.CustomTLVKey;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-
-public class LLDPDiscoveryUtils {
+public final class LLDPDiscoveryUtils {
     private static final Logger LOG = LoggerFactory.getLogger(LLDPDiscoveryUtils.class);
 
-    // Send LLDP every five seconds
-    public static final Long LLDP_INTERVAL = (long) (1000*5);
+    private static final short MINIMUM_LLDP_SIZE = 61;
+    public static final short ETHERNET_TYPE_VLAN = (short) 0x8100;
+    public static final short ETHERNET_TYPE_LLDP = (short) 0x88cc;
+    private static final short ETHERNET_TYPE_OFFSET = 12;
+    private static final short ETHERNET_VLAN_OFFSET = ETHERNET_TYPE_OFFSET + 4;
+    private static final String SERVICE_ENTITY_TYPE = "org.opendaylight.mdsal.ServiceEntityType";
 
-    // Let up to three intervals pass before we decide we are expired.
-    public static final Long LLDP_EXPIRATION_TIME = LLDP_INTERVAL*3;
+    private LLDPDiscoveryUtils() {
+    }
 
     public static String macToString(byte[] mac) {
-        StringBuilder b = new StringBuilder();
+        StringBuilder builder = new StringBuilder();
         for (int i = 0; i < mac.length; i++) {
-            b.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? ":" : ""));
+            builder.append(String.format("%02X%s", mac[i], i < mac.length - 1 ? ":" : ""));
         }
 
-        return b.toString();
+        return builder.toString();
     }
 
     /**
-     * @param payload
+     * Returns the encoded in custom TLV for the given lldp.
+     *
+     * @param payload lldp payload
      * @return nodeConnectorId - encoded in custom TLV of given lldp
      * @see LLDPDiscoveryUtils#lldpToNodeConnectorRef(byte[], boolean)
      */
@@ -63,21 +74,25 @@ public class LLDPDiscoveryUtils {
     }
 
     /**
-     * @param payload
+     * Returns the encoded in custom TLV for the given lldp.
+     *
+     * @param payload lldp payload
      * @param useExtraAuthenticatorCheck make it more secure (CVE-2015-1611 CVE-2015-1612)
      * @return nodeConnectorId - encoded in custom TLV of given lldp
      */
+    @SuppressWarnings("checkstyle:IllegalCatch")
     public static NodeConnectorRef lldpToNodeConnectorRef(byte[] payload, boolean useExtraAuthenticatorCheck)  {
-        Ethernet ethPkt = new Ethernet();
-        try {
-            ethPkt.deserialize(payload, 0,payload.length * NetUtils.NumBitsInAByte);
-        } catch (Exception e) {
-            LOG.warn("Failed to decode LLDP packet {}", e);
-        }
-
         NodeConnectorRef nodeConnectorRef = null;
 
-        if (ethPkt.getPayload() instanceof LLDP) {
+        if (isLLDP(payload)) {
+            Ethernet ethPkt = new Ethernet();
+            try {
+                ethPkt.deserialize(payload, 0, payload.length * NetUtils.NUM_BITS_IN_A_BYTE);
+            } catch (PacketException e) {
+                LOG.warn("Failed to decode LLDP packet", e);
+                return nodeConnectorRef;
+            }
+
             LLDP lldp = (LLDP) ethPkt.getPayload();
 
             try {
@@ -86,14 +101,13 @@ public class LLDPDiscoveryUtils {
 
                 final LLDPTLV systemIdTLV = lldp.getSystemNameId();
                 if (systemIdTLV != null) {
-                    String srcNodeIdString = new String(systemIdTLV.getValue(),Charset.defaultCharset());
+                    String srcNodeIdString = new String(systemIdTLV.getValue(), Charset.defaultCharset());
                     srcNodeId = new NodeId(srcNodeIdString);
                 } else {
                     throw new Exception("Node id wasn't specified via systemNameId in LLDP packet.");
                 }
 
-                final LLDPTLV nodeConnectorIdLldptlv = lldp.getCustomTLV(
-                        new CustomTLVKey(BitBufferHelper.getInt(LLDPTLV.OFOUI), LLDPTLV.CUSTOM_TLV_SUB_TYPE_NODE_CONNECTOR_ID[0]));
+                final LLDPTLV nodeConnectorIdLldptlv = lldp.getCustomTLV(LLDPTLV.createPortSubTypeCustomTLVKey());
                 if (nodeConnectorIdLldptlv != null) {
                     srcNodeConnectorId = new NodeConnectorId(LLDPTLV.getCustomString(
                             nodeConnectorIdLldptlv.getValue(), nodeConnectorIdLldptlv.getLength()));
@@ -103,46 +117,49 @@ public class LLDPDiscoveryUtils {
 
                 if (useExtraAuthenticatorCheck) {
                     boolean secure = checkExtraAuthenticator(lldp, srcNodeConnectorId);
-                    if (! secure) {
+                    if (!secure) {
                         LOG.warn("SECURITY ALERT: there is probably a LLDP spoofing attack in progress.");
-                        throw new Exception("Attack. LLDP packet with inconsistent extra authenticator field was received.");
+                        throw new Exception(
+                                "Attack. LLDP packet with inconsistent extra authenticator field was received.");
                     }
                 }
 
                 InstanceIdentifier<NodeConnector> srcInstanceId = InstanceIdentifier.builder(Nodes.class)
-                        .child(Node.class,new NodeKey(srcNodeId))
+                        .child(Node.class, new NodeKey(srcNodeId))
                         .child(NodeConnector.class, new NodeConnectorKey(srcNodeConnectorId))
-                        .toInstance();
+                        .build();
                 nodeConnectorRef = new NodeConnectorRef(srcInstanceId);
             } catch (Exception e) {
-                LOG.debug("Caught exception while parsing out lldp optional and custom fields: {}", e.getMessage(), e);
+                LOG.debug("Caught exception while parsing out lldp optional and custom fields", e);
             }
         }
         return nodeConnectorRef;
     }
 
     /**
-     * @param nodeConnectorId
+     * Gets an extra authenticator for lldp security.
+     *
+     * @param nodeConnectorId the NodeConnectorId
      * @return extra authenticator for lldp security
-     * @throws NoSuchAlgorithmException
      */
-    public static byte[] getValueForLLDPPacketIntegrityEnsuring(final NodeConnectorId nodeConnectorId) throws NoSuchAlgorithmException {
-        final String pureValue = nodeConnectorId+ManagementFactory.getRuntimeMXBean().getName();
-        final byte[] pureBytes = pureValue.getBytes();
+    public static byte[] getValueForLLDPPacketIntegrityEnsuring(final NodeConnectorId nodeConnectorId) {
+        String finalKey;
+        if (LLDPActivator.getLldpSecureKey() != null && !LLDPActivator.getLldpSecureKey().isEmpty()) {
+            finalKey = LLDPActivator.getLldpSecureKey();
+        } else {
+            finalKey = ManagementFactory.getRuntimeMXBean().getName();
+        }
+        final String pureValue = nodeConnectorId + finalKey;
+
+        final byte[] pureBytes = pureValue.getBytes(StandardCharsets.UTF_8);
         HashFunction hashFunction = Hashing.md5();
         Hasher hasher = hashFunction.newHasher();
         HashCode hashedValue = hasher.putBytes(pureBytes).hash();
         return hashedValue.asBytes();
     }
 
-    /**
-     * @param lldp
-     * @param srcNodeConnectorId
-     * @throws NoSuchAlgorithmException
-     */
-    private static boolean checkExtraAuthenticator(LLDP lldp, NodeConnectorId srcNodeConnectorId) throws NoSuchAlgorithmException {
-        final LLDPTLV hashLldptlv = lldp.getCustomTLV(
-                new CustomTLVKey(BitBufferHelper.getInt(LLDPTLV.OFOUI), LLDPTLV.CUSTOM_TLV_SUB_TYPE_CUSTOM_SEC[0]));
+    private static boolean checkExtraAuthenticator(LLDP lldp, NodeConnectorId srcNodeConnectorId) {
+        final LLDPTLV hashLldptlv = lldp.getCustomTLV(LLDPTLV.createSecSubTypeCustomTLVKey());
         boolean secAuthenticatorOk = false;
         if (hashLldptlv != null) {
             byte[] rawTlvValue = hashLldptlv.getValue();
@@ -155,4 +172,48 @@ public class LLDPDiscoveryUtils {
 
         return secAuthenticatorOk;
     }
+
+    private static boolean isLLDP(final byte[] packet) {
+        if (packet == null || packet.length < MINIMUM_LLDP_SIZE) {
+            return false;
+        }
+
+        final ByteBuffer bb = ByteBuffer.wrap(packet);
+
+        short ethernetType = bb.getShort(ETHERNET_TYPE_OFFSET);
+
+        if (ethernetType == ETHERNET_TYPE_VLAN) {
+            ethernetType = bb.getShort(ETHERNET_VLAN_OFFSET);
+        }
+
+        return ethernetType == ETHERNET_TYPE_LLDP;
+    }
+
+    public static boolean isEntityOwned(final EntityOwnershipService eos, final String nodeId) {
+        Preconditions.checkNotNull(eos, "Entity ownership service must not be null");
+
+        EntityOwnershipState state = null;
+        Optional<EntityOwnershipState> status = getCurrentOwnershipStatus(eos, nodeId);
+        if (status.isPresent()) {
+            state = status.get();
+        } else {
+            LOG.error("Fetching ownership status failed for node {}", nodeId);
+        }
+        return state != null && state.equals(EntityOwnershipState.IS_OWNER);
+    }
+
+    private static Optional<EntityOwnershipState> getCurrentOwnershipStatus(final EntityOwnershipService eos,
+            final String nodeId) {
+        Entity entity = createNodeEntity(nodeId);
+        Optional<EntityOwnershipState> ownershipStatus = eos.getOwnershipState(entity);
+
+        if (ownershipStatus.isPresent()) {
+            LOG.debug("Fetched ownership status for node {} is {}", nodeId, ownershipStatus.get());
+        }
+        return ownershipStatus;
+    }
+
+    private static Entity createNodeEntity(final String nodeId) {
+        return new Entity(SERVICE_ENTITY_TYPE, nodeId);
+    }
 }