]> git.ipfire.org Git - thirdparty/lldpd.git/commitdiff
Allow to set LLDP-MED POE-MDI TLV from lldpctl.
authorVincent Bernat <bernat@luffy.cx>
Fri, 26 Mar 2010 23:55:02 +0000 (00:55 +0100)
committerVincent Bernat <bernat@luffy.cx>
Sat, 3 Apr 2010 21:10:24 +0000 (23:10 +0200)
This adds a "-O" option to lldpctl.

man/lldpctl.8
src/client.c
src/lldp.c
src/lldp.h
src/lldpctl.c
src/lldpd.h

index 16221ea736ce90326ae695a6f966556ebec85641..2ff5c426cc1b5df75a21c5efb546d434fc4dfd05 100644 (file)
@@ -24,6 +24,7 @@
 .Op Fl d
 .Op Fl L Ar location
 .Op Fl P Ar policy
+.Op Fl O Ar poe
 .Op Ar interface ...
 .Sh DESCRIPTION
 The
@@ -244,7 +245,79 @@ these values mean.)
 .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
index 7ee48e15d1a0560dfc43319a302be424383722a1..3f39feb8039a65b10da8ecf465a11dd5392a6ba9 100644 (file)
@@ -25,6 +25,7 @@ static struct client_handle client_handles[] = {
 #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 },
@@ -196,6 +197,33 @@ client_handle_port_related(struct lldpd *cfg, struct hmsg *r, struct hmsg *s)
                                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;
index 4d9be3e27fcd4fcfebc278b932d2adb9afab785e..35633008e1542e2a796dcadbf16d47d52bd446a2 100644 (file)
@@ -276,6 +276,45 @@ lldp_send(struct lldpd *global,
                                        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
 
@@ -670,27 +709,13 @@ lldp_decode(struct lldpd *cfg, char *frame, int s,
                                                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:
index 76f091b37502c6fa58d25bbe02258a977a0e3ce5..f1b5f947e2b5688d90653bf1bcf5f3bd2dfbb47e 100644 (file)
@@ -205,10 +205,10 @@ enum {
 #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
index 316ce4a3d5830cf10b61923c606349746cc71a4a..7e7107930673b7b0c308f2889f052acda310cf2c 100644 (file)
@@ -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:"
+#define LLDPCTL_ARGS "hdf:L:P:O:"
 
 static void
 usage(void)
@@ -59,6 +59,8 @@ 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");
@@ -352,6 +354,106 @@ invalid_policy:
        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[])
 {
@@ -468,6 +570,60 @@ set_policy(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
@@ -477,6 +633,7 @@ main(int argc, char *argv[])
        char * fmt = "plain";
 #define ACTION_SET_LOCATION (1 << 0)
 #define ACTION_SET_POLICY   (1 << 1)
+#define ACTION_SET_POWER    (1 << 2)
        int action = 0;
        
        /*
@@ -494,16 +651,14 @@ main(int argc, char *argv[])
                        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();
@@ -528,6 +683,8 @@ main(int argc, char *argv[])
                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);
index 331691b97f886f37e8b0497384afed6d7fae9edb..947307b75285fa362ae09942a83aedf6f996d556 100644 (file)
@@ -325,6 +325,7 @@ enum hmsg_type {
        HMSG_GET_VLANS,
        HMSG_SET_LOCATION,
        HMSG_SET_POLICY,
+       HMSG_SET_POWER,
        HMSG_SHUTDOWN
 };