]> git.ipfire.org Git - thirdparty/lldpd.git/commitdiff
IEEE 802.1 2005 TLV enhancement - PPVID and PI added
authorShuah Khan <shuah.khan@hp.com>
Wed, 21 Sep 2011 23:07:17 +0000 (17:07 -0600)
committerVincent Bernat <bernat@luffy.cx>
Thu, 22 Sep 2011 19:19:54 +0000 (21:19 +0200)
src/client.c
src/display.c
src/lldp.c
src/lldpd.c
src/lldpd.h

index 7a9e7ab0a0851062d5ac36813f0fbc821fd775ce..8b5ea28ba4c2e9d7b0efee029e6b249119dd7cac 100644 (file)
@@ -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,
index c417ec6fe8577854d31dd7223a6fa534cb34f119..009872edc7fbae58251823aa3e999896337109cf 100644 (file)
@@ -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) {
index 80832f31e59f5bb33edcb98956a35ca7bc3d414e..6ebaab1559fbc9f646bb485f3d9ea03910c55aa3 100644 (file)
@@ -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++;
index 55deb500205aca9e8a4df53ea883656fbdcd7a7e..4d12b020b7d5851b8f56fc80cf93f9f3c2332785 100644 (file)
@@ -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;
index b11df407dfec1264cb0d1e4e4fa1283ca6991cc8..119e20653909e72cea73a0e3fa73ba017f40b598 100644 (file)
 #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);