diff options
-rw-r--r-- | lib/lldp/lldp.c | 350 | ||||
-rw-r--r-- | tests/test-aa.c | 6 |
2 files changed, 117 insertions, 239 deletions
diff --git a/lib/lldp/lldp.c b/lib/lldp/lldp.c index 2a581acf3..5f02d4199 100644 --- a/lib/lldp/lldp.c +++ b/lib/lldp/lldp.c @@ -1,5 +1,6 @@ /* -*- mode: c; c-file-style: "openbsd" -*- */ /* + * Copyright (c) 2015 Nicira, Inc. * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx> * Copyright (c) 2014 Michael Chapman * @@ -30,49 +31,9 @@ VLOG_DEFINE_THIS_MODULE(lldp); -/* This set of macro are used to build packets. The current position in buffer - * is `pos'. The length of the remaining space in buffer is `length'. `type' - * should be a member of `types'. - * - * This was stolen from ladvd which was adapted from Net::CDP. The original - * author of those macros, Michael Chapman, has relicensed those macros under - * the ISC license. - */ - -#define POKE(value, type, func) \ - ((length >= sizeof type) && \ - ( \ - type = func(value), \ - memcpy(pos, &type, sizeof type), \ - length -= sizeof type, \ - pos += sizeof type, \ - 1 \ - ) \ - ) -#define POKE_UINT8(value) POKE(value, types.f_uint8, ) -#define POKE_UINT16(value) POKE(value, types.f_uint16, htons) -#define POKE_UINT32(value) POKE(value, types.f_uint32, htonl) -#define POKE_BYTES(value, bytes) \ - ((length >= (bytes)) && \ - ( \ - memcpy(pos, value, bytes), \ - length -= (bytes), \ - pos += (bytes), \ - 1 \ - ) \ - ) -#define POKE_SAVE(where) (where = pos, 1) -#define POKE_RESTORE(where) \ - do { \ - if ((where) > pos) \ - length -= ((where) - pos); \ - else \ - length += (pos - (where)); \ - pos = (where); \ - } while(0) - -/* This set of macro are used to parse packets. The same variable as for POKE_ - * are used. There is no check on boundaries. +/* This set of macro are used to parse packets. The current position in buffer + * is `pos'. The length of the remaining space in buffer is `length'. There is + * no check on boundaries. */ #define PEEK(type, func) \ @@ -103,23 +64,6 @@ VLOG_DEFINE_THIS_MODULE(lldp); (length -= (bytes), \ pos += (bytes), \ memcmp(pos-bytes, value, bytes)) -#define PEEK_SAVE POKE_SAVE -#define PEEK_RESTORE POKE_RESTORE - -/* LLDP specific. We need a `tlv' pointer. */ -#define POKE_START_LLDP_TLV(type) \ - ( \ - tlv = pos, \ - POKE_UINT16(type << 9) \ - ) -#define POKE_END_LLDP_TLV \ - ( \ - memcpy(&types.f_uint16, tlv, sizeof(uint16_t)), \ - types.f_uint16 |= htons((pos - (tlv + 2)) & 0x01ff), \ - memcpy(tlv, &types.f_uint16, sizeof(uint16_t)), \ - 1 \ - ) - #define CHECK_TLV_SIZE(x, name) \ do { \ if (tlv_size < (x)) { \ @@ -128,6 +72,7 @@ VLOG_DEFINE_THIS_MODULE(lldp); goto malformed; \ } \ } while (0) +#define PEEK_SAVE(where) (where = pos, 1) static union { uint8_t f_uint8; @@ -161,17 +106,51 @@ lldpd_af_from_lldp_proto(int proto) } } +static void +lldp_tlv_put_u8(struct dp_packet *p, uint8_t x) +{ + dp_packet_put(p, &x, sizeof x); +} + +static void +lldp_tlv_put_u16(struct dp_packet *p, uint16_t x) +{ + ovs_be16 nx = htons(x); + dp_packet_put(p, &nx, sizeof nx); +} + +static void +lldp_tlv_put_u32(struct dp_packet *p, uint32_t x) +{ + ovs_be32 nx = htonl(x); + dp_packet_put(p, &nx, sizeof nx); +} + +static void +lldp_tlv_start(struct dp_packet *p, uint8_t tlv, unsigned int *start) +{ + *start = dp_packet_size(p); + lldp_tlv_put_u16(p, tlv << 9); +} + +static void +lldp_tlv_end(struct dp_packet *p, unsigned int start) +{ + ovs_be16 *tlv = dp_packet_at_assert(p, start, 2); + *tlv |= htons((dp_packet_size(p) - (start + 2)) & 0x1ff); +} + int lldp_send(struct lldpd *global OVS_UNUSED, struct lldpd_hardware *hardware, struct dp_packet *p) { + unsigned int orig_size = dp_packet_size(p); + unsigned int start; + struct lldpd_port *port; struct lldpd_chassis *chassis; - struct lldpd_frame *frame; - uint8_t *packet, *pos, *tlv; struct lldpd_mgmt *mgmt; - int length, proto; const uint8_t avaya[] = LLDP_TLV_ORG_AVAYA; struct lldpd_aa_isid_vlan_maps_tlv *vlan_isid_map; uint8_t msg_auth_digest[LLDP_TLV_AA_ISID_VLAN_DIGEST_LENGTH]; @@ -180,126 +159,71 @@ lldp_send(struct lldpd *global OVS_UNUSED, chassis = port->p_chassis; /* The ethernet header is filled in elsewhere, we must save room for it. */ - length = hardware->h_mtu - sizeof(struct eth_header); - packet = dp_packet_l3(p); - VLOG_DBG("LLDP PDU send to %s mtu %d incoming with ptr=%p", - hardware->h_ifname, hardware->h_mtu, packet); - pos = packet; - - /* - * Make room in dp_packet for chassis ID, Port ID, System Name, System - * Descr, System Cap - */ - pos = dp_packet_put_uninit(p, sizeof chassis->c_id_subtype + - chassis->c_id_len + - sizeof port->p_id_subtype + - port->p_id_len + - sizeof chassis->c_ttl + - strlen(chassis->c_name) + - strlen(chassis->c_descr) + - sizeof chassis->c_cap_available + - sizeof chassis->c_cap_enabled + 12); + VLOG_DBG("LLDP PDU send to %s mtu %d incoming", + hardware->h_ifname, hardware->h_mtu); /* Chassis ID */ - if (!(POKE_START_LLDP_TLV(LLDP_TLV_CHASSIS_ID) && - POKE_UINT8(chassis->c_id_subtype) && - POKE_BYTES(chassis->c_id, chassis->c_id_len) && - POKE_END_LLDP_TLV)) { - goto toobig; - } + lldp_tlv_start(p, LLDP_TLV_CHASSIS_ID, &start); + lldp_tlv_put_u8(p, chassis->c_id_subtype); + dp_packet_put(p, chassis->c_id, chassis->c_id_len); + lldp_tlv_end(p, start); /* Port ID */ - if (!(POKE_START_LLDP_TLV(LLDP_TLV_PORT_ID) && - POKE_UINT8(port->p_id_subtype) && - POKE_BYTES(port->p_id, port->p_id_len) && - POKE_END_LLDP_TLV)) { - goto toobig; - } + lldp_tlv_start(p, LLDP_TLV_PORT_ID, &start); + lldp_tlv_put_u8(p, port->p_id_subtype); + dp_packet_put(p, port->p_id, port->p_id_len); + lldp_tlv_end(p, start); /* Time to live */ - if (!(POKE_START_LLDP_TLV(LLDP_TLV_TTL) && - POKE_UINT16(chassis->c_ttl) && - POKE_END_LLDP_TLV)) { - goto toobig; - } + lldp_tlv_start(p, LLDP_TLV_TTL, &start); + lldp_tlv_put_u16(p, chassis->c_ttl); + lldp_tlv_end(p, start); /* System name */ if (chassis->c_name && *chassis->c_name != '\0') { - if (!(POKE_START_LLDP_TLV(LLDP_TLV_SYSTEM_NAME) && - POKE_BYTES(chassis->c_name, strlen(chassis->c_name)) && - POKE_END_LLDP_TLV)) { - goto toobig; - } + lldp_tlv_start(p, LLDP_TLV_SYSTEM_NAME, &start); + dp_packet_put(p, chassis->c_name, strlen(chassis->c_name)); + lldp_tlv_end(p, start); } /* System description (skip it if empty) */ if (chassis->c_descr && *chassis->c_descr != '\0') { - if (!(POKE_START_LLDP_TLV(LLDP_TLV_SYSTEM_DESCR) && - POKE_BYTES(chassis->c_descr, strlen(chassis->c_descr)) && - POKE_END_LLDP_TLV)) { - goto toobig; - } + lldp_tlv_start(p, LLDP_TLV_SYSTEM_DESCR, &start); + dp_packet_put(p, chassis->c_descr, strlen(chassis->c_descr)); + lldp_tlv_end(p, start); } /* System capabilities */ - if (!(POKE_START_LLDP_TLV(LLDP_TLV_SYSTEM_CAP) && - POKE_UINT16(chassis->c_cap_available) && - POKE_UINT16(chassis->c_cap_enabled) && - POKE_END_LLDP_TLV)) { - goto toobig; - } + lldp_tlv_start(p, LLDP_TLV_SYSTEM_CAP, &start); + lldp_tlv_put_u16(p, chassis->c_cap_available); + 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) { - /* - * Make room for 1 mgmt interface - */ - dp_packet_put_uninit(p, 2 + sizeof(uint8_t) + - sizeof(uint8_t) + - mgmt->m_addrsize + - sizeof(uint8_t) + - sizeof(uint32_t) + - sizeof(uint8_t)); - - proto = lldpd_af_to_lldp_proto(mgmt->m_family); - if (!(POKE_START_LLDP_TLV(LLDP_TLV_MGMT_ADDR) && - /* Size of the address, including its type */ - POKE_UINT8(mgmt->m_addrsize + 1) && - POKE_UINT8(proto) && - POKE_BYTES(&mgmt->m_addr, mgmt->m_addrsize))) { - goto toobig; - } + 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)); + dp_packet_put(p, &mgmt->m_addr, mgmt->m_addrsize); /* Interface port type, OID */ if (mgmt->m_iface == 0) { - if (!(/* We don't know the management interface */ - POKE_UINT8(LLDP_MGMT_IFACE_UNKNOWN) && - POKE_UINT32(0))) { - goto toobig; - } + /* We don't know the management interface */ + lldp_tlv_put_u8(p, LLDP_MGMT_IFACE_UNKNOWN); + lldp_tlv_put_u32(p, 0); } else { - if (!(/* We have the index of the management interface */ - POKE_UINT8(LLDP_MGMT_IFACE_IFINDEX) && - POKE_UINT32(mgmt->m_iface))) { - goto toobig; - } - } - if (!(/* We don't provide an OID for management */ - POKE_UINT8(0) && - POKE_END_LLDP_TLV)) { - goto toobig; + /* We have the index of the management interface */ + lldp_tlv_put_u8(p, LLDP_MGMT_IFACE_IFINDEX); + lldp_tlv_put_u32(p, mgmt->m_iface); } + lldp_tlv_put_u8(p, 0); + lldp_tlv_end(p, start); } /* Port description */ if (port->p_descr && *port->p_descr != '\0') { - /* make room for port descr */ - dp_packet_put_uninit(p, 2 + strlen(port->p_descr)); - - if (!(POKE_START_LLDP_TLV(LLDP_TLV_PORT_DESCR) && - POKE_BYTES(port->p_descr, strlen(port->p_descr)) && - POKE_END_LLDP_TLV)) { - goto toobig; - } + lldp_tlv_start(p, LLDP_TLV_PORT_DESCR, &start); + dp_packet_put(p, port->p_descr, strlen(port->p_descr)); + lldp_tlv_end(p, start); } /* Add Auto Attach tlvs to packet */ @@ -329,52 +253,31 @@ lldp_send(struct lldpd *global OVS_UNUSED, /* 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; - /* make room for element type tlv */ - dp_packet_put_uninit(p, 2 + sizeof avaya + - sizeof(uint8_t) + - sizeof aa_element_first_byte + - sizeof aa_element_second_byte + - sizeof port->p_element.system_id.system_mac + - sizeof aa_elem_sys_id_first_byte + - sizeof aa_elem_sys_id_second_byte + - sizeof port->p_element.system_id.mlt_id); - - if (!(POKE_START_LLDP_TLV(LLDP_TLV_ORG) && - POKE_BYTES(avaya, sizeof avaya) && - POKE_UINT8(LLDP_TLV_AA_ELEMENT_SUBTYPE) && - POKE_UINT8(aa_element_first_byte) && - POKE_UINT8(aa_element_second_byte) && - POKE_BYTES(&port->p_element.system_id.system_mac, - sizeof port->p_element.system_id.system_mac) && - POKE_UINT8(aa_elem_sys_id_first_byte) && - POKE_UINT8(aa_elem_sys_id_second_byte) && - POKE_BYTES(&port->p_element.system_id.mlt_id, - sizeof port->p_element.system_id.mlt_id) && - POKE_END_LLDP_TLV)) { - goto toobig; - } + 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, &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); + lldp_tlv_end(p, start); } if (!list_is_empty(&port->p_isid_vlan_maps.m_entries)) { int j; - /* - * make room for aa_isid_digest - */ - dp_packet_put_uninit(p, 2 + sizeof avaya + - sizeof(uint8_t) + - sizeof msg_auth_digest); - for (j = 0; j < LLDP_TLV_AA_ISID_VLAN_DIGEST_LENGTH; j++) { msg_auth_digest[j] = 0; } - if (!(POKE_START_LLDP_TLV(LLDP_TLV_ORG) && - POKE_BYTES(avaya, sizeof avaya) && - POKE_UINT8(LLDP_TLV_AA_ISID_VLAN_ASGNS_SUBTYPE) && - POKE_BYTES(msg_auth_digest, sizeof msg_auth_digest))) { - goto toobig; - } + lldp_tlv_start(p, LLDP_TLV_ORG, &start); + dp_packet_put(p, avaya, sizeof avaya); + lldp_tlv_put_u8(p, LLDP_TLV_AA_ISID_VLAN_ASGNS_SUBTYPE); + dp_packet_put(p, msg_auth_digest, sizeof msg_auth_digest); LIST_FOR_EACH (vlan_isid_map, m_entries, @@ -384,59 +287,34 @@ lldp_send(struct lldpd *global OVS_UNUSED, (vlan_isid_map->isid_vlan_data.status << 12) | vlan_isid_map->isid_vlan_data.vlan; - /* - * Make room for one isid-vlan mapping - */ - dp_packet_put_uninit(p, sizeof status_vlan_word + - sizeof vlan_isid_map->isid_vlan_data.isid); - - if (!(POKE_UINT16(status_vlan_word) && - POKE_BYTES(&vlan_isid_map->isid_vlan_data.isid, - sizeof vlan_isid_map->isid_vlan_data.isid))) { - goto toobig; - } + 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); } - if (!(POKE_END_LLDP_TLV)) { - goto toobig; - } + lldp_tlv_end(p, start); } - /* Make room for the End TLV 0x0000 */ - dp_packet_put_uninit(p, sizeof(uint16_t)); - /* END */ - if (!(POKE_START_LLDP_TLV(LLDP_TLV_END) && - POKE_END_LLDP_TLV)) { - goto toobig; - } + lldp_tlv_start(p, LLDP_TLV_END, &start); + lldp_tlv_end(p, start); hardware->h_tx_cnt++; - /* We assume that LLDP frame is the reference */ - if ((frame = malloc(sizeof(int) + pos - packet)) != NULL) { - frame->size = pos - packet; - length = frame->size; - memcpy(&frame->frame, packet, frame->size); - - if ((hardware->h_lport.p_lastframe == NULL) || - (hardware->h_lport.p_lastframe->size != frame->size) || - (memcmp(hardware->h_lport.p_lastframe->frame, frame->frame, - frame->size) != 0)) { - free(hardware->h_lport.p_lastframe); - hardware->h_lport.p_lastframe = frame; - hardware->h_lport.p_lastchange = time(NULL); - } else { - free(frame); - } + const char *lldp = dp_packet_at_assert(p, orig_size, 0); + unsigned int lldp_len = dp_packet_size(p) - orig_size; + 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); + free(hardware->h_lport.p_lastframe); + hardware->h_lport.p_lastframe = frame; + hardware->h_lport.p_lastchange = time(NULL); } - return length; - -toobig: - free(packet); - - return E2BIG; + return dp_packet_size(p); } int diff --git a/tests/test-aa.c b/tests/test-aa.c index c3f5f3aa6..c4c9e71ce 100644 --- a/tests/test-aa.c +++ b/tests/test-aa.c @@ -153,7 +153,7 @@ test_aa_send(void) struct lldpd_aa_isid_vlan_maps_tlv map[2]; uint32_t stub[512 / 4]; - struct ofpbuf packet; + struct dp_packet packet; int n; @@ -202,8 +202,8 @@ test_aa_send(void) map_init[1].isid_vlan_data.isid[2] = 6; /* Prepare an empty packet buffer */ - ofpbuf_use_stub(&packet, stub, sizeof stub); - ofpbuf_clear(&packet); + dp_packet_use_stub(&packet, stub, sizeof stub); + dp_packet_clear(&packet); /* Create a dummy lldp instance */ lldp = lldp_create_dummy(); |