netdev-dpdk: Reset RSS hash on transmit
[cascardo/ovs.git] / lib / lldp / lldp.c
index 1ebb270..493c2ff 100644 (file)
@@ -126,6 +126,15 @@ lldp_tlv_put_u32(struct dp_packet *p, uint32_t x)
     dp_packet_put(p, &nx, sizeof nx);
 }
 
+static void
+lldp_tlv_put_isid(struct dp_packet *p, uint32_t isid)
+{
+    uint8_t *data = dp_packet_put_uninit(p, 3);
+    data[0] = isid >> 16;
+    data[1] = isid >> 8;
+    data[2] = isid;
+}
+
 static void
 lldp_tlv_start(struct dp_packet *p, uint8_t tlv, unsigned int *start)
 {
@@ -199,7 +208,7 @@ lldp_send(struct lldpd *global OVS_UNUSED,
     lldp_tlv_put_u16(p, chassis->c_cap_enabled);
     lldp_tlv_end(p, start);
 
-    LIST_FOR_EACH (mgmt, m_entries, &chassis->c_mgmt.m_entries) {
+    LIST_FOR_EACH (mgmt, m_entries, &chassis->c_mgmt) {
         lldp_tlv_start(p, LLDP_TLV_MGMT_ADDR, &start);
         lldp_tlv_put_u8(p, mgmt->m_addrsize + 1);
         lldp_tlv_put_u8(p, lldpd_af_to_lldp_proto(mgmt->m_family));
@@ -226,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 10 bits rsvd */
+        aa_elem_sys_id_second_byte =
+            (port->p_element.system_id.rsvd & 0xFF);
 
-        /* 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;
+        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.m_entries)) {
-        int j;
+    if (!list_is_empty(&port->p_isid_vlan_maps)) {
 
-        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);
@@ -281,15 +306,14 @@ lldp_send(struct lldpd *global OVS_UNUSED,
 
         LIST_FOR_EACH (vlan_isid_map,
                        m_entries,
-                       &hardware->h_lport.p_isid_vlan_maps.m_entries) {
+                       &hardware->h_lport.p_isid_vlan_maps) {
             u_int16_t status_vlan_word;
             status_vlan_word =
                 (vlan_isid_map->isid_vlan_data.status << 12) |
                 vlan_isid_map->isid_vlan_data.vlan;
 
             lldp_tlv_put_u16(p, status_vlan_word);
-            dp_packet_put(p, &vlan_isid_map->isid_vlan_data.isid,
-                          sizeof vlan_isid_map->isid_vlan_data.isid);
+            lldp_tlv_put_isid(p, vlan_isid_map->isid_vlan_data.isid);
         }
 
         lldp_tlv_end(p, start);
@@ -306,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);
@@ -319,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;
@@ -331,10 +356,12 @@ lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s,
     const char avaya_oid[] = LLDP_TLV_ORG_AVAYA;
     const char dcbx[] = LLDP_TLV_ORG_DCBX;
     char orgid[3];
-    int length, gotend = 0, ttl_received = 0, af;
+    int length, af;
+    bool gotend = false;
+    bool ttl_received = false;
     int tlv_size, tlv_type, tlv_subtype;
     u_int8_t *pos, *tlv;
-    char *b;
+    void *b;
     struct lldpd_aa_isid_vlan_maps_tlv *isid_vlan_map = NULL;
     u_int8_t msg_auth_digest[LLDP_TLV_AA_ISID_VLAN_DIGEST_LENGTH];
     struct lldpd_mgmt *mgmt;
@@ -345,10 +372,10 @@ lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s,
     VLOG_DBG("receive LLDP PDU on %s", hardware->h_ifname);
 
     chassis = xzalloc(sizeof *chassis);
-    list_init(&chassis->c_mgmt.m_entries);
+    list_init(&chassis->c_mgmt);
 
     port = xzalloc(sizeof *port);
-    list_init(&port->p_isid_vlan_maps.m_entries);
+    list_init(&port->p_isid_vlan_maps);
 
     length = s;
     pos = (u_int8_t*) frame;
@@ -362,13 +389,14 @@ 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);
         goto malformed;
     }
 
-    while (length && (!gotend)) {
+    while (length && !gotend) {
         if (length < 2) {
             VLOG_WARN("tlv header too short received on %s",
                       hardware->h_ifname);
@@ -395,14 +423,14 @@ lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s,
                 VLOG_DBG("extra data after lldp end on %s",
                          hardware->h_ifname);
             }
-            gotend = 1;
+            gotend = true;
             break;
 
         case LLDP_TLV_CHASSIS_ID:
         case LLDP_TLV_PORT_ID:
             CHECK_TLV_SIZE(2, "Port Id");
             tlv_subtype = PEEK_UINT8;
-            if ((tlv_subtype == 0) || (tlv_subtype > 7)) {
+            if (tlv_subtype == 0 || tlv_subtype > 7) {
                 VLOG_WARN("unknown subtype for tlv id received on %s",
                           hardware->h_ifname);
                 goto malformed;
@@ -423,7 +451,7 @@ lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s,
         case LLDP_TLV_TTL:
             CHECK_TLV_SIZE(2, "TTL");
             chassis->c_ttl = PEEK_UINT16;
-            ttl_received = 1;
+            ttl_received = true;
             break;
 
         case LLDP_TLV_PORT_DESCR:
@@ -473,7 +501,7 @@ lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s,
                 VLOG_WARN("unable to allocate memory for management address");
                 goto malformed;
             }
-            list_push_back(&chassis->c_mgmt.m_entries, &mgmt->m_entries);
+            list_push_back(&chassis->c_mgmt, &mgmt->m_entries);
             break;
 
         case LLDP_TLV_ORG:
@@ -488,39 +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 4 most-significant bits */
-                    port->p_element.type = aa_element_word >> 12;
+                    /* Type is first 6 most-significant bits of
+                     * aa_element_dword */
+                    port->p_element.type = aa_element_dword >> 26;
 
-                    /* mgmt_vlan is last 12 bits */
-                    port->p_element.mgmt_vlan = aa_element_word & 0x0FFF;
-                    VLOG_INFO("Element type: %X, Mgmt vlan: %X",
+                    /* State is 6 most significant bits of aa_element_dword */
+                    aa_element_state = (aa_element_dword >> 20) & 0x3F;
+
+                    /* 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: 0x%.2X%.2X%.2X%.2X%.2X%.2X",
-                              port->p_element.system_id.system_mac[0],
-                              port->p_element.system_id.system_mac[1],
-                              port->p_element.system_id.system_mac[2],
-                              port->p_element.system_id.system_mac[3],
-                              port->p_element.system_id.system_mac[4],
-                              port->p_element.system_id.system_mac[5]);
+                    VLOG_INFO("System mac: "ETH_ADDR_FMT,
+                        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:
@@ -531,13 +577,15 @@ lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s,
                      */
                     num_mappings = tlv_size - 4 -
                         LLDP_TLV_AA_ISID_VLAN_DIGEST_LENGTH;
-                    if ((num_mappings % 5) != 0) {
+                    if (num_mappings % 5 != 0) {
                         VLOG_INFO("malformed vlan-isid mappings tlv received");
                         goto malformed;
                     }
 
                     num_mappings /= 5; /* Each mapping is 5 Bytes */
                     for(; num_mappings > 0; num_mappings--) {
+                        uint8_t isid[3];
+
                         isid_vlan_map = xzalloc(sizeof *isid_vlan_map);
                         aa_status_vlan_word = PEEK_UINT16;
 
@@ -548,11 +596,11 @@ lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s,
                         /* Vlan is last 12 bits */
                         isid_vlan_map->isid_vlan_data.vlan =
                             aa_status_vlan_word & 0x0FFF;
-                        PEEK_BYTES(&isid_vlan_map->isid_vlan_data.isid,
-                            sizeof isid_vlan_map->isid_vlan_data.isid);
-                        list_push_back(
-                            (struct ovs_list *) &port->p_isid_vlan_maps,
-                            (struct ovs_list *) isid_vlan_map);
+                        PEEK_BYTES(isid, 3);
+                        isid_vlan_map->isid_vlan_data.isid =
+                            (isid[0] << 16) | (isid[1] << 8) | isid[2];
+                        list_push_back(&port->p_isid_vlan_maps,
+                                       &isid_vlan_map->m_entries);
                         isid_vlan_map = NULL;
                     }
                     break;
@@ -587,10 +635,7 @@ lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s,
     }
 
     /* Some random check */
-    if ((chassis->c_id == NULL) ||
-        (port->p_id == NULL) ||
-        (!ttl_received) ||
-        (gotend == 0)) {
+    if (!chassis->c_id || !port->p_id || !ttl_received || !gotend) {
         VLOG_WARN("some mandatory tlv are missing for frame received "
                   "on %s", hardware->h_ifname);
         goto malformed;