From: Vincent Bernat Date: Sat, 8 May 2010 17:52:53 +0000 (+0200) Subject: Allow to set Dot3 POE-MDI TLV from lldpctl. X-Git-Tag: 0.5.4~12 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=42ee7382e54a0b348db7ba7e1c304143b1417ed1;p=thirdparty%2Flldpd.git Allow to set Dot3 POE-MDI TLV from lldpctl. Also add SNMP support for lldpXdot3LocPowerTable. --- diff --git a/man/lldpctl.8 b/man/lldpctl.8 index d83f43d4..c1f3ccd6 100644 --- a/man/lldpctl.8 +++ b/man/lldpctl.8 @@ -25,6 +25,7 @@ .Op Fl L Ar location .Op Fl P Ar policy .Op Fl O Ar poe +.Op Fl o Ar poe .Op Ar interface ... .Sh DESCRIPTION The @@ -277,6 +278,10 @@ same applies for PD and power priority. LLDP-MED MIB does not allow this kind of representation. .El .Pp +This option is distinct of +.Fl o +option. You may want to use both options at the same time. +.Pp The format of this option is (without spaces): .Pp .Em type @@ -286,7 +291,6 @@ The format of this option is (without spaces): .Ar priority : .Ar value -: .Bl -tag -width "XX" .It Ar type Valid types are: @@ -329,6 +333,74 @@ For PD, the power value is the total power in tenth of watts required by a PD device from the PSE device. This value should range from 0 to 1023 tenth of watts. .El +.It Fl o Ar poe +Enable the transmission of Dot3 POE-MDI TLV for the given +interfaces. One can act as a PD (power consumer) or a PSE (power +provider). This option is distinct of the +.Fl O +option. You might want to use both. Contrary to LLDP-MED POE-MDI TLV, +Dot3 POE-MDI TLV are strictly per-port values. +.Pp +The format of this option is (without spaces): +.Pp +.Em type +: +.Ar supported +: +.Ar enabled +: +.Ar paircontrol +: +.Ar powerpairs +: +.Ar class +.Bl -tag -width "XX" +.It Ar type +Valid types are: +.Bl -tag -width "XXX." -compact +.It Sy PSE +Power Sourcing Entity (power provider) +.It Sy PD +Power Device (power consumer) +.El +.It Ar powerpairs +Valid sources are: +.Bl -tag -width "X." -compact +.It Sy 1 +The signal pairs only are in use. +.It Sy 2 +The spare pairs only are in use. +.El +.It Ar class +Five classes are available: +.Bl -tag -width "X." -compact +.It Sy 1 +class 0 +.It Sy 2 +class 1 +.It Sy 3 +class 2 +.It Sy 4 +class 3 +.It Sy 5 +class 4 +.It Sy 0 +no class +.El +.El +.Pp +.Ar supported , +.Ar enabled +and +.Ar paircontrol +can be set to to 0 or 1. +.Ar supported +means that MDI power is supported on the given port. +.Ar enabled +means that MDI power is enabled on the given port. +.Ar paircontrol +is used to indicate if the pair selection can be controlled on the +given port. .El .Sh FILES .Bl -tag -width "/var/run/lldpd.socketXX" -compact diff --git a/src/agent.c b/src/agent.c index 660a27e4..882bb00b 100644 --- a/src/agent.c +++ b/src/agent.c @@ -401,7 +401,13 @@ header_tprvindexed_table(struct variable *vp, oid *name, size_t *length, #define LLDP_SNMP_LOCAL_DOT3_AGG_STATUS 9 #define LLDP_SNMP_LOCAL_DOT3_AGG_ID 10 #define LLDP_SNMP_LOCAL_DOT3_MFS 11 -#define LLDP_SNMP_LOCAL_DOT1_PVID 12 +#define LLDP_SNMP_LOCAL_DOT3_POWER_DEVICETYPE 12 +#define LLDP_SNMP_LOCAL_DOT3_POWER_SUPPORT 13 +#define LLDP_SNMP_LOCAL_DOT3_POWER_ENABLED 14 +#define LLDP_SNMP_LOCAL_DOT3_POWER_PAIRCONTROL 15 +#define LLDP_SNMP_LOCAL_DOT3_POWER_PAIRS 16 +#define LLDP_SNMP_LOCAL_DOT3_POWER_CLASS 17 +#define LLDP_SNMP_LOCAL_DOT1_PVID 18 /* Remote ports */ #define LLDP_SNMP_REMOTE_CIDSUBTYPE 1 #define LLDP_SNMP_REMOTE_CID 2 @@ -1088,6 +1094,43 @@ agent_h_local_port(struct variable *vp, oid *name, size_t *length, case LLDP_SNMP_LOCAL_DOT3_MFS: long_ret = hardware->h_lport.p_mfs; return (u_char *)&long_ret; + case LLDP_SNMP_LOCAL_DOT3_POWER_DEVICETYPE: + if (hardware->h_lport.p_power.devicetype) { + long_ret = (hardware->h_lport.p_power.devicetype == + LLDP_DOT3_POWER_PSE)?1:2; + return (u_char *)&long_ret; + } + break; + case LLDP_SNMP_LOCAL_DOT3_POWER_SUPPORT: + if (hardware->h_lport.p_power.devicetype) { + long_ret = (hardware->h_lport.p_power.supported)?1:2; + return (u_char *)&long_ret; + } + break; + case LLDP_SNMP_LOCAL_DOT3_POWER_ENABLED: + if (hardware->h_lport.p_power.devicetype) { + long_ret = (hardware->h_lport.p_power.enabled)?1:2; + return (u_char *)&long_ret; + } + break; + case LLDP_SNMP_LOCAL_DOT3_POWER_PAIRCONTROL: + if (hardware->h_lport.p_power.devicetype) { + long_ret = (hardware->h_lport.p_power.paircontrol)?1:2; + return (u_char *)&long_ret; + } + break; + case LLDP_SNMP_LOCAL_DOT3_POWER_PAIRS: + if (hardware->h_lport.p_power.devicetype) { + long_ret = hardware->h_lport.p_power.pairs; + return (u_char *)&long_ret; + } + break; + case LLDP_SNMP_LOCAL_DOT3_POWER_CLASS: + if (hardware->h_lport.p_power.devicetype && hardware->h_lport.p_power.class) { + long_ret = hardware->h_lport.p_power.class; + return (u_char *)&long_ret; + } + break; #endif #ifdef ENABLE_DOT1 case LLDP_SNMP_LOCAL_DOT1_PVID: @@ -1097,7 +1140,10 @@ agent_h_local_port(struct variable *vp, oid *name, size_t *length, default: break; } - return NULL; + if (!exact && (name[*length-1] < MAX_SUBID)) + return agent_h_local_port(vp, name, length, + exact, var_len, write_method); + return NULL; } #ifdef ENABLE_DOT1 @@ -1383,6 +1429,18 @@ static struct variable8 lldp_vars[] = { {1, 5, 4623, 1, 2, 1, 1, 3}}, {LLDP_SNMP_LOCAL_DOT3_AUTONEG_MAU, ASN_INTEGER, RONLY, agent_h_local_port, 8, {1, 5, 4623, 1, 2, 1, 1, 4}}, + {LLDP_SNMP_LOCAL_DOT3_POWER_DEVICETYPE, ASN_INTEGER, RONLY, agent_h_local_port, 8, + {1, 5, 4623, 1, 2, 2, 1, 1}}, + {LLDP_SNMP_LOCAL_DOT3_POWER_SUPPORT, ASN_INTEGER, RONLY, agent_h_local_port, 8, + {1, 5, 4623, 1, 2, 2, 1, 2}}, + {LLDP_SNMP_LOCAL_DOT3_POWER_ENABLED, ASN_INTEGER, RONLY, agent_h_local_port, 8, + {1, 5, 4623, 1, 2, 2, 1, 3}}, + {LLDP_SNMP_LOCAL_DOT3_POWER_PAIRCONTROL, ASN_INTEGER, RONLY, agent_h_local_port, 8, + {1, 5, 4623, 1, 2, 2, 1, 4}}, + {LLDP_SNMP_LOCAL_DOT3_POWER_PAIRS, ASN_INTEGER, RONLY, agent_h_local_port, 8, + {1, 5, 4623, 1, 2, 2, 1, 5}}, + {LLDP_SNMP_LOCAL_DOT3_POWER_CLASS, ASN_INTEGER, RONLY, agent_h_local_port, 8, + {1, 5, 4623, 1, 2, 2, 1, 6}}, {LLDP_SNMP_LOCAL_DOT3_AGG_STATUS, ASN_OCTET_STR, RONLY, agent_h_local_port, 8, {1, 5, 4623, 1, 2, 3, 1, 1}}, {LLDP_SNMP_LOCAL_DOT3_AGG_ID, ASN_INTEGER, RONLY, agent_h_local_port, 8, diff --git a/src/client.c b/src/client.c index 93a35168..8d87f018 100644 --- a/src/client.c +++ b/src/client.c @@ -27,6 +27,9 @@ static struct client_handle client_handles[] = { { HMSG_SET_POLICY, client_handle_port_related }, { HMSG_SET_POWER, client_handle_port_related }, #endif +#ifdef ENABLE_DOT3 + { HMSG_SET_DOT3_POWER, client_handle_port_related }, +#endif #ifdef ENABLE_DOT1 { HMSG_GET_VLANS, client_handle_port_related }, #endif @@ -224,6 +227,22 @@ client_handle_port_related(struct lldpd *cfg, struct hmsg *r, struct hmsg *s) break; } break; +#endif +#ifdef ENABLE_DOT3 + case HMSG_SET_DOT3_POWER: + p = (char*)&r->data + IFNAMSIZ; + memset(&hardware->h_lport.p_power, 0, + sizeof(struct lldpd_dot3_power)); + if (ctl_msg_unpack_structure(STRUCT_LLDPD_DOT3_POWER, + &hardware->h_lport.p_power, + sizeof(struct lldpd_dot3_power), + r, &p) == -1) { + LLOG_WARNX("unable to set POE-MDI for %s", + ifname); + s->hdr.len = -1; + return; + } + break; #endif case HMSG_GET_NB_PORTS: p = &s->data; diff --git a/src/lldp.c b/src/lldp.c index d58f579b..b48b4759 100644 --- a/src/lldp.c +++ b/src/lldp.c @@ -198,6 +198,22 @@ lldp_send(struct lldpd *global, POKE_UINT16(port->p_mfs) && POKE_END_LLDP_TLV)) goto toobig; + /* Power */ + if (port->p_power.devicetype) { + if (!( + POKE_START_LLDP_TLV(LLDP_TLV_ORG) && + POKE_BYTES(dot3, sizeof(dot3)) && + POKE_UINT8(LLDP_TLV_DOT3_POWER) && + POKE_UINT8(( + (((2 - port->p_power.devicetype) %(1<< 1))<<0) | + (( port->p_power.supported %(1<< 1))<<1) | + (( port->p_power.enabled %(1<< 1))<<2) | + (( port->p_power.paircontrol %(1<< 1))<<3))) && + POKE_UINT8(port->p_power.pairs) && + POKE_UINT8(port->p_power.class) && + POKE_END_LLDP_TLV)) + goto toobig; + } #endif #ifdef ENABLE_LLDPMED diff --git a/src/lldpctl.c b/src/lldpctl.c index 49b490ce..91bcd158 100644 --- a/src/lldpctl.c +++ b/src/lldpctl.c @@ -41,7 +41,7 @@ get_interfaces(int s, struct interfaces *ifs); extern void display_interfaces(int s, const char * fmt, int argc, char *argv[]); -#define LLDPCTL_ARGS "hdf:L:P:O:" +#define LLDPCTL_ARGS "hdf:L:P:O:o:" static void usage(void) @@ -62,6 +62,10 @@ usage(void) fprintf(stderr, "-O poe Enable the trabsmission of LLDP-MED POE-MDI TLV\n"); fprintf(stderr, " for the given interfaces.\n"); #endif +#ifdef ENABLE_DOT3 + fprintf(stderr, "-o poe Enable the trabsmission of Dot3 POE-MDI TLV\n"); + fprintf(stderr, " for the given interfaces.\n"); +#endif fprintf(stderr, "\n"); @@ -453,7 +457,104 @@ lldpd_parse_power(struct lldpd_port *port, const char *poe) LLOG_WARNX("The format POE-MDI is invalid (%s)", poe); return -1; } +#endif + +#ifdef ENABLE_DOT3 +static int +lldpd_parse_dot3_power(struct lldpd_port *port, const char *poe) +{ + const char *e; + int device_type = 0; + int supported = 0; + int enabled = 0; + int paircontrol = 0; + int powerpairs = 0; + int class = 0; + + if (strlen(poe) == 0) + return 0; + e = poe; + /* Device type */ + if (!strncmp(e, "PD", 2)) + device_type = LLDP_DOT3_POWER_PD; + else if (!strncmp(e, "PSE", 3)) + device_type = LLDP_DOT3_POWER_PSE; + else { + LLOG_WARNX("Device type should be either 'PD' or 'PSE'."); + goto invalid_dot3_poe; + } + + /* Supported */ + if ((e = strchr(e, ':')) == NULL) { + LLOG_WARNX("Expected power support."); + goto invalid_dot3_poe; + } + supported = atoi(++e); + if (supported < 0 || supported > 1) { + LLOG_WARNX("Power support should be 1 or 0, not %d", supported); + goto invalid_dot3_poe; + } + + /* Enabled */ + if ((e = strchr(e, ':')) == NULL) { + LLOG_WARNX("Expected power ability."); + goto invalid_dot3_poe; + } + enabled = atoi(++e); + if (enabled < 0 || enabled > 1) { + LLOG_WARNX("Power ability should be 1 or 0, not %d", enabled); + goto invalid_dot3_poe; + } + + /* Pair control */ + if ((e = strchr(e, ':')) == NULL) { + LLOG_WARNX("Expected power pair control ability."); + goto invalid_dot3_poe; + } + paircontrol = atoi(++e); + if (paircontrol < 0 || paircontrol > 1) { + LLOG_WARNX("Power pair control ability should be 1 or 0, not %d", paircontrol); + goto invalid_dot3_poe; + } + + /* Power pairs */ + if ((e = strchr(e, ':')) == NULL) { + LLOG_WARNX("Expected power pairs."); + goto invalid_dot3_poe; + } + powerpairs = atoi(++e); + if (powerpairs < 1 || powerpairs > 2) { + LLOG_WARNX("Power pairs should be 1 or 2, not %d.", powerpairs); + goto invalid_dot3_poe; + } + + /* Class */ + if ((e = strchr(e, ':')) == NULL) { + LLOG_WARNX("Expected power class."); + goto invalid_dot3_poe; + } + class = atoi(++e); + if (class < 0 || class > 5) { + LLOG_WARNX("Power class out of range (%d).", class); + goto invalid_dot3_poe; + } + + port->p_power.devicetype = device_type; + port->p_power.supported = supported; + port->p_power.enabled = enabled; + port->p_power.paircontrol = paircontrol; + port->p_power.pairs = powerpairs; + port->p_power.class = class; + return 0; + + invalid_dot3_poe: + LLOG_WARNX("The format POE-MDI is invalid (%s)", poe); + return -1; +} +#endif + +#ifdef ENABLE_LLDPMED static void set_location(int s, int argc, char *argv[]) { @@ -626,6 +727,62 @@ set_power(int s, int argc, char *argv[]) } #endif +#ifdef ENABLE_DOT3 +static void +set_dot3_power(int s, int argc, char *argv[]) +{ + int i, ch; + struct interfaces ifs; + struct lldpd_interface *iff; + struct lldpd_port port; + void *p; + struct hmsg *h; + + if ((h = (struct hmsg *)malloc(MAX_HMSGSIZE)) == NULL) + fatal(NULL); + + memset(&port, 0, sizeof(struct lldpd_port)); + optind = 1; + while ((ch = getopt(argc, argv, LLDPCTL_ARGS)) != -1) { + switch (ch) { + case 'o': + if ((lldpd_parse_dot3_power(&port, optarg)) == -1) + fatalx("Incorrect POE-MDI."); + break; + } + } + + get_interfaces(s, &ifs); + TAILQ_FOREACH(iff, &ifs, next) { + if (optind < argc) { + for (i = optind; i < argc; i++) + if (strncmp(argv[i], iff->name, IFNAMSIZ) == 0) + break; + if (i == argc) + continue; + } + + ctl_msg_init(h, HMSG_SET_DOT3_POWER); + strlcpy((char *)&h->data, iff->name, IFNAMSIZ); + h->hdr.len += IFNAMSIZ; + p = (char*)&h->data + IFNAMSIZ; + if (ctl_msg_pack_structure(STRUCT_LLDPD_DOT3_POWER, + &port.p_power, + sizeof(struct lldpd_dot3_power), h, &p) == -1) { + LLOG_WARNX("set_dot3_power: Unable to set POE-MDI for %s", iff->name); + fatalx("aborting"); + } + if (ctl_msg_send(s, h) == -1) + fatalx("set_dot3_power: unable to send request"); + if (ctl_msg_recv(s, h) == -1) + fatalx("set_dot3_power: unable to receive answer"); + if (h->hdr.type != HMSG_SET_DOT3_POWER) + fatalx("set_dot3_power: unknown answer type received"); + LLOG_INFO("Dot3 POE-MDI successfully set for %s", iff->name); + } +} +#endif + int main(int argc, char *argv[]) { @@ -634,6 +791,7 @@ main(int argc, char *argv[]) #define ACTION_SET_LOCATION (1 << 0) #define ACTION_SET_POLICY (1 << 1) #define ACTION_SET_POWER (1 << 2) +#define ACTION_SET_DOT3_POWER (1 << 3) int action = 0; /* @@ -662,6 +820,14 @@ main(int argc, char *argv[]) #else fprintf(stderr, "LLDP-MED support is not built-in\n"); usage(); +#endif + break; + case 'o': +#ifdef ENABLE_DOT3 + action |= ACTION_SET_DOT3_POWER; +#else + fprintf(stderr, "Dot3 support is not built-in\n"); + usage(); #endif break; default: @@ -685,6 +851,10 @@ main(int argc, char *argv[]) set_policy(s, argc, argv); if (action & ACTION_SET_POWER) set_power(s, argc, argv); +#endif +#ifdef ENABLE_DOT3 + if (action & ACTION_SET_DOT3_POWER) + set_dot3_power(s, argc, argv); #endif if (!action) display_interfaces(s, fmt, argc, argv); diff --git a/src/lldpd.h b/src/lldpd.h index f93478e8..20770bc2 100644 --- a/src/lldpd.h +++ b/src/lldpd.h @@ -364,6 +364,7 @@ enum hmsg_type { HMSG_SET_LOCATION, HMSG_SET_POLICY, HMSG_SET_POWER, + HMSG_SET_DOT3_POWER, HMSG_SHUTDOWN };