This adds a "-O" option to lldpctl.
.Op Fl d
.Op Fl L Ar location
.Op Fl P Ar policy
+.Op Fl O Ar poe
.Op Ar interface ...
.Sh DESCRIPTION
The
.It Sy 1:0:1:500:6:46
Voice (1): not unknown (0), tagged (1), VLAN-ID 500, l2 prio Voice (6), DSCP 46 (EF, Expedited Forwarding)
.It Sy 2:0:1:500:3:24
-Voice Signaling (2): not unknown (0), tagged (1), VLAN-ID 500, l2 prio Excellent Effort (3), DSCP 24 (CS3, Class Selector 3)
+Voice Signaling (2): not unknown (0), tagged (1), VLAN-ID 500, l2 prio
+Excellent Effort (3), DSCP 24 (CS3, Class Selector 3)
+.El
+.El
+.Pp
+.It Fl O Ar poe
+Enable the transmission of LLDP-MED POE-MDI TLV for the given
+interfaces. One can act as a PD (power consumer) or a PSE (power
+provider). No check is done on the validity of the parameters while
+LLDP-MED requires some restrictions:
+.Bl -bullet
+.It
+PD shall never request more power than physical 802.3af class.
+.It
+PD shall never draw more than the maximum power advertised by PSE.
+.It
+PSE shall not reduce power allocated to PD when this power is in use.
+.It
+PSE may request reduced power using conservation mode
+.El
+.Pp
+The format of this option is (without spaces):
+.Pp
+.Em type
+:
+.Ar source
+:
+.Ar priority
+:
+.Ar value
+:
+.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 source
+Valid sources are:
+.Bl -tag -width "X." -compact
+.It Sy 0
+Unknown
+.It Sy 1
+For PD, the power source is the PSE. For PSE, the power source is the
+primary power source.
+.It Sy 2
+For PD, the power source is a local source. For PSE, the power source
+is the backup power source or a power conservation mode is asked (the
+PSE may be running on UPS for example).
+.It Sy 3
+For PD, the power source is both the PSE and a local source. For PSE,
+this value should not be used.
+.El
+.It Ar priority
+Four priorities are available:
+.Bl -tag -width "X." -compact
+.It Sy 0
+Unknown priority
+.It Sy 1
+Critical
+.It Sy 2
+High
+.It Sy 3
+Low
+.El
+.It Ar value
+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
.El
.Sh FILES
.Bl -tag -width "/var/run/lldpd.socketXX" -compact
#ifdef ENABLE_LLDPMED
{ HMSG_SET_LOCATION, client_handle_port_related },
{ HMSG_SET_POLICY, client_handle_port_related },
+ { HMSG_SET_POWER, client_handle_port_related },
#endif
#ifdef ENABLE_DOT1
{ HMSG_GET_VLANS, client_handle_port_related },
hardware->h_lport.p_med_cap_enabled |=
LLDPMED_CAP_POLICY;
break;
+ case HMSG_SET_POWER:
+ p = (char*)&r->data + IFNAMSIZ;
+ memset(&hardware->h_lport.p_med_power, 0,
+ sizeof(struct lldpd_med_power));
+ if (ctl_msg_unpack_structure(STRUCT_LLDPD_MED_POWER,
+ &hardware->h_lport.p_med_power,
+ sizeof(struct lldpd_med_power),
+ r, &p) == -1) {
+ LLOG_WARNX("unable to set POE-MDI for %s",
+ ifname);
+ s->hdr.len = -1;
+ return;
+ }
+ hardware->h_lport.p_med_cap_enabled &= ~(
+ LLDPMED_CAP_MDI_PD | LLDPMED_CAP_MDI_PSE);
+ switch (hardware->h_lport.p_med_power.devicetype)
+ {
+ case LLDPMED_POW_TYPE_PSE:
+ hardware->h_lport.p_med_cap_enabled |=
+ LLDPMED_CAP_MDI_PSE;
+ break;
+ case LLDPMED_POW_TYPE_PD:
+ hardware->h_lport.p_med_cap_enabled |=
+ LLDPMED_CAP_MDI_PD;
+ break;
+ }
+ break;
#endif
case HMSG_GET_NB_PORTS:
p = &s->data;
goto toobig;
}
}
+
+ /* LLDP-MED POE-MDI */
+ if ((port->p_med_power.devicetype == LLDPMED_POW_TYPE_PSE) ||
+ (port->p_med_power.devicetype == LLDPMED_POW_TYPE_PD)) {
+ int devicetype = 0, source = 0;
+ if (!(
+ POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
+ POKE_BYTES(med, sizeof(med)) &&
+ POKE_UINT8(LLDP_TLV_MED_MDI)))
+ goto toobig;
+ switch (port->p_med_power.devicetype) {
+ case LLDPMED_POW_TYPE_PSE:
+ devicetype = 0;
+ switch (port->p_med_power.source) {
+ case LLDPMED_POW_SOURCE_PRIMARY: source = 1; break;
+ case LLDPMED_POW_SOURCE_BACKUP: source = 2; break;
+ case LLDPMED_POW_SOURCE_RESERVED: source = 3; break;
+ default: source = 0; break;
+ }
+ break;
+ case LLDPMED_POW_TYPE_PD:
+ devicetype = 1;
+ switch (port->p_med_power.source) {
+ case LLDPMED_POW_SOURCE_PSE: source = 1; break;
+ case LLDPMED_POW_SOURCE_LOCAL: source = 2; break;
+ case LLDPMED_POW_SOURCE_BOTH: source = 3; break;
+ default: source = 0; break;
+ }
+ break;
+ }
+ if (!(
+ POKE_UINT8((
+ ((devicetype %(1<< 2))<<6) |
+ ((source %(1<< 2))<<4) |
+ ((port->p_med_power.priority %(1<< 4))<<0) )) &&
+ POKE_UINT16(port->p_med_power.val) &&
+ POKE_END_LLDP_TLV))
+ goto toobig;
+ }
}
#endif
port->p_med_power.devicetype =
LLDPMED_POW_TYPE_RESERVED;
}
- switch (power & 0x0F) {
- case 0x0:
+ if (((power & 0x0F) < 0) ||
+ ((power & 0x0F) > LLDPMED_POW_PRIO_LOW))
port->p_med_power.priority =
LLDPMED_POW_PRIO_UNKNOWN;
- break;
- case 0x1:
- port->p_med_power.priority =
- LLDPMED_POW_PRIO_CRITICAL;
- break;
- case 0x2:
- port->p_med_power.priority =
- LLDPMED_POW_PRIO_HIGH;
- break;
- case 0x3:
+ else
port->p_med_power.priority =
- LLDPMED_POW_PRIO_LOW;
- break;
- default:
- port->p_med_power.priority =
- LLDPMED_POW_PRIO_UNKNOWN;
- }
+ power & 0x0F;
port->p_med_power.val = PEEK_UINT16;
break;
case LLDP_TLV_MED_IV_HW:
#define LLDPMED_POW_SOURCE_LOCAL 6
#define LLDPMED_POW_SOURCE_BOTH 7
-#define LLDPMED_POW_PRIO_UNKNOWN 1
-#define LLDPMED_POW_PRIO_CRITICAL 2
-#define LLDPMED_POW_PRIO_HIGH 3
-#define LLDPMED_POW_PRIO_LOW 4
+#define LLDPMED_POW_PRIO_UNKNOWN 0
+#define LLDPMED_POW_PRIO_CRITICAL 1
+#define LLDPMED_POW_PRIO_HIGH 2
+#define LLDPMED_POW_PRIO_LOW 3
#define LLDPMED_CAP_CAP 0x01
#define LLDPMED_CAP_POLICY 0x02
extern void
display_interfaces(int s, const char * fmt, int argc, char *argv[]);
-#define LLDPCTL_ARGS "hdf:L:P:"
+#define LLDPCTL_ARGS "hdf:L:P:O:"
static void
usage(void)
fprintf(stderr, "-P policy Enable the transmission of LLDP-MED Network Policy TLVs\n");
fprintf(stderr, " for the given interfaces. Can be repeated to specify\n");
fprintf(stderr, " different policies.\n");
+ fprintf(stderr, "-O poe Enable the trabsmission of LLDP-MED POE-MDI TLV\n");
+ fprintf(stderr, " for the given interfaces.\n");
#endif
fprintf(stderr, "\n");
return -1;
}
+static int
+lldpd_parse_power(struct lldpd_port *port, const char *poe)
+{
+ const char *e;
+ int device_type = 0;
+ int source = 0;
+ int priority = 0;
+ int val = 0;
+
+ if (strlen(poe) == 0)
+ return 0;
+ e = poe;
+
+ /* Device type */
+ if (!strncmp(e, "PD", 2))
+ device_type = LLDPMED_POW_TYPE_PD;
+ else if (!strncmp(e, "PSE", 3))
+ device_type = LLDPMED_POW_TYPE_PSE;
+ else {
+ LLOG_WARNX("Device type should be either 'PD' or 'PSE'.");
+ goto invalid_poe;
+ }
+
+ /* Source */
+ if ((e = strchr(e, ':')) == NULL) {
+ LLOG_WARNX("Expected power source.");
+ goto invalid_poe;
+ }
+ source = atoi(++e);
+ if (source < 0 || source > 3) {
+ LLOG_WARNX("Power source out of range (%d).", source);
+ goto invalid_poe;
+ }
+
+ /* Priority */
+ if ((e = strchr(e, ':')) == NULL) {
+ LLOG_WARNX("Expected power priority.");
+ goto invalid_poe;
+ }
+ priority = atoi(++e);
+ if (priority < 0 || priority > 3) {
+ LLOG_WARNX("Power priority out of range (%d).", priority);
+ goto invalid_poe;
+ }
+
+ /* Value */
+ if ((e = strchr(e, ':')) == NULL) {
+ LLOG_WARNX("Expected power value.");
+ goto invalid_poe;
+ }
+ val = atoi(++e);
+ if (val < 0 || val > 1023) {
+ LLOG_WARNX("Power value out of range (%d).", val);
+ goto invalid_poe;
+ }
+
+ port->p_med_power.devicetype = device_type;
+ port->p_med_power.priority = priority;
+ port->p_med_power.val = val;
+
+ switch (device_type) {
+ case LLDPMED_POW_TYPE_PD:
+ switch (source) {
+ case 1:
+ port->p_med_power.source = LLDPMED_POW_SOURCE_PSE;
+ break;
+ case 2:
+ port->p_med_power.source = LLDPMED_POW_SOURCE_LOCAL;
+ break;
+ case 3:
+ port->p_med_power.source = LLDPMED_POW_SOURCE_BOTH;
+ break;
+ default:
+ port->p_med_power.source = LLDPMED_POW_SOURCE_UNKNOWN;
+ break;
+ }
+ port->p_med_cap_enabled |= LLDPMED_CAP_MDI_PD;
+ break;
+ case LLDPMED_POW_TYPE_PSE:
+ switch (source) {
+ case 1:
+ port->p_med_power.source = LLDPMED_POW_SOURCE_PRIMARY;
+ break;
+ case 2:
+ port->p_med_power.source = LLDPMED_POW_SOURCE_BACKUP;
+ break;
+ default:
+ port->p_med_power.source = LLDPMED_POW_SOURCE_UNKNOWN;
+ break;
+ }
+ port->p_med_cap_enabled |= LLDPMED_CAP_MDI_PSE;
+ break;
+ }
+ return 0;
+
+ invalid_poe:
+ LLOG_WARNX("The format POE-MDI is invalid (%s)", poe);
+ return -1;
+}
+
static void
set_location(int s, int argc, char *argv[])
{
LLOG_INFO("Network Policy successfully set for %s", iff->name);
}
}
+
+static void
+set_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_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_POWER);
+ strlcpy((char *)&h->data, iff->name, IFNAMSIZ);
+ h->hdr.len += IFNAMSIZ;
+ p = (char*)&h->data + IFNAMSIZ;
+ if (ctl_msg_pack_structure(STRUCT_LLDPD_MED_POWER,
+ &port.p_med_power,
+ sizeof(struct lldpd_med_power), h, &p) == -1) {
+ LLOG_WARNX("set_power: Unable to set POE-MDI for %s", iff->name);
+ fatalx("aborting");
+ }
+ if (ctl_msg_send(s, h) == -1)
+ fatalx("set_power: unable to send request");
+ if (ctl_msg_recv(s, h) == -1)
+ fatalx("set_power: unable to receive answer");
+ if (h->hdr.type != HMSG_SET_POWER)
+ fatalx("set_power: unknown answer type received");
+ LLOG_INFO("POE-MDI successfully set for %s", iff->name);
+ }
+}
#endif
int
char * fmt = "plain";
#define ACTION_SET_LOCATION (1 << 0)
#define ACTION_SET_POLICY (1 << 1)
+#define ACTION_SET_POWER (1 << 2)
int action = 0;
/*
fmt = optarg;
break;
case 'L':
-#ifdef ENABLE_LLDPMED
- action |= ACTION_SET_LOCATION;
-#else
- fprintf(stderr, "LLDP-MED support is not built-in\n");
- usage();
-#endif
- break;
case 'P':
+ case 'O':
#ifdef ENABLE_LLDPMED
- action |= ACTION_SET_POLICY;
+ switch (ch) {
+ case 'L': action |= ACTION_SET_LOCATION; break;
+ case 'P': action |= ACTION_SET_POLICY; break;
+ case 'O': action |= ACTION_SET_POWER; break;
+ }
#else
fprintf(stderr, "LLDP-MED support is not built-in\n");
usage();
set_location(s, argc, argv);
if (action & ACTION_SET_POLICY)
set_policy(s, argc, argv);
+ if (action & ACTION_SET_POWER)
+ set_power(s, argc, argv);
#endif
if (!action)
display_interfaces(s, fmt, argc, argv);
HMSG_GET_VLANS,
HMSG_SET_LOCATION,
HMSG_SET_POLICY,
+ HMSG_SET_POWER,
HMSG_SHUTDOWN
};