Make a link depends on packet-in LLDP packet.

The ONOS does not process the incoming LLDP packet from switches.
The ONOS only process LLDP packets if LLDP packet has "ONOS Discovery" optional TLV.

So, this changes process incoming LLDP packet from switch and make a link information and onos can utilize it.

Also, this patch changes the requested appId of DefaultForwardingObjective generated by PacketManager.
So, AppId in result of flows cli will be printed to actual requested appId.

ONOS-7748

Change-Id: I2611b34655bec2369b8817ce0cd29fb2edbed845
diff --git a/utils/misc/src/main/java/org/onlab/packet/LLDP.java b/utils/misc/src/main/java/org/onlab/packet/LLDP.java
index 33b1f85..e555f1f 100644
--- a/utils/misc/src/main/java/org/onlab/packet/LLDP.java
+++ b/utils/misc/src/main/java/org/onlab/packet/LLDP.java
@@ -37,8 +37,16 @@
 
     public static final byte PORT_TLV_TYPE = 2;
     public static final short PORT_TLV_SIZE = 5;
+
+    /**
+     * @deprecated since 1.15. Use the PORT_TLV_COMPONENT_SUBTYPE instead of PORT_TLV_SUBTYPE.
+     */
+    @Deprecated
     public static final byte PORT_TLV_SUBTYPE = 2;
 
+    public static final byte PORT_TLV_COMPONENT_SUBTYPE = PORT_TLV_SUBTYPE;
+    public static final byte PORT_TLV_INTERFACE_NAME_SUBTYPE = 5;
+
     public static final byte TTL_TLV_TYPE = 3;
     public static final short TTL_TLV_SIZE = 2;
 
diff --git a/utils/misc/src/main/java/org/onlab/packet/ONOSLLDP.java b/utils/misc/src/main/java/org/onlab/packet/ONOSLLDP.java
index f0b981c..7405bbf 100644
--- a/utils/misc/src/main/java/org/onlab/packet/ONOSLLDP.java
+++ b/utils/misc/src/main/java/org/onlab/packet/ONOSLLDP.java
@@ -18,6 +18,7 @@
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import org.apache.commons.lang.ArrayUtils;
+import org.slf4j.Logger;
 
 import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
@@ -31,16 +32,18 @@
 
 import static org.onlab.packet.LLDPOrganizationalTLV.OUI_LENGTH;
 import static org.onlab.packet.LLDPOrganizationalTLV.SUBTYPE_LENGTH;
+import static org.slf4j.LoggerFactory.getLogger;
 
 /**
  *  ONOS LLDP containing organizational TLV for ONOS device discovery.
  */
 public class ONOSLLDP extends LLDP {
 
+    private static final Logger log = getLogger(ONOSLLDP.class);
+
     public static final String DEFAULT_DEVICE = "INVALID";
     public static final String DEFAULT_NAME = "ONOS Discovery";
 
-
     protected static final byte NAME_SUBTYPE = 1;
     protected static final byte DEVICE_SUBTYPE = 2;
     protected static final byte DOMAIN_SUBTYPE = 3;
@@ -62,11 +65,7 @@
     private static final byte CHASSIS_TLV_SIZE = 7;
     private static final byte CHASSIS_TLV_SUBTYPE = 4;
 
-    private static final byte PORT_TLV_TYPE = 2;
-    private static final byte PORT_TLV_SUBTYPE = 2;
-
     private static final byte TTL_TLV_TYPE = 3;
-
     private static final byte PORT_DESC_TLV_TYPE = 4;
 
     private final byte[] ttlValue = new byte[] {0, 0x78};
@@ -137,7 +136,7 @@
     }
 
     public void setPortId(final int portNumber) {
-        byte[] port = ArrayUtils.addAll(new byte[] {PORT_TLV_SUBTYPE},
+        byte[] port = ArrayUtils.addAll(new byte[] {PORT_TLV_COMPONENT_SUBTYPE},
                 String.valueOf(portNumber).getBytes(StandardCharsets.UTF_8));
 
         LLDPTLV portTLV = new LLDPTLV();
@@ -147,6 +146,17 @@
         this.setPortId(portTLV);
     }
 
+    public void setPortName(final String portName) {
+        byte[] port = ArrayUtils.addAll(new byte[] {PORT_TLV_INTERFACE_NAME_SUBTYPE},
+                portName.getBytes(StandardCharsets.UTF_8));
+
+        LLDPTLV portTLV = new LLDPTLV();
+        portTLV.setLength((short) port.length);
+        portTLV.setType(PORT_TLV_TYPE);
+        portTLV.setValue(port);
+        this.setPortId(portTLV);
+    }
+
     public void setTimestamp(long timestamp) {
         LLDPOrganizationalTLV tmtlv = opttlvs.get(TIMESTAMP_SUBTYPE);
         if (tmtlv == null) {
@@ -235,6 +245,17 @@
         return null;
     }
 
+    public LLDPTLV getPortDescTLV() {
+        for (LLDPTLV tlv : this.getOptionalTLVList()) {
+            if (tlv.getType() == PORT_DESC_TLV_TYPE) {
+                return tlv;
+            }
+        }
+
+        log.error("Cannot find the port description tlv type.");
+        return null;
+    }
+
     public String getNameString() {
         LLDPOrganizationalTLV tlv = getNameTLV();
         if (tlv != null) {
@@ -259,12 +280,57 @@
         return null;
     }
 
+    public String getPortDescString() {
+        LLDPTLV tlv = getPortDescTLV();
+        if (tlv != null) {
+            return new String(tlv.getValue(), StandardCharsets.UTF_8);
+        }
+        return null;
+    }
+
     public Integer getPort() {
         ByteBuffer portBB = ByteBuffer.wrap(this.getPortId().getValue());
-        portBB.position(1);
+        byte type = portBB.get();
 
-        return Integer.parseInt(new String(portBB.array(),
-                portBB.position(), portBB.remaining(), StandardCharsets.UTF_8));
+        if (type == PORT_TLV_COMPONENT_SUBTYPE) {
+            return Integer.parseInt(new String(portBB.array(),
+                    portBB.position(), portBB.remaining(), StandardCharsets.UTF_8));
+        } else {
+            return -1;
+        }
+    }
+
+    public String getPortNameString() {
+        ByteBuffer portBB = ByteBuffer.wrap(this.getPortId().getValue());
+        byte type = portBB.get();
+
+        if (type == PORT_TLV_INTERFACE_NAME_SUBTYPE) {
+            return new String(portBB.array(), portBB.position(), portBB.remaining(), StandardCharsets.UTF_8);
+        } else {
+            log.error("Cannot find the port name tlv type.");
+            return null;
+        }
+    }
+
+    public MacAddress getChassisIdByMac() {
+        ByteBuffer portBB = ByteBuffer.wrap(this.getChassisId().getValue());
+        byte type = portBB.get();
+
+        if (type == CHASSIS_TLV_SUBTYPE) {
+            byte[] bytes = new byte[portBB.remaining()];
+
+            System.arraycopy(portBB.array(), portBB.position(), bytes, 0, MacAddress.MAC_ADDRESS_LENGTH);
+
+            return new MacAddress(bytes);
+        } else {
+            return MacAddress.NONE;
+        }
+    }
+
+    public short getTtlBySeconds() {
+        ByteBuffer portBB = ByteBuffer.wrap(this.getTtl().getValue());
+
+        return portBB.getShort();
     }
 
     public long getTimestamp() {
@@ -303,6 +369,22 @@
     }
 
     /**
+     * Given an ethernet packet, returns the device the LLDP came from.
+     * @param eth an ethernet packet
+     * @return a the lldp packet or null
+     */
+    public static ONOSLLDP parseLLDP(Ethernet eth) {
+        if (eth.getEtherType() == Ethernet.TYPE_LLDP ||
+                eth.getEtherType() == Ethernet.TYPE_BSN) {
+
+            return new ONOSLLDP((LLDP) eth.getPayload());
+        }
+
+        log.error("Packet is not the LLDP or BSN.");
+        return null;
+    }
+
+    /**
      * Creates a link probe for link discovery/verification.
      * @deprecated since 1.15. Insecure, do not use.
      *
diff --git a/utils/misc/src/test/java/org/onlab/packet/ONOSLLDPTest.java b/utils/misc/src/test/java/org/onlab/packet/ONOSLLDPTest.java
index b2494b5..2405998 100644
--- a/utils/misc/src/test/java/org/onlab/packet/ONOSLLDPTest.java
+++ b/utils/misc/src/test/java/org/onlab/packet/ONOSLLDPTest.java
@@ -30,6 +30,7 @@
     private static final Integer PORT_NUMBER = 2;
     private static final Integer PORT_NUMBER_2 = 98761234;
     private static final String PORT_DESC = "Ethernet1";
+    private static final String PORT_NAME = "Ethernet2";
     private static final String TEST_SECRET = "test";
 
     private ONOSLLDP onoslldp = ONOSLLDP.onosSecureLLDP(DEVICE_ID, CHASSIS_ID, PORT_NUMBER, PORT_DESC, TEST_SECRET);
@@ -39,11 +40,21 @@
      */
     @Test
     public void testPortNumber() throws Exception {
-        assertEquals("the value from constructor with getPort value is miss matched",
+        assertEquals("the value from constructor with getPort value is mismatched",
                 PORT_NUMBER, onoslldp.getPort());
 
         onoslldp.setPortId(PORT_NUMBER_2);
-        assertEquals("the value from setPortId with getPort value is miss matched",
+        assertEquals("the value from setPortId with getPort value is mismatched",
                 PORT_NUMBER_2, onoslldp.getPort());
     }
+
+    /**
+     * Tests port name and getters.
+     */
+    @Test
+    public void testPortName() throws Exception {
+        onoslldp.setPortName(PORT_NAME);
+        assertEquals("the value from setPortName with getPortNameString value is mismatched",
+                PORT_NAME, onoslldp.getPortNameString());
+    }
 }
\ No newline at end of file