Skip to content

Commit

Permalink
auto-attach: Support latest version of auto-attach LLDP TLVs
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Ben Pfaff <[email protected]>
  • Loading branch information
Dennis Flynn authored and blp committed Mar 23, 2015
1 parent 5568661 commit 1469121
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 80 deletions.
6 changes: 4 additions & 2 deletions lib/lldp/aa-structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@
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;
};
Expand Down
30 changes: 20 additions & 10 deletions lib/lldp/lldp-tlv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -61,16 +61,26 @@
#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
Expand Down
127 changes: 84 additions & 43 deletions lib/lldp/lldp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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:
Expand Down
17 changes: 8 additions & 9 deletions lib/ovs-lldp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
33 changes: 17 additions & 16 deletions tests/test-aa.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 1469121

Please sign in to comment.