From 9757bfbcde09193d399f860e02676f3b3f18dbcb Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Wed, 21 Sep 2011 17:07:17 -0600 Subject: [PATCH] IEEE 802.1 2005 TLV enhancement - PPVID and PI added --- src/client.c | 26 +++++++++++++ src/display.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/lldp.c | 91 ++++++++++++++++++++++++++++++++++++++++++++ src/lldpd.c | 40 +++++++++++++++++--- src/lldpd.h | 25 ++++++++++++- 5 files changed, 278 insertions(+), 6 deletions(-) diff --git a/src/client.c b/src/client.c index 7a9e7ab0..8b5ea28b 100644 --- a/src/client.c +++ b/src/client.c @@ -32,6 +32,8 @@ static struct client_handle client_handles[] = { #endif #ifdef ENABLE_DOT1 { HMSG_GET_VLANS, client_handle_port_related }, + { HMSG_GET_PPVIDS, client_handle_port_related }, + { HMSG_GET_PIDS, client_handle_port_related }, #endif { HMSG_SHUTDOWN, client_handle_shutdown }, { 0, NULL } }; @@ -255,6 +257,8 @@ client_handle_port_related(struct lldpd *cfg, struct hmsg *r, struct hmsg *s) s->hdr.len = sizeof(int); break; case HMSG_GET_VLANS: + case HMSG_GET_PPVIDS: + case HMSG_GET_PIDS: case HMSG_GET_PORT: case HMSG_GET_CHASSIS: /* We read the index which is right after the interface name */ @@ -291,6 +295,28 @@ client_handle_port_related(struct lldpd *cfg, struct hmsg *r, struct hmsg *s) return; } break; + case HMSG_GET_PPVIDS: + if (ctl_msg_pack_list( + STRUCT_LLDPD_PPVID, + &port->p_ppvids, + sizeof(struct lldpd_ppvid), s, &p) == -1) { + LLOG_WARNX("unable to send ppvids information for " + "interface %s for %d", ifname, r->hdr.pid); + s->hdr.len = -1; + return; + } + break; + case HMSG_GET_PIDS: + if (ctl_msg_pack_list( + STRUCT_LLDPD_PI, + &port->p_pids, + sizeof(struct lldpd_pi), s, &p) == -1) { + LLOG_WARNX("unable to send PI's information for " + "interface %s for %d", ifname, r->hdr.pid); + s->hdr.len = -1; + return; + } + break; #endif case HMSG_GET_PORT: if (ctl_msg_pack_structure(STRUCT_LLDPD_PORT, diff --git a/src/display.c b/src/display.c index c417ec6f..009872ed 100644 --- a/src/display.c +++ b/src/display.c @@ -29,6 +29,8 @@ TAILQ_HEAD(interfaces, lldpd_interface); #ifdef ENABLE_DOT1 TAILQ_HEAD(vlans, lldpd_vlan); +TAILQ_HEAD(ppvids, lldpd_ppvid); +TAILQ_HEAD(pids, lldpd_pi); #endif #define ntohll(x) (((u_int64_t)(ntohl((int)((x << 32) >> 32))) << 32) | \ @@ -393,6 +395,56 @@ get_vlans(int s, struct vlans *vls, char *interface, int nb) fatalx("get_vlans: unable to retrieve the list of vlans"); return 1; } + +static int +get_ppvids(int s, struct ppvids *pvs, char *interface, int nb) +{ + void *p; + struct hmsg *h; + + if ((h = (struct hmsg *)malloc(MAX_HMSGSIZE)) == NULL) + fatal(NULL); + ctl_msg_init(h, HMSG_GET_PPVIDS); + strlcpy((char *)&h->data, interface, IFNAMSIZ); + memcpy((char*)&h->data + IFNAMSIZ, &nb, sizeof(int)); + h->hdr.len += IFNAMSIZ + sizeof(int); + if (ctl_msg_send(s, h) == -1) + fatalx("get_ppvids: unable to send request"); + if (ctl_msg_recv(s, h) == -1) + fatalx("get_ppvids: unable to receive answer"); + if (h->hdr.type != HMSG_GET_PPVIDS) + fatalx("get_ppvids: unknown answer type received"); + p = &h->data; + if (ctl_msg_unpack_list(STRUCT_LLDPD_PPVID, + pvs, sizeof(struct lldpd_ppvid), h, &p) == -1) + fatalx("get_ppvids: unable to retrieve the list of ppvids"); + return 1; +} + +static int +get_pids(int s, struct pids *pids, char *interface, int nb) +{ + void *p; + struct hmsg *h; + + if ((h = (struct hmsg *)malloc(MAX_HMSGSIZE)) == NULL) + fatal(NULL); + ctl_msg_init(h, HMSG_GET_PIDS); + strlcpy((char *)&h->data, interface, IFNAMSIZ); + memcpy((char*)&h->data + IFNAMSIZ, &nb, sizeof(int)); + h->hdr.len += IFNAMSIZ + sizeof(int); + if (ctl_msg_send(s, h) == -1) + fatalx("get_pids: unable to send request"); + if (ctl_msg_recv(s, h) == -1) + fatalx("get_pids: unable to receive answer"); + if (h->hdr.type != HMSG_GET_PIDS) + fatalx("get_ppvids: unknown answer type received"); + p = &h->data; + if (ctl_msg_unpack_list(STRUCT_LLDPD_PI, + pids, sizeof(struct lldpd_pi), h, &p) == -1) + fatalx("get_pids: unable to retrieve the list of pids"); + return 1; +} #endif static int @@ -1000,6 +1052,44 @@ display_vlans(struct writer *w, struct lldpd_port *port) tag_end(w); } } + +static void +display_ppvids(struct writer *w, struct lldpd_port *port) +{ + struct lldpd_ppvid *ppvid; + TAILQ_FOREACH(ppvid, &port->p_ppvids, p_entries) { + tag_start(w, "ppvid", "PPVID"); + switch(ppvid->p_cap_status) { + case LLDPD_PPVID_CAP_SUPPORTED: + tag_attr(w, "ppvid-cap-status supported", "", + u2str(ppvid->p_cap_status)); + break; + case LLDPD_PPVID_CAP_ENABLED: + tag_attr(w, "ppvid-cap-status enabled", "", + u2str(ppvid->p_cap_status)); + break; + case LLDPD_PPVID_CAP_SUPPORTED_AND_ENABLED: + tag_attr(w, + "ppvid-cap-status supported, enabled", + "", + u2str(ppvid->p_cap_status)); + break; + } + tag_attr(w, "ppvid", "", u2str(ppvid->p_ppvid)); + tag_end(w); + } +} + +static void +display_pids(struct writer *w, struct lldpd_port *port) +{ + struct lldpd_pi *pi; + TAILQ_FOREACH(pi, &port->p_pids, p_entries) { + tag_start(w, "pi", "PI"); + tag_data(w, pi->p_pi); + tag_end(w); + } +} #endif static const char* @@ -1027,6 +1117,8 @@ display_interfaces(int s, const char * fmt, int argc, char *argv[]) struct interfaces ifs; #ifdef ENABLE_DOT1 struct vlans vls; + struct ppvids pvs; + struct pids pids; #endif struct lldpd_interface *iff; struct lldpd_chassis chassis; @@ -1080,6 +1172,16 @@ display_interfaces(int s, const char * fmt, int argc, char *argv[]) if (!TAILQ_EMPTY(&port.p_vlans) || port.p_pvid) { display_vlans(w, &port); } + if (get_ppvids(s, &pvs, iff->name, i) != -1) + memcpy(&port.p_ppvids, &pvs, sizeof(struct ppvids)); + if (!TAILQ_EMPTY(&port.p_ppvids)) { + display_ppvids(w, &port); + } + if (get_pids(s, &pids, iff->name, i) != -1) + memcpy(&port.p_pids, &pids, sizeof(struct pids)); + if (!TAILQ_EMPTY(&port.p_pids)) { + display_pids(w, &port); + } #endif #ifdef ENABLE_LLDPMED if (port.p_med_cap_enabled) { diff --git a/src/lldp.c b/src/lldp.c index 80832f31..6ebaab15 100644 --- a/src/lldp.c +++ b/src/lldp.c @@ -40,6 +40,8 @@ lldp_send(struct lldpd *global, #ifdef ENABLE_DOT1 const u_int8_t dot1[] = LLDP_TLV_ORG_DOT1; struct lldpd_vlan *vlan; + struct lldpd_ppvid *ppvid; + struct lldpd_pi *pi; #endif #ifdef ENABLE_DOT3 const u_int8_t dot3[] = LLDP_TLV_ORG_DOT3; @@ -152,6 +154,29 @@ lldp_send(struct lldpd *global, goto toobig; #ifdef ENABLE_DOT1 + /* Port VLAN ID */ + if(port->p_pvid != 0) { + if (!( + POKE_START_LLDP_TLV(LLDP_TLV_ORG) && + POKE_BYTES(dot1, sizeof(dot1)) && + POKE_UINT8(LLDP_TLV_DOT1_PVID) && + POKE_UINT16(port->p_pvid) && + POKE_END_LLDP_TLV)) { + goto toobig; + } + } + /* Port and Protocol VLAN IDs */ + TAILQ_FOREACH(ppvid, &port->p_ppvids, p_entries) { + if (!( + POKE_START_LLDP_TLV(LLDP_TLV_ORG) && + POKE_BYTES(dot1, sizeof(dot1)) && + POKE_UINT8(LLDP_TLV_DOT1_PPVID) && + POKE_UINT8(ppvid->p_cap_status) && + POKE_UINT16(ppvid->p_ppvid) && + POKE_END_LLDP_TLV)) { + goto toobig; + } + } /* VLANs */ TAILQ_FOREACH(vlan, &port->p_vlans, v_entries) { if (!( @@ -164,6 +189,17 @@ lldp_send(struct lldpd *global, POKE_END_LLDP_TLV)) goto toobig; } + /* Protocol Identities */ + TAILQ_FOREACH(pi, &port->p_pids, p_entries) { + if (!( + POKE_START_LLDP_TLV(LLDP_TLV_ORG) && + POKE_BYTES(dot1, sizeof(dot1)) && + POKE_UINT8(LLDP_TLV_DOT1_PI) && + POKE_UINT8(strlen(pi->p_pi)) && + POKE_BYTES(pi->p_pi, strlen(pi->p_pi)) && + POKE_END_LLDP_TLV)) + goto toobig; + } #endif #ifdef ENABLE_DOT3 @@ -415,6 +451,9 @@ lldp_decode(struct lldpd *cfg, char *frame, int s, #ifdef ENABLE_DOT1 struct lldpd_vlan *vlan; int vlan_len; + struct lldpd_ppvid *ppvid; + struct lldpd_pi *pi; + int pi_len; #endif if ((chassis = calloc(1, sizeof(struct lldpd_chassis))) == NULL) { @@ -428,6 +467,8 @@ lldp_decode(struct lldpd *cfg, char *frame, int s, } #ifdef ENABLE_DOT1 TAILQ_INIT(&port->p_vlans); + TAILQ_INIT(&port->p_ppvids); + TAILQ_INIT(&port->p_pids); #endif length = s; @@ -583,6 +624,56 @@ lldp_decode(struct lldpd *cfg, char *frame, int s, CHECK_TLV_SIZE(6, "PVID"); port->p_pvid = PEEK_UINT16; break; + case LLDP_TLV_DOT1_PPVID: + CHECK_TLV_SIZE(7, "PPVID"); + /* validation needed */ + /* PPVID has to be unique if more than + one PPVID TLVs are received - + discard if duplicate */ + /* if support bit is not set and + enabled bit is set - PPVID TLV is + considered error and discarded */ + /* if PPVID > 4096 - bad and discard */ + if ((ppvid = (struct lldpd_ppvid *)calloc(1, + sizeof(struct lldpd_ppvid))) == NULL) { + LLOG_WARN("unable to alloc ppvid " + "structure for " + "tlv received on %s", + hardware->h_ifname); + goto malformed; + } + ppvid->p_cap_status = PEEK_UINT8; + ppvid->p_ppvid = PEEK_UINT16; + TAILQ_INSERT_TAIL(&port->p_ppvids, + ppvid, p_entries); + break; + case LLDP_TLV_DOT1_PI: + /* validation needed */ + /* PI has to be unique if more than + one PI TLVs are received - discard + if duplicate ?? */ + CHECK_TLV_SIZE(5, "PI"); + if ((pi = (struct lldpd_pi *)calloc(1, + sizeof(struct lldpd_pi))) == NULL) { + LLOG_WARN("unable to alloc PI " + "structure for " + "tlv received on %s", + hardware->h_ifname); + goto malformed; + } + pi_len = PEEK_UINT8; + CHECK_TLV_SIZE(1 + pi_len, "PI"); + if ((pi->p_pi = + (char *)calloc(1, pi_len + 1)) == NULL) { + LLOG_WARN("unable to alloc pid name for " + "tlv received on %s", + hardware->h_ifname); + goto malformed; + } + PEEK_BYTES(pi->p_pi, pi_len); + TAILQ_INSERT_TAIL(&port->p_pids, + pi, p_entries); + break; default: /* Unknown Dot1 TLV, ignore it */ hardware->h_rx_unrecognized_cnt++; diff --git a/src/lldpd.c b/src/lldpd.c index 55deb500..4d12b020 100644 --- a/src/lldpd.c +++ b/src/lldpd.c @@ -185,6 +185,8 @@ lldpd_alloc_hardware(struct lldpd *cfg, char *name) #endif #ifdef ENABLE_DOT1 TAILQ_INIT(&hardware->h_lport.p_vlans); + TAILQ_INIT(&hardware->h_lport.p_ppvids); + TAILQ_INIT(&hardware->h_lport.p_pids); #endif return hardware; } @@ -203,6 +205,33 @@ lldpd_vlan_cleanup(struct lldpd_port *port) free(vlan); } } + +void +lldpd_ppvid_cleanup(struct lldpd_port *port) +{ + struct lldpd_ppvid *ppvid, *ppvid_next; + for (ppvid = TAILQ_FIRST(&port->p_ppvids); + ppvid != NULL; + ppvid = ppvid_next) { + ppvid_next = TAILQ_NEXT(ppvid, p_entries); + TAILQ_REMOVE(&port->p_ppvids, ppvid, p_entries); + free(ppvid); + } +} + +void +lldpd_pi_cleanup(struct lldpd_port *port) +{ + struct lldpd_pi *pi, *pi_next; + for (pi = TAILQ_FIRST(&port->p_pids); + pi != NULL; + pi = pi_next) { + free(pi->p_pi); + pi_next = TAILQ_NEXT(pi, p_entries); + TAILQ_REMOVE(&port->p_pids, pi, p_entries); + free(pi); + } +} #endif /* If `all' is true, clear all information, including information that @@ -218,6 +247,8 @@ lldpd_port_cleanup(struct lldpd *cfg, struct lldpd_port *port, int all) #endif #ifdef ENABLE_DOT1 lldpd_vlan_cleanup(port); + lldpd_ppvid_cleanup(port); + lldpd_pi_cleanup(port); #endif free(port->p_id); free(port->p_descr); @@ -558,6 +589,10 @@ lldpd_get_lsb_release() { static char * lldpd_get_os_release() { static char release[1024]; + char line[1024]; + char *key, *val; + char *ptr1 = release; + char *ptr2 = release; FILE *fp = fopen("/etc/os-release", "r"); if (!fp) { @@ -565,9 +600,6 @@ lldpd_get_os_release() { return NULL; } - char line[1024]; - char *key, *val; - while ((fgets(line, 1024, fp) != NULL)) { key = strtok(line, "="); val = strtok(NULL, "="); @@ -580,8 +612,6 @@ lldpd_get_os_release() { fclose(fp); /* Remove trailing newline and all " in the string. */ - char *ptr1 = release; - char *ptr2 = release; while (*ptr1 != 0) { if ((*ptr1 == '"') || (*ptr1 == '\n')) { ++ptr1; diff --git a/src/lldpd.h b/src/lldpd.h index b11df407..119e2065 100644 --- a/src/lldpd.h +++ b/src/lldpd.h @@ -67,12 +67,29 @@ #define USING_AGENTX_SUBAGENT_MODULE 1 #ifdef ENABLE_DOT1 +#define LLDPD_PPVID_CAP_SUPPORTED 0x01 +#define LLDPD_PPVID_CAP_ENABLED 0x02 +#define LLDPD_PPVID_CAP_SUPPORTED_AND_ENABLED 0x03 + +struct lldpd_ppvid { + TAILQ_ENTRY(lldpd_ppvid) p_entries; + u_int8_t p_cap_status; + u_int16_t p_ppvid; +}; +#define STRUCT_LLDPD_PPVID "(Lbw)" + struct lldpd_vlan { TAILQ_ENTRY(lldpd_vlan) v_entries; char *v_name; u_int16_t v_vid; }; #define STRUCT_LLDPD_VLAN "(Lsw)" + +struct lldpd_pi { + TAILQ_ENTRY(lldpd_pi) p_entries; + char *p_pi; +}; +#define STRUCT_LLDPD_PI "(Ls)" #endif #ifdef ENABLE_LLDPMED @@ -213,9 +230,11 @@ struct lldpd_port { #endif #ifdef ENABLE_DOT1 -#define STRUCT_LLDPD_PORT_DOT1 "wPP" +#define STRUCT_LLDPD_PORT_DOT1 "wPPP" u_int16_t p_pvid; TAILQ_HEAD(, lldpd_vlan) p_vlans; + TAILQ_HEAD(, lldpd_ppvid) p_ppvids; + TAILQ_HEAD(, lldpd_pi) p_pids; #else #define STRUCT_LLDPD_PORT_DOT1 "" #endif @@ -368,6 +387,8 @@ enum hmsg_type { HMSG_GET_PORT, HMSG_GET_CHASSIS, HMSG_GET_VLANS, + HMSG_GET_PPVIDS, + HMSG_GET_PIDS, HMSG_SET_LOCATION, HMSG_SET_POLICY, HMSG_SET_POWER, @@ -395,7 +416,9 @@ struct lldpd_hardware *lldpd_get_hardware(struct lldpd *, struct lldpd_hardware *lldpd_alloc_hardware(struct lldpd *, char *); void lldpd_hardware_cleanup(struct lldpd*, struct lldpd_hardware *); #ifdef ENABLE_DOT1 +void lldpd_ppvid_cleanup(struct lldpd_port *); void lldpd_vlan_cleanup(struct lldpd_port *); +void lldpd_pi_cleanup(struct lldpd_port *); #endif void lldpd_remote_cleanup(struct lldpd *, struct lldpd_hardware *, int); void lldpd_port_cleanup(struct lldpd*, struct lldpd_port *, int); -- 2.39.5