From: Vincent Bernat Date: Fri, 7 Nov 2008 11:17:50 +0000 (+0100) Subject: Add FDP support X-Git-Tag: 0.2~25^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=031118c42dd92009e7c06bebcc23f7f423239bf2;p=thirdparty%2Flldpd.git Add FDP support --- diff --git a/README b/README index 75c8b56a..87deb7b2 100644 --- a/README +++ b/README @@ -22,14 +22,14 @@ on bridges. More complex setups may give false results. lldpctl allows to query information collected through the command line. -lldpd also implements CDP (Cisco Discovery Protocol), SONMP (Nortel -Discovery Protocol) and EDP (Extreme Discovery Protocol). However, -recent versions of IOS should support LLDP and most Extreme stuff -support LLDP. When a EDP, CDP or SONMP frame is received on a given -interface, lldpd starts sending EDP, CDP or SONMP frame on this -interface. Informations collected through EDP/CDP/SONMP are integrated -with other informations and can be queried with lldpctl or through -SNMP. +lldpd also implements CDP (Cisco Discovery Protocol), FDP (Foundry +Discovery Protocol), SONMP (Nortel Discovery Protocol) and EDP +(Extreme Discovery Protocol). However, recent versions of IOS should +support LLDP and most Extreme stuff support LLDP. When a EDP, CDP or +SONMP frame is received on a given interface, lldpd starts sending +EDP, CDP, FDP or SONMP frame on this interface. Informations collected +through EDP/CDP/FDP/SONMP are integrated with other informations and +can be queried with lldpctl or through SNMP. For bonding, you need 2.6.24 (in previous version, PACKET_ORIGDEV affected only non multicast packets). See: diff --git a/debian/control b/debian/control index 70292a31..2601ab53 100644 --- a/debian/control +++ b/debian/control @@ -19,4 +19,5 @@ Description: implementation of IEEE 802.1ab (LLDP) LLDP is to provide an inter-vendor compatible mechanism to deliver Link-Layer notifications to adjacent network devices. . - This daemon is also able to deal with CDP, SONMP and EDP protocol. + This daemon is also able to deal with CDP, FDP, SONMP and EDP + protocol. diff --git a/man/lldpd.8 b/man/lldpd.8 index 962c1caa..c5963ad4 100644 --- a/man/lldpd.8 +++ b/man/lldpd.8 @@ -69,6 +69,9 @@ information about local system and remote systems through SNMP. .It Fl c Enable the support of CDP protocol to deal with Cisco routers that do not speak LLDP. +.It Fl f +Enable the support of FDP protocol to deal with Foundry routers that do +not speak LLDP. .It Fl s Enable the support of SONMP protocol to deal with Nortel routers and switches that do not speak LLDP. diff --git a/src/cdp.c b/src/cdp.c index 9ff735e5..3acc757e 100644 --- a/src/cdp.c +++ b/src/cdp.c @@ -14,6 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +/* We also supports FDP which is very similar to CDPv1 */ #include "lldpd.h" #include @@ -25,8 +26,8 @@ cdp_send(struct lldpd *global, struct lldpd_chassis *chassis, { struct cdp_header ch; struct ethllc llc; - const u_int8_t mcastaddr[] = CDP_MULTICAST_ADDR; - const u_int8_t llcorg[] = LLC_ORG_CISCO; + u_int8_t mcastaddr[] = CDP_MULTICAST_ADDR; + u_int8_t llcorg[] = LLC_ORG_CISCO; struct iovec *iov = NULL; struct cdp_tlv_head device; struct cdp_tlv_head port; @@ -42,6 +43,14 @@ cdp_send(struct lldpd *global, struct lldpd_chassis *chassis, sizeof(struct iovec))) == NULL) \ fatal(NULL); + /* Handle FDP */ + if (version == 0) { + const u_int8_t fdpmcastaddr[] = FDP_MULTICAST_ADDR; + const u_int8_t fdpllcorg[] = LLC_ORG_FOUNDRY; + memcpy(mcastaddr, fdpmcastaddr, sizeof(mcastaddr)); + memcpy(llcorg, fdpllcorg, sizeof(llcorg)); + } + /* Ether + LLC */ memset(&llc, 0, sizeof(llc)); memcpy(&llc.ether.shost, &hardware->h_lladdr, @@ -58,7 +67,10 @@ cdp_send(struct lldpd *global, struct lldpd_chassis *chassis, /* CDP header */ memset(&ch, 0, sizeof(ch)); - ch.version = version; + if (version == 0) + ch.version = 1; + else + ch.version = version; ch.ttl = chassis->c_ttl; IOV_NEW; iov[c].iov_base = &ch; @@ -104,20 +116,22 @@ cdp_send(struct lldpd *global, struct lldpd_chassis *chassis, iov[c].iov_base = hardware->h_lport.p_descr; iov[c].iov_len = strlen(hardware->h_lport.p_descr); - /* Capaibilities */ - memset(&cap, 0, sizeof(cap)); - cap.head.tlv_type = htons(CDP_TLV_CAPABILITIES); - cap.head.tlv_len = htons(sizeof(cap)); - cap.cap = 0; - if (chassis->c_cap_enabled & LLDP_CAP_ROUTER) - cap.cap |= CDP_CAP_ROUTER; - if (chassis->c_cap_enabled & LLDP_CAP_BRIDGE) - cap.cap |= CDP_CAP_BRIDGE; - cap.cap = htonl(cap.cap); - IOV_NEW; - iov[c].iov_base = ∩ - iov[c].iov_len = sizeof(cap); - + /* Capabilities */ + if (version != 0) { + memset(&cap, 0, sizeof(cap)); + cap.head.tlv_type = htons(CDP_TLV_CAPABILITIES); + cap.head.tlv_len = htons(sizeof(cap)); + cap.cap = 0; + if (chassis->c_cap_enabled & LLDP_CAP_ROUTER) + cap.cap |= CDP_CAP_ROUTER; + if (chassis->c_cap_enabled & LLDP_CAP_BRIDGE) + cap.cap |= CDP_CAP_BRIDGE; + cap.cap = htonl(cap.cap); + IOV_NEW; + iov[c].iov_base = ∩ + iov[c].iov_len = sizeof(cap); + } + /* Software version */ memset(&soft, 0, sizeof(soft)); soft.tlv_type = htons(CDP_TLV_SOFTWARE); @@ -165,6 +179,7 @@ cdp_send(struct lldpd *global, struct lldpd_chassis *chassis, return 0; } +/* cdp_decode also decodes FDP */ int cdp_decode(struct lldpd *cfg, char *frame, int s, struct lldpd_hardware *hardware, @@ -182,7 +197,8 @@ cdp_decode(struct lldpd *cfg, char *frame, int s, char *software = NULL, *platform = NULL; int software_len = 0, platform_len = 0; const unsigned char cdpaddr[] = CDP_MULTICAST_ADDR; - int i, f, len, rlen; + const unsigned char fdpaddr[] = CDP_MULTICAST_ADDR; + int i, f, len, rlen, fdp = 0; if ((chassis = calloc(1, sizeof(struct lldpd_chassis))) == NULL) { LLOG_WARN("failed to allocate remote chassis"); @@ -202,9 +218,13 @@ cdp_decode(struct lldpd *cfg, char *frame, int s, llc = (struct ethllc *)frame; if (memcmp(&llc->ether.dhost, cdpaddr, sizeof(cdpaddr)) != 0) { - LLOG_INFO("frame not targeted at CDP multicast address received on %s", - hardware->h_ifname); - goto malformed; + if (memcmp(&llc->ether.dhost, fdpaddr, sizeof(fdpaddr)) != 0) + fdp = 1; + else { + LLOG_INFO("frame not targeted at CDP/FDP multicast address received on %s", + hardware->h_ifname); + goto malformed; + } } if (ntohs(llc->ether.size) > s - sizeof(struct ieee8023)) { LLOG_WARNX("incorrect 802.3 frame size reported on %s", @@ -226,7 +246,7 @@ cdp_decode(struct lldpd *cfg, char *frame, int s, f = sizeof(struct ethllc); ch = (struct cdp_header *)(frame + f); if ((ch->version != 1) && (ch->version != 2)) { - LLOG_WARNX("incorrect CDP version (%d) for frame received on %s", + LLOG_WARNX("incorrect CDP/FDP version (%d) for frame received on %s", ch->version, hardware->h_ifname); goto malformed; } @@ -236,7 +256,7 @@ cdp_decode(struct lldpd *cfg, char *frame, int s, cksum = iov_checksum(&iov, 1, 1); /* An off-by-one error may happen. Just ignore it */ if ((cksum != 0) && (cksum != 0xfffe)) { - LLOG_INFO("incorrect CDP checksum for frame received on %s (%d)", + LLOG_INFO("incorrect CDP/FDP checksum for frame received on %s (%d)", hardware->h_ifname, cksum); goto malformed; } @@ -244,7 +264,7 @@ cdp_decode(struct lldpd *cfg, char *frame, int s, f += sizeof(struct cdp_header); while (f < s) { if (f + sizeof(struct cdp_tlv_head) > s) { - LLOG_WARNX("CDP TLV header is too large for " + LLOG_WARNX("CDP/FDP TLV header is too large for " "frame received on %s", hardware->h_ifname); goto malformed; @@ -252,7 +272,7 @@ cdp_decode(struct lldpd *cfg, char *frame, int s, tlv = (struct cdp_tlv_head *)(frame + f); len = ntohs(tlv->tlv_len) - sizeof(struct cdp_tlv_head); if ((len < 0) || (f + sizeof(struct cdp_tlv_head) + len > s)) { - LLOG_WARNX("incorrect size in CDP TLV header for frame " + LLOG_WARNX("incorrect size in CDP/FDP TLV header for frame " "received on %s", hardware->h_ifname); goto malformed; @@ -276,7 +296,7 @@ cdp_decode(struct lldpd *cfg, char *frame, int s, break; case CDP_TLV_ADDRESSES: if (len < 4) { - LLOG_WARNX("incorrect size in CDP TLV header for frame " + LLOG_WARNX("incorrect size in CDP/FDP TLV header for frame " "received on %s", hardware->h_ifname); goto malformed; @@ -332,6 +352,12 @@ cdp_decode(struct lldpd *cfg, char *frame, int s, f += len; break; case CDP_TLV_CAPABILITIES: + if (fdp) { + /* Capabilities are ignored with FDP */ + f += sizeof(struct cdp_tlv_head) + len; + chassis->c_cap_enabled = chassis->c_cap_available = LLDP_CAP_BRIDGE; + break; + } f += sizeof(struct cdp_tlv_head); if (len != 4) { LLOG_WARNX("incorrect size for capabilities TLV " @@ -361,7 +387,7 @@ cdp_decode(struct lldpd *cfg, char *frame, int s, f += len; break; default: - LLOG_DEBUG("unknown CDP TLV type (%d) received on %s", + LLOG_DEBUG("unknown CDP/FDP TLV type (%d) received on %s", ntohs(tlv->tlv_type), hardware->h_ifname); f += sizeof(struct cdp_tlv_head) + len; hardware->h_rx_unrecognized_cnt++; @@ -402,7 +428,7 @@ cdp_decode(struct lldpd *cfg, char *frame, int s, (port->p_descr == NULL) || (chassis->c_ttl == 0) || (chassis->c_cap_enabled == 0)) { - LLOG_WARNX("some mandatory tlv are missing for frame received on %s", + LLOG_WARNX("some mandatory CDP/FDP tlv are missing for frame received on %s", hardware->h_ifname); goto malformed; } @@ -436,6 +462,13 @@ cdpv2_send(struct lldpd *global, struct lldpd_chassis *chassis, return cdp_send(global, chassis, hardware, 2); } +int +fdp_send(struct lldpd *global, struct lldpd_chassis *chassis, + struct lldpd_hardware *hardware) +{ + return cdp_send(global, chassis, hardware, 0); +} + int cdp_guess(char *frame, int len, int version) { diff --git a/src/cdp.h b/src/cdp.h index c18ebdf6..8694e679 100644 --- a/src/cdp.h +++ b/src/cdp.h @@ -20,7 +20,11 @@ #define CDP_MULTICAST_ADDR { \ 0x01, 0x00, 0x0c, 0xcc, 0xcc, 0xcc \ } +#define FDP_MULTICAST_ADDR { \ + 0x01, 0xe0, 0x52, 0xcc, 0xcc, 0xcc, \ +} #define LLC_ORG_CISCO { 0x00, 0x00, 0x0c } +#define LLC_ORG_FOUNDRY { 0x00, 0xe0, 0x52 } #define LLC_PID_CDP 0x2000 /* Other protocols */ #define LLC_PID_DRIP 0x102 diff --git a/src/lldpd.c b/src/lldpd.c index 10fa5425..48fb4836 100644 --- a/src/lldpd.c +++ b/src/lldpd.c @@ -67,6 +67,15 @@ void lldpd_iface_multicast(struct lldpd *, const char *, int); { 0x6, 0, 0, 0x0000ffff }, \ { 0x6, 0, 0, 0x00000000 }, struct sock_filter lldpd_filter_lldp_f[] = { LLDPD_FILTER_LLDP_F }; +/* "ether dst 01:e0:52:cc:cc:cc" */ +#define LLDPD_FILTER_FDP_F \ + { 0x20, 0, 0, 0x00000002 }, \ + { 0x15, 0, 3, 0x52cccccc }, \ + { 0x28, 0, 0, 0x00000000 }, \ + { 0x15, 0, 1, 0x000001e0 }, \ + { 0x6, 0, 0, 0x0000ffff }, \ + { 0x6, 0, 0, 0x00000000 }, +struct sock_filter lldpd_filter_fdp_f[] = { LLDPD_FILTER_FDP_F }; /* "ether dst 01:00:0c:cc:cc:cc" */ #define LLDPD_FILTER_CDP_F \ { 0x20, 0, 0, 0x00000002 }, \ @@ -100,15 +109,18 @@ struct sock_filter lldpd_filter_edp_f[] = { LLDPD_FILTER_EDP_F }; { 0x20, 0, 0, 0x00000002 }, \ { 0x15, 0, 2, 0xc200000e }, \ { 0x28, 0, 0, 0x00000000 }, \ - { 0x15, 8, 9, 0x00000180 }, \ + { 0x15, 11, 12, 0x00000180 }, \ { 0x20, 0, 0, 0x00000002 }, \ { 0x15, 0, 2, 0x2b000000 }, \ { 0x28, 0, 0, 0x00000000 }, \ - { 0x15, 4, 5, 0x000000e0 }, \ + { 0x15, 7, 8, 0x000000e0 }, \ { 0x15, 1, 0, 0x0ccccccc }, \ - { 0x15, 0, 3, 0x81000100 }, \ + { 0x15, 0, 2, 0x81000100 }, \ + { 0x28, 0, 0, 0x00000000 }, \ + { 0x15, 3, 4, 0x00000100 }, \ + { 0x15, 0, 3, 0x52cccccc }, \ { 0x28, 0, 0, 0x00000000 }, \ - { 0x15, 0, 1, 0x00000100 }, \ + { 0x15, 0, 1, 0x000001e0 }, \ { 0x6, 0, 0, 0x0000ffff }, \ { 0x6, 0, 0, 0x00000000 }, struct sock_filter lldpd_filter_any_f[] = { LLDPD_FILTER_ANY_F }; @@ -125,6 +137,8 @@ struct protocol protos[] = SONMP_MULTICAST_ADDR, lldpd_filter_sonmp_f, sizeof(lldpd_filter_sonmp_f) }, { LLDPD_MODE_EDP, 0, "EDP", 'e', edp_send, edp_decode, NULL, EDP_MULTICAST_ADDR, lldpd_filter_edp_f, sizeof(lldpd_filter_edp_f) }, + { LLDPD_MODE_FDP, 0, "FDP", 'f', fdp_send, cdp_decode, NULL, + FDP_MULTICAST_ADDR, lldpd_filter_fdp_f, sizeof(lldpd_filter_fdp_f) }, { 0, 0, "any", ' ', NULL, NULL, NULL, {0,0,0,0,0,0}, lldpd_filter_any_f, sizeof(lldpd_filter_any_f) } }; @@ -149,9 +163,9 @@ usage(void) { extern const char *__progname; #ifndef USE_SNMP - fprintf(stderr, "usage: %s [-d] [-v] [-c] [-s] [-e] [-p|-P] [-m ip]\n", __progname); + fprintf(stderr, "usage: %s [-dvcse] [-p|-P] [-m ip]\n", __progname); #else /* USE_SNMP */ - fprintf(stderr, "usage: %s [-d] [-v] [-c] [-s] [-e] [-p|-P] [-m ip] [-x]\n", __progname); + fprintf(stderr, "usage: %s [-dvcsex] [-p|-P] [-m ip]\n", __progname); #endif /* USE_SNMP */ exit(1); } diff --git a/src/lldpd.h b/src/lldpd.h index 38e6d4fe..d5ecf8ba 100644 --- a/src/lldpd.h +++ b/src/lldpd.h @@ -111,6 +111,7 @@ struct lldpd_hardware { #define LLDPD_MODE_CDPV2 3 #define LLDPD_MODE_SONMP 4 #define LLDPD_MODE_EDP 5 +#define LLDPD_MODE_FDP 6 int h_mode; int h_flags; @@ -247,6 +248,7 @@ int lldp_decode(PROTO_DECODE_SIG); /* cdp.c */ int cdpv1_send(PROTO_SEND_SIG); int cdpv2_send(PROTO_SEND_SIG); +int fdp_send(PROTO_SEND_SIG); int cdp_decode(PROTO_DECODE_SIG); int cdpv1_guess(PROTO_GUESS_SIG); int cdpv2_guess(PROTO_GUESS_SIG);