auto-attach: Support latest version of auto-attach LLDP TLVs
authorDennis Flynn <drflynn@avaya.com>
Wed, 18 Mar 2015 18:47:14 +0000 (14:47 -0400)
committerBen Pfaff <blp@nicira.com>
Mon, 23 Mar 2015 20:28:53 +0000 (13:28 -0700)
The following enhancements to the auto-attach feature are provided

- Support recent modifications to the AA element discovery TLV
- Support recent Avaya Organizationally Unique ID (OUI) change.
  (This will change to IEEE assigned OUI once AA standard has been ratified)
- Remove some Avaya specific #defines

The primary purpose of this commit is to catch up with the latest changes made
to the auto attach TLVs as the Auto Attach feature progresses through the
802.1Q IEEE standards committee. Most notably this includes some minor rework
of the AA element discovery TLV and a recent change to the Avaya OUI value.

Signed-off-by: Dennis Flynn <drflynn@avaya.com>
Signed-off-by: Ben Pfaff <blp@nicira.com>
lib/lldp/aa-structs.h
lib/lldp/lldp-tlv.h
lib/lldp/lldp.c
lib/ovs-lldp.c
tests/test-aa.c

index 567a831..983c74c 100644 (file)
 struct lldp_aa_element_system_id {
     uint8_t  system_mac[6];
     uint16_t conn_type;
-    uint16_t smlt_id;
-    uint8_t  mlt_id[2];
+    uint16_t rsvd;
+    uint8_t  rsvd2[2];
 };
 
 struct lldpd_aa_element_tlv {
     uint16_t                         type;
+    uint16_t                         vlan_tagging;
+    uint16_t                         auto_prov_mode;
     uint16_t                         mgmt_vlan;
     struct lldp_aa_element_system_id system_id;
 };
index 237414d..2b94828 100644 (file)
@@ -36,7 +36,7 @@
 #define LLDP_TLV_ORG_DOT1       {0x00, 0x80, 0xc2}
 #define LLDP_TLV_ORG_DOT3       {0x00, 0x12, 0x0f}
 #define LLDP_TLV_ORG_MED        {0x00, 0x12, 0xbb}
-#define LLDP_TLV_ORG_AVAYA      {0x00, 0x40, 0x0D}
+#define LLDP_TLV_ORG_AVAYA      {0x00, 0x04, 0x0D}
 #define LLDP_TLV_ORG_DCBX       {0x00, 0x1b, 0x21}
 
 #define LLDP_TLV_DOT1_PVID      1
 #define LLDP_TLV_MED_IV_MODEL   10
 #define LLDP_TLV_MED_IV_ASSET   11
 
-#define LLDP_TLV_AA_ELEMENT_SUBTYPE           0x08
-#define LLDP_TLV_AA_ISID_VLAN_ASGNS_SUBTYPE   0x09
+#define LLDP_TLV_AA_ELEMENT_SUBTYPE           0x0b
+#define LLDP_TLV_AA_ISID_VLAN_ASGNS_SUBTYPE   0x0c
 #define LLDP_TLV_AA_ISID_VLAN_DIGEST_LENGTH   32
-#define LLDP_TLV_AA_ELEM_TYPE_UNKNOWN         1
-#define LLDP_TLV_AA_ELEM_TYPE_SERVER          2
-#define LLDP_TLV_AA_ELEM_TYPE_PROXY           3
-#define LLDP_TLV_AA_ELEM_TYPE_UNTAG_CLIENT    4
-#define LLDP_TLV_AA_ELEM_TYPE_TAG_CLIENT      5
-#define LLDP_TLV_AA_ELEM_TYPE_SERV_NO_AUTH    6
-#define LLDP_TLV_AA_ELEM_TYPE_PROXY_NO_AUTH   7
+
+#define LLDP_TLV_AA_ELEM_TYPE_UNKNOWN                            1
+#define LLDP_TLV_AA_ELEM_TYPE_SERVER                             2
+#define LLDP_TLV_AA_ELEM_TYPE_PROXY                              3
+#define LLDP_TLV_AA_ELEM_TYPE_SERV_NO_AUTH                       4
+#define LLDP_TLV_AA_ELEM_TYPE_PROXY_NO_AUTH                      5
+#define LLDP_TLV_AA_ELEM_TYPE_CLIENT_WIRELESS_ACCESS_POINT_TYPE1 6
+#define LLDP_TLV_AA_ELEM_TYPE_CLIENT_WIRELESS_ACCESS_POINT_TYPE2 7
+#define LLDP_TLV_AA_ELEM_TYPE_CLIENT_SWITCH                      8
+#define LLDP_TLV_AA_ELEM_TYPE_CLIENT_ROUTER                      9
+#define LLDP_TLV_AA_ELEM_TYPE_CLIENT_IP_PHONE                    10
+#define LLDP_TLV_AA_ELEM_TYPE_CLIENT_IP_CAMERA                   11
+#define LLDP_TLV_AA_ELEM_TYPE_CLIENT_IP_VIDEO                    12
+#define LLDP_TLV_AA_ELEM_TYPE_CLIENT_SECURITY_DEVICE             13
+#define LLDP_TLV_AA_ELEM_TYPE_CLIENT_VIRTUAL_SWITCH              14
+#define LLDP_TLV_AA_ELEM_TYPE_CLIENT_SERVER_ENDPOINT             15
+
 #define LLDP_TLV_AA_ELEM_CONN_TYPE_SINGLE     0
 #define LLDP_TLV_AA_ELEM_CONN_TYPE_MLT        1
 #define LLDP_TLV_AA_ELEM_CONN_TYPE_SLT        2
index d77bcd0..493c2ff 100644 (file)
@@ -235,53 +235,69 @@ lldp_send(struct lldpd *global OVS_UNUSED,
         lldp_tlv_end(p, start);
     }
 
-    /* Add Auto Attach tlvs to packet */
+    /* Add Auto Attach tlvs V3.1 to packet. LLDP FA element v3.1 format:
+    TLV Type[127]   TLV Length[50 octets] Avaya OUI[00-04-0D] Subtype[11]
+    7 bits                9 bits                3 octets      1 octet
+    HMAC-SHA Digest  Element Type   State   Mgmt VLAN   Rsvd    System ID
+      32 octets       6 bits        6 bits   12 bits    1 octet 10 octets
+    */
     /* AA-ELEMENT */
     if (port->p_element.type != 0) {
-        u_int8_t aa_element_first_byte;
-        u_int8_t aa_element_second_byte = 0;
+        u_int16_t aa_element_first_word = 0;
+        u_int16_t aa_element_second_word = 0;
+        u_int16_t aa_element_state = 0;
         u_int8_t aa_elem_sys_id_first_byte;
         u_int8_t aa_elem_sys_id_second_byte;
 
-        /* Element type should be first 4 most significant bits, so bitwise OR
-         * that with the first 4 bits of the 12-bit-wide mgmt_vlan
-         */
-        aa_element_first_byte = (((port->p_element.type & 0xF) << 4) |
-                                 ((port->p_element.mgmt_vlan >> 8) & 0xF));
-
-        /* Second byte should just be the remaining 8 bits of .mgmt_vlan */
-        aa_element_second_byte = port->p_element.mgmt_vlan & 0x0FF;
-
-        /* .conn_type should be 4 most sig. bits, so bitwise OR that
-         * with the first 4 bits of the 12-bit-wide .smlt_id
-         */
+        /* Link VLAN Tagging Requirements (bit 1),
+         * Automatic Provisioning Mode (bit 2/3) (left to right, 1 based) */
+        aa_element_state = ((port->p_element.vlan_tagging & 0x1) << 5) |
+            ((port->p_element.auto_prov_mode & 0x3) << 3);
+
+        /* Element first word should be first 6 most significant bits of
+         * element type, bitwise OR that with the next 6 bits of the state,
+         * bitwise OR with the first 4 bits of mgmt vlan id.
+         * Element type should be LLDP_TLV_AA_ELEM_TYPE_VIRTUAL_SWITCH for
+         * AA client */
+        aa_element_first_word = (port->p_element.type << 10) |
+            (aa_element_state << 4) |
+            ((port->p_element.mgmt_vlan & 0x0F00)>> 8);
+
+        /* Element second type should be the first 8 most significant bits
+         * of the remaining 8 bits of mgmt vlan id. */
+        aa_element_second_word = (port->p_element.mgmt_vlan & 0xFF) << 8;
+
+        /* System id first byte should be first 3 most significant bits of
+         * connecion type, bitwise OR that with the device state and bitwise
+         * OR that with the first 2 most significant bitsof rsvd (10 bits). */
         aa_elem_sys_id_first_byte =
-            ((port->p_element.system_id.conn_type & 0xF) << 4) |
-            ((port->p_element.system_id.smlt_id >> 8) & 0xF);
+            ((port->p_element.system_id.conn_type & 0x7) << 5) |
+            ((port->p_element.system_id.rsvd >> 8) & 0x3);
 
-        /* Second byte should just be the remaining 8 bits of .smlt_id */
-        aa_elem_sys_id_second_byte = port->p_element.system_id.smlt_id & 0x0FF;
+        /* Second byte should just be the remaining 8 bits of 10 bits rsvd */
+        aa_elem_sys_id_second_byte =
+            (port->p_element.system_id.rsvd & 0xFF);
+
+        memset(msg_auth_digest, 0, sizeof msg_auth_digest);
 
         lldp_tlv_start(p, LLDP_TLV_ORG, &start);
         dp_packet_put(p, avaya, sizeof avaya);
         lldp_tlv_put_u8(p, LLDP_TLV_AA_ELEMENT_SUBTYPE);
-        lldp_tlv_put_u8(p, aa_element_first_byte);
-        lldp_tlv_put_u8(p, aa_element_second_byte);
+        dp_packet_put(p, msg_auth_digest, sizeof msg_auth_digest);
+        lldp_tlv_put_u16(p, aa_element_first_word);
+        lldp_tlv_put_u16(p, aa_element_second_word);
         dp_packet_put(p, &port->p_element.system_id.system_mac,
                       sizeof port->p_element.system_id.system_mac);
         lldp_tlv_put_u8(p, aa_elem_sys_id_first_byte);
         lldp_tlv_put_u8(p, aa_elem_sys_id_second_byte);
-        dp_packet_put(p, &port->p_element.system_id.mlt_id,
-                      sizeof port->p_element.system_id.mlt_id);
+        dp_packet_put(p, &port->p_element.system_id.rsvd2,
+                      sizeof port->p_element.system_id.rsvd2);
         lldp_tlv_end(p, start);
     }
 
     if (!list_is_empty(&port->p_isid_vlan_maps)) {
-        int j;
 
-        for (j = 0; j < LLDP_TLV_AA_ISID_VLAN_DIGEST_LENGTH; j++) {
-            msg_auth_digest[j] = 0;
-        }
+        memset(msg_auth_digest, 0, sizeof msg_auth_digest);
 
         lldp_tlv_start(p, LLDP_TLV_ORG, &start);
         dp_packet_put(p, avaya, sizeof avaya);
@@ -314,6 +330,7 @@ lldp_send(struct lldpd *global OVS_UNUSED,
     if (!hardware->h_lport.p_lastframe
         || hardware->h_lport.p_lastframe->size != lldp_len
         || memcmp(hardware->h_lport.p_lastframe->frame, lldp, lldp_len)) {
+
         struct lldpd_frame *frame = xmalloc(sizeof *frame + lldp_len);
         frame->size = lldp_len;
         memcpy(frame->frame, lldp, lldp_len);
@@ -327,8 +344,8 @@ lldp_send(struct lldpd *global OVS_UNUSED,
 
 int
 lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s,
-    struct lldpd_hardware *hardware, struct lldpd_chassis **newchassis,
-    struct lldpd_port **newport)
+            struct lldpd_hardware *hardware, struct lldpd_chassis **newchassis,
+            struct lldpd_port **newport)
 {
     struct lldpd_chassis *chassis;
     struct lldpd_port *port;
@@ -372,6 +389,7 @@ lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s,
                   "received on %s", hardware->h_ifname);
         goto malformed;
     }
+
     PEEK_DISCARD(ETH_ADDR_LEN); /* Skip source address */
     if (PEEK_UINT16 != ETHERTYPE_LLDP) {
         VLOG_INFO("non LLDP frame received on %s", hardware->h_ifname);
@@ -498,34 +516,57 @@ lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s,
                 /* LLDP-MED */
                 hardware->h_rx_unrecognized_cnt++;
             } else if (memcmp(avaya_oid, orgid, sizeof orgid) == 0) {
-                u_int16_t aa_element_word;
-                u_int16_t aa_status_vlan_word;
+                u_int32_t aa_element_dword;
                 u_int16_t aa_system_id_word;
+                u_int16_t aa_status_vlan_word;
+                u_int8_t aa_element_state;
                 unsigned short num_mappings;
 
                 switch(tlv_subtype) {
                 case LLDP_TLV_AA_ELEMENT_SUBTYPE:
-                    aa_element_word = PEEK_UINT16;
+                    PEEK_BYTES(&msg_auth_digest, sizeof msg_auth_digest);
+
+                    aa_element_dword = PEEK_UINT32;
+
+                    /* Type is first 6 most-significant bits of
+                     * aa_element_dword */
+                    port->p_element.type = aa_element_dword >> 26;
 
-                    /* Type is first 4 most-significant bits */
-                    port->p_element.type = aa_element_word >> 12;
+                    /* State is 6 most significant bits of aa_element_dword */
+                    aa_element_state = (aa_element_dword >> 20) & 0x3F;
 
-                    /* mgmt_vlan is last 12 bits */
-                    port->p_element.mgmt_vlan = aa_element_word & 0x0FFF;
-                    VLOG_INFO("Element type: %X, Mgmt vlan: %X",
+                    /* vlan tagging requirement is the bit 1(left to right)
+                     * of the 6 bits state (1 based) */
+                    port->p_element.vlan_tagging =
+                        (aa_element_state >> 5) & 0x1;
+
+                    /* Automatic provision mode is the bit 2/3(left to right)
+                     * of the 6 bits state (1 based) */
+                    port->p_element.auto_prov_mode =
+                        (aa_element_state >> 3) & 0x3;
+
+                    /* mgmt_vlan is the 12 bits of aa_element_dword from
+                     * bit 12 */
+                    port->p_element.mgmt_vlan =
+                        (aa_element_dword >> 8) & 0xFFF;
+                    VLOG_INFO("Element type: %X, vlan tagging %X, "
+                              "auto prov mode %x, Mgmt vlan: %X",
                               port->p_element.type,
+                              port->p_element.vlan_tagging,
+                              port->p_element.auto_prov_mode,
                               port->p_element.mgmt_vlan);
+
                     PEEK_BYTES(&port->p_element.system_id.system_mac,
                                sizeof port->p_element.system_id.system_mac);
                     VLOG_INFO("System mac: "ETH_ADDR_FMT,
-                              ETH_ADDR_ARGS(port->p_element.system_id.system_mac));
+                        ETH_ADDR_ARGS(port->p_element.system_id.system_mac));
                     aa_system_id_word = PEEK_UINT16;
                     port->p_element.system_id.conn_type =
-                        aa_system_id_word >> 12;
-                    port->p_element.system_id.smlt_id =
-                        aa_system_id_word & 0x0FFF;
-                    PEEK_BYTES(&port->p_element.system_id.mlt_id,
-                               sizeof port->p_element.system_id.mlt_id);
+                        aa_system_id_word >> 13;
+                    port->p_element.system_id.rsvd = aa_system_id_word &
+                        0x03FF;
+                    PEEK_BYTES(&port->p_element.system_id.rsvd2,
+                               sizeof port->p_element.system_id.rsvd2);
                     break;
 
                 case LLDP_TLV_AA_ISID_VLAN_ASGNS_SUBTYPE:
index a30eca5..db97648 100644 (file)
@@ -822,16 +822,15 @@ lldp_create(const struct netdev *netdev,
     hw->h_lport.p_id_len = strlen(netdev_get_name(netdev));
 
     /* Auto Attach element tlv */
-    hw->h_lport.p_element.type = LLDP_TLV_AA_ELEM_TYPE_TAG_CLIENT;
+    hw->h_lport.p_element.type = LLDP_TLV_AA_ELEM_TYPE_CLIENT_VIRTUAL_SWITCH;
     hw->h_lport.p_element.mgmt_vlan = 0;
     memcpy(&hw->h_lport.p_element.system_id.system_mac,
            lchassis->c_id, lchassis->c_id_len);
     hw->h_lport.p_element.system_id.conn_type =
         LLDP_TLV_AA_ELEM_CONN_TYPE_SINGLE;
-
-    hw->h_lport.p_element.system_id.smlt_id = 0;
-    hw->h_lport.p_element.system_id.mlt_id[0] = 0;
-    hw->h_lport.p_element.system_id.mlt_id[1] = 0;
+    hw->h_lport.p_element.system_id.rsvd = 0;
+    hw->h_lport.p_element.system_id.rsvd2[0] = 0;
+    hw->h_lport.p_element.system_id.rsvd2[1] = 0;
 
     list_init(&hw->h_lport.p_isid_vlan_maps);
     list_init(&lldp->lldpd->g_hardware);
@@ -908,15 +907,15 @@ lldp_create_dummy(void)
     hw->h_lport.p_id_len = strlen(hw->h_lport.p_id);
 
     /* Auto Attach element tlv */
-    hw->h_lport.p_element.type = LLDP_TLV_AA_ELEM_TYPE_TAG_CLIENT;
+    hw->h_lport.p_element.type = LLDP_TLV_AA_ELEM_TYPE_CLIENT_VIRTUAL_SWITCH;
     hw->h_lport.p_element.mgmt_vlan = 0;
     memcpy(&hw->h_lport.p_element.system_id.system_mac,
            lchassis->c_id, lchassis->c_id_len);
     hw->h_lport.p_element.system_id.conn_type =
         LLDP_TLV_AA_ELEM_CONN_TYPE_SINGLE;
-    hw->h_lport.p_element.system_id.smlt_id = 0;
-    hw->h_lport.p_element.system_id.mlt_id[0] = 0;
-    hw->h_lport.p_element.system_id.mlt_id[1] = 0;
+    hw->h_lport.p_element.system_id.rsvd = 0;
+    hw->h_lport.p_element.system_id.rsvd2[0] = 0;
+    hw->h_lport.p_element.system_id.rsvd2[1] = 0;
 
     list_init(&hw->h_lport.p_isid_vlan_maps);
     list_init(&lldp->lldpd->g_hardware);
index 4fb2618..9dabce1 100644 (file)
@@ -98,12 +98,12 @@ check_received_aa(struct lldpd_port *sport,
            sport->p_element.system_id.system_mac[5]);
     assert(rport->p_element.system_id.conn_type ==
            sport->p_element.system_id.conn_type);
-    assert(rport->p_element.system_id.smlt_id ==
-           sport->p_element.system_id.smlt_id);
-    assert(rport->p_element.system_id.mlt_id[0] ==
-           sport->p_element.system_id.mlt_id[0]);
-    assert(rport->p_element.system_id.mlt_id[1] ==
-           sport->p_element.system_id.mlt_id[1]);
+    assert(rport->p_element.system_id.rsvd ==
+           sport->p_element.system_id.rsvd);
+    assert(rport->p_element.system_id.rsvd2[0] ==
+           sport->p_element.system_id.rsvd2[0]);
+    assert(rport->p_element.system_id.rsvd2[1] ==
+           sport->p_element.system_id.rsvd2[1]);
 
     /* Should receive 2 mappings */
     assert(!list_is_empty(&rport->p_isid_vlan_maps));
@@ -160,7 +160,8 @@ test_aa_send(void)
     hardware.h_lport.p_mfs = 1516;
 
     /* Auto attach element discovery info */
-    hardware.h_lport.p_element.type = LLDP_TLV_AA_ELEM_TYPE_TAG_CLIENT;
+    hardware.h_lport.p_element.type =
+        LLDP_TLV_AA_ELEM_TYPE_CLIENT_VIRTUAL_SWITCH;
     hardware.h_lport.p_element.mgmt_vlan = 0xCDC;
     hardware.h_lport.p_element.system_id.system_mac[0] = 0x1;
     hardware.h_lport.p_element.system_id.system_mac[1] = 0x2;
@@ -170,9 +171,9 @@ test_aa_send(void)
     hardware.h_lport.p_element.system_id.system_mac[5] = 0x6;
 
     hardware.h_lport.p_element.system_id.conn_type = 0x5;
-    hardware.h_lport.p_element.system_id.smlt_id = 0x3CC;
-    hardware.h_lport.p_element.system_id.mlt_id[0] = 0xB;
-    hardware.h_lport.p_element.system_id.mlt_id[1] = 0xE;
+    hardware.h_lport.p_element.system_id.rsvd = 0x3CC;
+    hardware.h_lport.p_element.system_id.rsvd2[0] = 0xB;
+    hardware.h_lport.p_element.system_id.rsvd2[1] = 0xE;
 
     /* Local chassis info */
     chassis.c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
@@ -242,12 +243,12 @@ test_aa_send(void)
 
     hw->h_lport.p_element.system_id.conn_type =
         hardware.h_lport.p_element.system_id.conn_type;
-    hw->h_lport.p_element.system_id.smlt_id =
-        hardware.h_lport.p_element.system_id.smlt_id;
-    hw->h_lport.p_element.system_id.mlt_id[0] =
-        hardware.h_lport.p_element.system_id.mlt_id[0];
-    hw->h_lport.p_element.system_id.mlt_id[1] =
-        hardware.h_lport.p_element.system_id.mlt_id[1];
+    hw->h_lport.p_element.system_id.rsvd =
+        hardware.h_lport.p_element.system_id.rsvd;
+    hw->h_lport.p_element.system_id.rsvd2[0] =
+        hardware.h_lport.p_element.system_id.rsvd2[0];
+    hw->h_lport.p_element.system_id.rsvd2[1] =
+        hardware.h_lport.p_element.system_id.rsvd2[1];
 
     /* Populate instance with two auto attach isid/vlan mappings */
     map[0].isid_vlan_data.status  = map_init[0].isid_vlan_data.status;