This includes send and receive support as well as SNMP support.
802.3at seems to not define OID that should be used as well as the
mapping for bit values. Therefore, the implementation is a wild guess
of what is consistent with 802.1ab.
+ Allow to set LLDP-MED network policy from lldpctl, thanks to a patch from
Philipp Kempgen.
+ Allow to set LLDP-MED POE-MDI from lldpctl.
- + Handle Dot3 POE-MDI TLV (802.3af).
+ + Handle Dot3 POE-MDI TLV (802.3af and 802.3at).
+ Allow to set Dot3 POE-MDI from lldpctl.
+ Add a summary of available options in "lldpd -h" and "lldpctl -h",
thanks to a patch from Jorge Boncompte.
.Ar powerpairs
:
.Ar class
+[ :
+.Ar powertype
+:
+.Ar source
+:
+.Ar priority
+:
+.Ar requested
+:
+.Ar allocated
+]
.Bl -tag -width "XX"
.It Ar type
Valid types are:
.Ar paircontrol
is used to indicate if the pair selection can be controlled on the
given port.
+.Pp
+.Ar powertype ,
+.Ar source ,
+.Ar priority
+(and remaining values) are optional. They are only requested in
+conformance with 802.3at.
+.Ar type
+should be either 1 or 2. For the possible values of the next two
+fields, see the possible values of
+.Ar source
+and
+.Ar priority
+for LLDP-MED MDI/POE.
+.Ar requested
+and
+.Ar allocated
+are respectively the PD requested power value and the PSE allocated
+power value. This should be expressed in tenth of watts from 1 to 255.
.El
.Sh FILES
.Bl -tag -width "/var/run/lldpd.socketXX" -compact
#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
+#define LLDP_SNMP_LOCAL_DOT3_POWER_TYPE 18
+#define LLDP_SNMP_LOCAL_DOT3_POWER_SOURCE 19
+#define LLDP_SNMP_LOCAL_DOT3_POWER_PRIORITY 20
+#define LLDP_SNMP_LOCAL_DOT3_POWER_REQUESTED 21
+#define LLDP_SNMP_LOCAL_DOT3_POWER_ALLOCATED 22
+#define LLDP_SNMP_LOCAL_DOT1_PVID 23
/* Remote ports */
#define LLDP_SNMP_REMOTE_CIDSUBTYPE 1
#define LLDP_SNMP_REMOTE_CID 2
#define LLDP_SNMP_REMOTE_DOT3_POWER_PAIRCONTROL 20
#define LLDP_SNMP_REMOTE_DOT3_POWER_PAIRS 21
#define LLDP_SNMP_REMOTE_DOT3_POWER_CLASS 22
-#define LLDP_SNMP_REMOTE_DOT1_PVID 23
+#define LLDP_SNMP_REMOTE_DOT3_POWER_TYPE 23
+#define LLDP_SNMP_REMOTE_DOT3_POWER_SOURCE 24
+#define LLDP_SNMP_REMOTE_DOT3_POWER_PRIORITY 25
+#define LLDP_SNMP_REMOTE_DOT3_POWER_REQUESTED 26
+#define LLDP_SNMP_REMOTE_DOT3_POWER_ALLOCATED 27
+#define LLDP_SNMP_REMOTE_DOT1_PVID 28
/* Local vlans */
#define LLDP_SNMP_LOCAL_DOT1_VLANNAME 1
/* Remote vlans */
return (u_char *)&long_ret;
}
break;
+ case LLDP_SNMP_LOCAL_DOT3_POWER_TYPE:
+ if (hardware->h_lport.p_power.devicetype &&
+ hardware->h_lport.p_power.powertype != LLDP_DOT3_POWER_8023AT_OFF) {
+ *var_len = 1;
+ bit = (((hardware->h_lport.p_power.powertype ==
+ LLDP_DOT3_POWER_8023AT_TYPE1)?1:0) << 7) |
+ (((hardware->h_lport.p_power.devicetype ==
+ LLDP_DOT3_POWER_PSE)?0:1) << 6);
+ return (u_char *)&bit;
+ }
+ break;
+ case LLDP_SNMP_LOCAL_DOT3_POWER_SOURCE:
+ if (hardware->h_lport.p_power.devicetype &&
+ hardware->h_lport.p_power.powertype != LLDP_DOT3_POWER_8023AT_OFF) {
+ *var_len = 1;
+ bit = swap_bits(hardware->h_lport.p_power.source%(1<<2));
+ return (u_char *)&bit;
+ }
+ break;
+ case LLDP_SNMP_LOCAL_DOT3_POWER_PRIORITY:
+ if (hardware->h_lport.p_power.devicetype &&
+ hardware->h_lport.p_power.powertype != LLDP_DOT3_POWER_8023AT_OFF) {
+ long_ret = hardware->h_lport.p_power.priority;
+ return (u_char *)&long_ret;
+ }
+ break;
+ case LLDP_SNMP_LOCAL_DOT3_POWER_REQUESTED:
+ if (hardware->h_lport.p_power.devicetype &&
+ hardware->h_lport.p_power.powertype != LLDP_DOT3_POWER_8023AT_OFF) {
+ long_ret = hardware->h_lport.p_power.requested;
+ return (u_char *)&long_ret;
+ }
+ break;
+ case LLDP_SNMP_LOCAL_DOT3_POWER_ALLOCATED:
+ if (hardware->h_lport.p_power.devicetype &&
+ hardware->h_lport.p_power.powertype != LLDP_DOT3_POWER_8023AT_OFF) {
+ long_ret = hardware->h_lport.p_power.allocated;
+ return (u_char *)&long_ret;
+ }
+ break;
#endif
#ifdef ENABLE_DOT1
case LLDP_SNMP_LOCAL_DOT1_PVID:
return (u_char *)&long_ret;
}
break;
+ case LLDP_SNMP_REMOTE_DOT3_POWER_TYPE:
+ if (port->p_power.devicetype &&
+ port->p_power.powertype != LLDP_DOT3_POWER_8023AT_OFF) {
+ *var_len = 1;
+ bit = (((port->p_power.powertype ==
+ LLDP_DOT3_POWER_8023AT_TYPE1)?1:0) << 7) |
+ (((port->p_power.devicetype ==
+ LLDP_DOT3_POWER_PSE)?0:1) << 6);
+ return (u_char *)&bit;
+ }
+ break;
+ case LLDP_SNMP_REMOTE_DOT3_POWER_SOURCE:
+ if (port->p_power.devicetype &&
+ port->p_power.powertype != LLDP_DOT3_POWER_8023AT_OFF) {
+ *var_len = 1;
+ bit = swap_bits(port->p_power.source%(1<<2));
+ return (u_char *)&bit;
+ }
+ break;
+ case LLDP_SNMP_REMOTE_DOT3_POWER_PRIORITY:
+ if (port->p_power.devicetype &&
+ port->p_power.powertype != LLDP_DOT3_POWER_8023AT_OFF) {
+ long_ret = port->p_power.priority;
+ return (u_char *)&long_ret;
+ }
+ break;
+ case LLDP_SNMP_REMOTE_DOT3_POWER_REQUESTED:
+ if (port->p_power.devicetype &&
+ port->p_power.powertype != LLDP_DOT3_POWER_8023AT_OFF) {
+ long_ret = port->p_power.requested;
+ return (u_char *)&long_ret;
+ }
+ break;
+ case LLDP_SNMP_REMOTE_DOT3_POWER_ALLOCATED:
+ if (port->p_power.devicetype &&
+ port->p_power.powertype != LLDP_DOT3_POWER_8023AT_OFF) {
+ long_ret = port->p_power.allocated;
+ return (u_char *)&long_ret;
+ }
+ break;
#endif
#ifdef ENABLE_DOT1
case LLDP_SNMP_REMOTE_DOT1_PVID:
{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_POWER_TYPE, ASN_OCTET_STR, RONLY, agent_h_local_port, 8,
+ {1, 5, 4623, 1, 2, 2, 1, 7}},
+ {LLDP_SNMP_LOCAL_DOT3_POWER_SOURCE, ASN_OCTET_STR, RONLY, agent_h_local_port, 8,
+ {1, 5, 4623, 1, 2, 2, 1, 8}},
+ {LLDP_SNMP_LOCAL_DOT3_POWER_PRIORITY, ASN_INTEGER, RONLY, agent_h_local_port, 8,
+ {1, 5, 4623, 1, 2, 2, 1, 9}},
+ {LLDP_SNMP_LOCAL_DOT3_POWER_REQUESTED, ASN_INTEGER, RONLY, agent_h_local_port, 8,
+ {1, 5, 4623, 1, 2, 2, 1, 10}},
+ {LLDP_SNMP_LOCAL_DOT3_POWER_ALLOCATED, ASN_INTEGER, RONLY, agent_h_local_port, 8,
+ {1, 5, 4623, 1, 2, 2, 1, 11}},
{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,
{1, 5, 4623, 1, 3, 2, 1, 5}},
{LLDP_SNMP_REMOTE_DOT3_POWER_CLASS, ASN_INTEGER, RONLY, agent_h_remote_port, 8,
{1, 5, 4623, 1, 3, 2, 1, 6}},
+ {LLDP_SNMP_REMOTE_DOT3_POWER_TYPE, ASN_OCTET_STR, RONLY, agent_h_remote_port, 8,
+ {1, 5, 4623, 1, 3, 2, 1, 7}},
+ {LLDP_SNMP_REMOTE_DOT3_POWER_SOURCE, ASN_OCTET_STR, RONLY, agent_h_remote_port, 8,
+ {1, 5, 4623, 1, 3, 2, 1, 8}},
+ {LLDP_SNMP_REMOTE_DOT3_POWER_PRIORITY, ASN_INTEGER, RONLY, agent_h_remote_port, 8,
+ {1, 5, 4623, 1, 3, 2, 1, 9}},
+ {LLDP_SNMP_REMOTE_DOT3_POWER_REQUESTED, ASN_INTEGER, RONLY, agent_h_remote_port, 8,
+ {1, 5, 4623, 1, 3, 2, 1, 10}},
+ {LLDP_SNMP_REMOTE_DOT3_POWER_ALLOCATED, ASN_INTEGER, RONLY, agent_h_remote_port, 8,
+ {1, 5, 4623, 1, 3, 2, 1, 11}},
{LLDP_SNMP_REMOTE_DOT3_AGG_STATUS, ASN_OCTET_STR, RONLY, agent_h_remote_port, 8,
{1, 5, 4623, 1, 3, 3, 1, 1}},
{LLDP_SNMP_REMOTE_DOT3_AGG_ID, ASN_INTEGER, RONLY, agent_h_remote_port, 8,
{ 5, "class 4" },
{ 0, NULL }
};
+
+static const struct value_string port_dot3_power_pse_source_map[] = {
+ { LLDP_DOT3_POWER_SOURCE_BOTH, "PSE + Local" },
+ { LLDP_DOT3_POWER_SOURCE_PSE, "PSE" },
+ { 0, NULL }
+};
+
+static const struct value_string port_dot3_power_pd_source_map[] = {
+ { LLDP_DOT3_POWER_SOURCE_BACKUP, "Backup source" },
+ { LLDP_DOT3_POWER_SOURCE_PRIMARY, "Primary power source" },
+ { 0, NULL }
+};
+
+static const struct value_string port_dot3_power_priority_map[] = {
+ { LLDPMED_POW_PRIO_CRITICAL, "critical" },
+ { LLDPMED_POW_PRIO_HIGH, "high" },
+ { LLDPMED_POW_PRIO_LOW, "low" },
+ { 0, NULL },
+};
#endif
static const struct value_string chassis_capability_map[] = {
tag_data(w, map_lookup(port_dot3_power_class_map,
port->p_power.class));
tag_end(w);
+
+ /* 802.3at */
+ if (port->p_power.powertype != LLDP_DOT3_POWER_8023AT_OFF) {
+ tag_start(w, "power-type", "Power type");
+ tag_data(w, u2str(port->p_power.powertype));
+ tag_end(w);
+
+ tag_start(w, "source", "Power Source");
+ tag_data(w, map_lookup(
+ (port->p_power.devicetype == LLDP_DOT3_POWER_PSE)?
+ port_dot3_power_pse_source_map:
+ port_dot3_power_pd_source_map,
+ port->p_power.source));
+ tag_end(w);
+
+ tag_start(w, "priority", "Power Priority");
+ tag_data(w, map_lookup(port_dot3_power_priority_map,
+ port->p_power.priority));
+ tag_end(w);
+
+ tag_start(w, "requested", "PD requested power Value");
+ tag_data(w, u2str(port->p_power.requested * 100));
+ tag_end(w);
+
+ tag_start(w, "allocated", "PSE allocated power Value");
+ tag_data(w, u2str(port->p_power.allocated * 100));
+ tag_end(w);
+ }
+
tag_end(w);
}
#endif
(( 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))
+ POKE_UINT8(port->p_power.class)))
+ goto toobig;
+ /* 802.3at */
+ if (port->p_power.powertype != LLDP_DOT3_POWER_8023AT_OFF) {
+ if (!(
+ POKE_UINT8((
+ (((port->p_power.powertype ==
+ LLDP_DOT3_POWER_8023AT_TYPE1)?1:0) << 7) |
+ (((port->p_power.devicetype ==
+ LLDP_DOT3_POWER_PSE)?0:1) << 6) |
+ ((port->p_power.source %(1<< 2))<<4) |
+ ((port->p_power.priority %(1<< 2))<<0))) &&
+ POKE_UINT16(port->p_power.requested) &&
+ POKE_UINT16(port->p_power.allocated)))
+ goto toobig;
+ }
+ if (!(POKE_END_LLDP_TLV))
goto toobig;
}
#endif
LLDP_DOT3_POWER_PSE:LLDP_DOT3_POWER_PD;
port->p_power.pairs = PEEK_UINT8;
port->p_power.class = PEEK_UINT8;
+ /* 802.3at? */
+ if (tlv_size >= 12) {
+ port->p_power.powertype = PEEK_UINT8;
+ port->p_power.source =
+ (port->p_power.powertype & (1<<5 | 1<<4)) >> 4;
+ port->p_power.priority =
+ (port->p_power.powertype & (1<<1 | 1<<0));
+ port->p_power.powertype =
+ (port->p_power.powertype & (1<<7))?
+ LLDP_DOT3_POWER_8023AT_TYPE1:
+ LLDP_DOT3_POWER_8023AT_TYPE2;
+ port->p_power.requested = PEEK_UINT16;
+ port->p_power.allocated = PEEK_UINT16;
+ } else
+ port->p_power.powertype =
+ LLDP_DOT3_POWER_8023AT_OFF;
break;
default:
/* Unknown Dot3 TLV, ignore it */
#define LLDP_DOT3_POWERPAIRS_SIGNAL 1
#define LLDP_DOT3_POWERPAIRS_SPARE 2
+/* Dot3 Power type (for 802.3at) */
+#define LLDP_DOT3_POWER_8023AT_OFF 0
+#define LLDP_DOT3_POWER_8023AT_TYPE1 1
+#define LLDP_DOT3_POWER_8023AT_TYPE2 2
+
+/* Dot3 power source */
+#define LLDP_DOT3_POWER_SOURCE_UNKNOWN 0
+#define LLDP_DOT3_POWER_SOURCE_PRIMARY 1
+#define LLDP_DOT3_POWER_SOURCE_PSE 1
+#define LLDP_DOT3_POWER_SOURCE_BACKUP 2
+#define LLDP_DOT3_POWER_SOURCE_BOTH 3
+
+/* Dot3 power priority */
+#define LLDP_DOT3_POWER_PRIO_UNKNOWN 0
+#define LLDP_DOT3_POWER_PRIO_CRITICAL 1
+#define LLDP_DOT3_POWER_PRIO_HIGH 2
+#define LLDP_DOT3_POWER_PRIO_LOW 3
+
/* PMD Auto-Negotiation Advertised Capability field, from RFC 3636 */
#define LLDP_DOT3_LINK_AUTONEG_OTHER 0x8000
#define LLDP_DOT3_LINK_AUTONEG_10BASE_T 0x4000
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;
+ struct lldpd_dot3_power target;
if (strlen(poe) == 0)
return 0;
e = poe;
+ memset(&target, 0, sizeof(target));
/* Device type */
if (!strncmp(e, "PD", 2))
- device_type = LLDP_DOT3_POWER_PD;
+ target.devicetype = LLDP_DOT3_POWER_PD;
else if (!strncmp(e, "PSE", 3))
- device_type = LLDP_DOT3_POWER_PSE;
+ target.devicetype = LLDP_DOT3_POWER_PSE;
else {
LLOG_WARNX("Device type should be either 'PD' or 'PSE'.");
goto invalid_dot3_poe;
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);
+ target.supported = atoi(++e);
+ if (target.supported > 1) {
+ LLOG_WARNX("Power support should be 1 or 0, not %d", target.supported);
goto invalid_dot3_poe;
}
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);
+ target.enabled = atoi(++e);
+ if (target.enabled > 1) {
+ LLOG_WARNX("Power ability should be 1 or 0, not %d", target.enabled);
goto invalid_dot3_poe;
}
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);
+ target.paircontrol = atoi(++e);
+ if (target.paircontrol > 1) {
+ LLOG_WARNX("Power pair control ability should be 1 or 0, not %d",
+ target.paircontrol);
goto invalid_dot3_poe;
}
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);
+ target.pairs = atoi(++e);
+ if (target.pairs < 1 || target.pairs > 2) {
+ LLOG_WARNX("Power pairs should be 1 or 2, not %d.", target.pairs);
goto invalid_dot3_poe;
}
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);
+ target.class = atoi(++e);
+ if (target.class > 5) {
+ LLOG_WARNX("Power class out of range (%d).", target.class);
+ goto invalid_dot3_poe;
+ }
+ /* 802.3at */
+ if ((e = strchr(e, ':')) == NULL) {
+ target.powertype = LLDP_DOT3_POWER_8023AT_OFF;
+ goto no8023at;
+ }
+ /* 802.3at: Power type */
+ target.powertype = atoi(++e);
+ if ((target.powertype != LLDP_DOT3_POWER_8023AT_TYPE1) &&
+ (target.powertype != LLDP_DOT3_POWER_8023AT_TYPE2)) {
+ LLOG_WARNX("Incorrect power type (%d).", target.powertype);
+ goto invalid_dot3_poe;
+ }
+ /* 802.3at: Source */
+ if ((e = strchr(e, ':')) == NULL) {
+ LLOG_WARNX("Expected power source.");
+ goto invalid_dot3_poe;
+ }
+ target.source = atoi(++e);
+ if (target.source > 3) {
+ LLOG_WARNX("Power source out of range (%d).", target.source);
+ goto invalid_dot3_poe;
+ }
+ /* 802.3at: priority */
+ if ((e = strchr(e, ':')) == NULL) {
+ LLOG_WARNX("Expected power priority.");
+ goto invalid_dot3_poe;
+ }
+ target.priority = atoi(++e);
+ if (target.priority > 3) {
+ LLOG_WARNX("Power priority out of range (%d).", target.priority);
+ goto invalid_dot3_poe;
+ }
+ /* 802.3at: requested */
+ if ((e = strchr(e, ':')) == NULL) {
+ LLOG_WARNX("Expected requested power value.");
+ goto invalid_dot3_poe;
+ }
+ target.requested = atoi(++e);
+ /* 802.3at: allocated */
+ if ((e = strchr(e, ':')) == NULL) {
+ LLOG_WARNX("Expected allocated power value.");
goto invalid_dot3_poe;
}
+ target.allocated = atoi(++e);
- 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;
+ no8023at:
+ memcpy(&port->p_power, &target, sizeof(target));
return 0;
invalid_dot3_poe:
u_int16_t mau_type;
};
-#define STRUCT_LLDPD_DOT3_POWER "(bbbbbb)"
+#define STRUCT_LLDPD_DOT3_POWER "(bbbbbbbbbww)"
struct lldpd_dot3_power {
u_int8_t devicetype;
u_int8_t supported;
u_int8_t paircontrol;
u_int8_t pairs;
u_int8_t class;
+ u_int8_t powertype; /* If set to LLDP_DOT3_POWER_8023AT_OFF,
+ following fields have no meaning */
+ u_int8_t source;
+ u_int8_t priority;
+ u_int16_t requested;
+ u_int16_t allocated;
};
#endif