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:
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.
.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.
* 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 <errno.h>
{
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;
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,
/* 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;
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);
return 0;
}
+/* cdp_decode also decodes FDP */
int
cdp_decode(struct lldpd *cfg, char *frame, int s,
struct lldpd_hardware *hardware,
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");
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",
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;
}
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;
}
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;
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;
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;
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 "
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++;
(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;
}
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)
{
#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
{ 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 }, \
{ 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 };
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) }
};
{
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);
}
#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;
/* 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);