]> git.ipfire.org Git - thirdparty/lldpd.git/commitdiff
Allow to set LLDP-MED network policy TLV from lldpctl.
authorVincent Bernat <bernat@luffy.cx>
Wed, 24 Mar 2010 21:57:30 +0000 (22:57 +0100)
committerVincent Bernat <bernat@luffy.cx>
Wed, 24 Mar 2010 22:10:54 +0000 (23:10 +0100)
Patch from Philipp Kempgen. This adds a "-P" option to lldpctl that
can be repeated several times.

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

index 416b63a6db1c1c6584fff7f745137e758d9581b0..16221ea736ce90326ae695a6f966556ebec85641 100644 (file)
@@ -23,6 +23,7 @@
 .Nm
 .Op Fl d
 .Op Fl L Ar location
+.Op Fl P Ar policy
 .Op Ar interface ...
 .Sh DESCRIPTION
 The
@@ -149,6 +150,101 @@ and the second argument is the ELIN number.
 When setting a location for a given port, all previous locations are
 erased. To erase all location, just use the empty string. There is
 currently no way to get the location from the command line.
+.Pp
+.It Fl P Ar policy
+Enable the transmission of LLDP-MED Network Policy TLVs for the given
+interfaces. This option can be repeated several times to specify
+different policies. Format (without spaces!):
+.Pp
+.Em App-Type
+:
+.Ar U
+:
+.Ar T
+:
+.Ar VLAN-ID
+:
+.Ar L2-Prio
+:
+.Ar DSCP
+.Bl -tag -width "XX"
+.It Ar App-Type
+Valid application types (see ANSI/TIA-1057 table 12):
+.Bl -tag -width "X." -compact
+.It Sy 1
+Voice
+.It Sy 2
+Voice Signaling
+.It Sy 3
+Guest Voice
+.It Sy 4
+Guest Voice Signaling
+.It Sy 5
+Softphone Voice
+.It Sy 6
+Video Conferencing
+.It Sy 7
+Streaming Video
+.It Sy 8
+Video Signaling
+.El
+.It Ar U
+Unknown Policy Flag.
+.Bl -tag -width "X." -compact
+.It Sy 0
+Network policy for the specified application type is defined.
+.It Sy 1
+Network policy for the specified application type is required by
+the device but is currently unknown. This is used by Endpoint
+Devices, not by Network Connectivity Devices.
+.El
+.It Ar T
+Tagged Flag.
+.Bl -tag -width "X." -compact
+.It Sy 0
+Untagged VLAN. In this case the VLAN ID and the Layer 2 Priority
+are ignored and only the DSCP value has relevance.
+.It Sy 1
+Tagged VLAN.
+.El
+.It Ar VLAN-ID
+IEEE 802.1q VLAN ID (VID). A value of 1 through 4094 defines a
+VLAN ID. A value of 0 means that only the priority level is
+significant.
+.It Ar L2-Prio
+IEEE 802.1d / IEEE 802.1p Layer 2 Priority, also known as Class of Service
+(CoS), to be used for the specified application type.
+.Bl -tag -width "X." -compact
+.It Sy 1
+Background
+.It Sy 2
+Spare
+.It Sy 0
+Best Effort (default)
+.It Sy 3
+Excellent Effort
+.It Sy 4
+Controlled Load
+.It Sy 5
+Video
+.It Sy 6
+Voice
+.It Sy 7
+Network Control
+.El
+.It Ar DSCP
+DiffServ/Differentiated Services Code Point (DSCP) value as defined
+in IETF RFC 2474 for the specified application type. Value: 0 (default
+per RFC 2475) through 63. Note: The class selector DSCP values are
+backwards compatible for devices that only support the old IP
+precedence Type of Service (ToS) format. (See the RFCs for what
+these values mean.)
+.It Examples:
+.Bl -tag -width "X." -compact
+.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)
 .El
 .Sh FILES
 .Bl -tag -width "/var/run/lldpd.socketXX" -compact
index 4b7d466c4fe65c3169846074f5b76a210ae855b2..7ee48e15d1a0560dfc43319a302be424383722a1 100644 (file)
@@ -24,6 +24,7 @@ static struct client_handle client_handles[] = {
        { HMSG_GET_CHASSIS, client_handle_port_related },
 #ifdef ENABLE_LLDPMED
        { HMSG_SET_LOCATION, client_handle_port_related },
+       { HMSG_SET_POLICY, client_handle_port_related },
 #endif
 #ifdef ENABLE_DOT1
        { HMSG_GET_VLANS, client_handle_port_related },
@@ -166,6 +167,35 @@ client_handle_port_related(struct lldpd *cfg, struct hmsg *r, struct hmsg *s)
                                }
                                hardware->h_lport.p_med_cap_enabled |= LLDPMED_CAP_LOCATION;
                                break;
+                       case HMSG_SET_POLICY:
+                               p = (char*)&r->data + IFNAMSIZ;
+                               for (i=0; i < LLDPMED_APPTYPE_LAST; i++) {
+                                       hardware->h_lport.p_med_policy[i].type     = 0;
+                                       hardware->h_lport.p_med_policy[i].unknown  = 0;
+                                       hardware->h_lport.p_med_policy[i].tagged   = 0;
+                                       hardware->h_lport.p_med_policy[i].vid      = 0;
+                                       hardware->h_lport.p_med_policy[i].priority = 0;
+                                       hardware->h_lport.p_med_policy[i].dscp     = 0;
+                               }
+                               if (ctl_msg_unpack_structure(
+                                       STRUCT_LLDPD_MED_POLICY
+                                       STRUCT_LLDPD_MED_POLICY
+                                       STRUCT_LLDPD_MED_POLICY
+                                       STRUCT_LLDPD_MED_POLICY
+                                       STRUCT_LLDPD_MED_POLICY
+                                       STRUCT_LLDPD_MED_POLICY
+                                       STRUCT_LLDPD_MED_POLICY
+                                       STRUCT_LLDPD_MED_POLICY,
+                                       hardware->h_lport.p_med_policy,
+                                       8*sizeof(struct lldpd_med_policy),
+                                       r, &p) == -1) {
+                                       LLOG_WARNX("unable to set network policy for %s", ifname);
+                                       s->hdr.len = -1;
+                                       return;
+                               }
+                               hardware->h_lport.p_med_cap_enabled |=
+                                       LLDPMED_CAP_POLICY;
+                               break;
 #endif
                        case HMSG_GET_NB_PORTS:
                                p = &s->data;
index 6fc74933a4cc55fb53284ed82db41b984dcfb9d8..2bb9e2ee10790318825753c019c0dbe1e005c6c8 100644 (file)
@@ -256,6 +256,26 @@ lldp_send(struct lldpd *global,
                                        goto toobig;
                        }
                }
+
+               /* LLDP-MED network policy */
+               for (i = 0; i < LLDPMED_APPTYPE_LAST; i++) {
+                       if (port->p_med_policy[i].type == i + 1) {
+                               if (!(
+                                     POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
+                                     POKE_BYTES(med, sizeof(med)) &&
+                                     POKE_UINT8(LLDP_TLV_MED_POLICY) &&
+                                     POKE_UINT32((
+                                       ((port->p_med_policy[i].type     %(1<< 8))<<24) |
+                                       ((port->p_med_policy[i].unknown  %(1<< 1))<<23) |
+                                       ((port->p_med_policy[i].tagged   %(1<< 1))<<22) |
+                                     /*((0                              %(1<< 1))<<21) |*/
+                                       ((port->p_med_policy[i].vid      %(1<<12))<< 9) |
+                                       ((port->p_med_policy[i].priority %(1<< 3))<< 6) |
+                                       ((port->p_med_policy[i].dscp     %(1<< 6))<< 0) )) &&
+                                     POKE_END_LLDP_TLV))
+                                       goto toobig;
+                       }
+               }
        }
 #endif
 
index 869d7d58ae948c15c8c0639130c5beb1a08c55c2..33111cfb9135be2c7ab92b38bbc0d035576969a5 100644 (file)
@@ -54,6 +54,9 @@ usage(void)
        fprintf(stderr, "-L location Enable the transmission of LLDP-MED location TLV for the\n");
        fprintf(stderr, "            given interfaces. Can be repeated to enable the transmission\n");
        fprintf(stderr, "            of the location in several formats.\n");
+       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");
 #endif
 
        fprintf(stderr, "\n");
@@ -247,6 +250,106 @@ invalid_location:
        return -1;
 }
 
+static int
+lldpd_parse_policy(struct lldpd_port *port, const char *policy)
+{
+       const char *e;
+       int app_type            = 0;
+       int unknown_policy_flag = 0;
+       int tagged_flag         = 0;
+       int vlan_id             = 0;
+       int l2_prio             = 0;
+       int dscp                = 0;
+
+       if (strlen(policy) == 0) {
+               return 0;
+       }
+
+       e = policy;
+
+       /* Application Type: */
+       app_type = atoi(e);
+       if (app_type < 1 || app_type > LLDPMED_APPTYPE_LAST) {
+               LLOG_WARNX("Application Type (%u) out of range.", app_type);
+               goto invalid_policy;
+       }
+
+       /* Unknown Policy Flag (U): */
+       if ((e = strchr(e, ':')) == NULL) {
+               LLOG_WARNX("Expected Unknown Policy Flag (U).");
+               goto invalid_policy;
+       }
+       e = e + 1;
+       unknown_policy_flag = atoi(e);
+       if (unknown_policy_flag < 0 || unknown_policy_flag > 1) {
+               LLOG_WARNX("Unknown Policy Flag (%u) out of range.", unknown_policy_flag);
+               goto invalid_policy;
+       }
+
+       /* Tagged Flag (T): */
+       if ((e = strchr(e, ':')) == NULL) {
+               LLOG_WARNX("Expected Tagged Flag (T).");
+               goto invalid_policy;
+       }
+       e = e + 1;
+       tagged_flag = atoi(e);
+       if (tagged_flag < 0 || tagged_flag > 1) {
+               LLOG_WARNX("Tagged Flag (%u) out of range.", tagged_flag);
+               goto invalid_policy;
+       }
+
+       /* VLAN-ID (VID): */
+       if ((e = strchr(e, ':')) == NULL) {
+               LLOG_WARNX("Expected VLAN ID (VID).");
+               goto invalid_policy;
+       }
+       e = e + 1;
+       vlan_id = atoi(e);
+       if (vlan_id < 0 || vlan_id > 4094) {
+               LLOG_WARNX("VLAN ID (%u) out of range.", vlan_id);
+               goto invalid_policy;
+       }
+
+       /* Layer 2 Priority: */
+       if ((e = strchr(e, ':')) == NULL) {
+               LLOG_WARNX("Expected Layer 2 Priority.");
+               goto invalid_policy;
+       }
+       e = e + 1;
+       l2_prio = atoi(e);
+       if (l2_prio < 0 || l2_prio > 7) {
+               LLOG_WARNX("Layer 2 Priority (%u) out of range.", l2_prio);
+               goto invalid_policy;
+       }
+
+       /* DSCP value: */
+       if ((e = strchr(e, ':')) == NULL) {
+               LLOG_WARNX("Expected DSCP value.");
+               goto invalid_policy;
+       }
+       e = e + 1;
+       dscp = atoi(e);
+       if (dscp < 0 || dscp > 63) {
+               LLOG_WARNX("DSCP value (%u) out of range.", dscp);
+               goto invalid_policy;
+       }
+
+       port->p_med_policy[app_type - 1].type     = (u_int8_t)  app_type;
+       port->p_med_policy[app_type - 1].unknown  = (u_int8_t)  unknown_policy_flag;
+       port->p_med_policy[app_type - 1].tagged   = (u_int8_t)  tagged_flag;
+       port->p_med_policy[app_type - 1].vid      = (u_int16_t) vlan_id;
+       port->p_med_policy[app_type - 1].priority = (u_int8_t)  l2_prio;
+       port->p_med_policy[app_type - 1].dscp     = (u_int8_t)  dscp;
+
+       port->p_med_cap_enabled |= LLDPMED_CAP_POLICY;
+       return 0;
+
+invalid_policy:
+       LLOG_WARNX("The format of the policy is invalid (%s)",
+               policy);
+       return -1;
+}
+
 static void
 set_location(int s, int argc, char *argv[])
 {
@@ -301,6 +404,68 @@ set_location(int s, int argc, char *argv[])
                LLOG_INFO("Location set succesfully for %s", iff->name);
        }
 }
+
+static void
+set_policy(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, "dP:")) != -1) {
+               switch (ch) {
+               case 'P':
+                       if ((lldpd_parse_policy(&port, optarg)) == -1)
+                               fatalx("Incorrect Network Policy.");
+                       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_POLICY);
+               strlcpy((char *)&h->data, iff->name, IFNAMSIZ);
+               h->hdr.len += IFNAMSIZ;
+               p = (char*)&h->data + IFNAMSIZ;
+               if (ctl_msg_pack_structure(
+                       STRUCT_LLDPD_MED_POLICY
+                       STRUCT_LLDPD_MED_POLICY
+                       STRUCT_LLDPD_MED_POLICY
+                       STRUCT_LLDPD_MED_POLICY
+                       STRUCT_LLDPD_MED_POLICY
+                       STRUCT_LLDPD_MED_POLICY
+                       STRUCT_LLDPD_MED_POLICY
+                       STRUCT_LLDPD_MED_POLICY,
+                       port.p_med_policy,
+                       8*sizeof(struct lldpd_med_policy), h, &p) == -1) {
+                       LLOG_WARNX("set_policy: Unable to set Network Policy for %s", iff->name);
+                       fatalx("aborting");
+               }
+               if (ctl_msg_send(s, h) == -1)
+                       fatalx("set_policy: unable to send request");
+               if (ctl_msg_recv(s, h) == -1)
+                       fatalx("set_policy: unable to receive answer");
+               if (h->hdr.type != HMSG_SET_POLICY)
+                       fatalx("set_policy: unknown answer type received");
+               LLOG_INFO("Network Policy successfully set for %s", iff->name);
+       }
+}
 #endif
 
 int
@@ -309,12 +474,13 @@ main(int argc, char *argv[])
        int ch, s, debug = 1;
        char * fmt = "plain";
 #define ACTION_SET_LOCATION 1
+#define ACTION_SET_POLICY   2
        int action = 0;
        
        /*
         * Get and parse command line options
         */
-       while ((ch = getopt(argc, argv, "hdf:L:")) != -1) {
+       while ((ch = getopt(argc, argv, "hdf:L:P:")) != -1) {
                switch (ch) {
                case 'h':
                        usage();
@@ -331,6 +497,14 @@ main(int argc, char *argv[])
 #else
                        fprintf(stderr, "LLDP-MED support is not built-in\n");
                        usage();
+#endif
+                       break;
+               case 'P':
+#ifdef ENABLE_LLDPMED
+                       action = ACTION_SET_POLICY;
+#else
+                       fprintf(stderr, "LLDP-MED support is not built-in\n");
+                       usage();
 #endif
                        break;
                default:
@@ -352,6 +526,9 @@ main(int argc, char *argv[])
        case ACTION_SET_LOCATION:
                set_location(s, argc, argv);
                break;
+       case ACTION_SET_POLICY:
+               set_policy(s, argc, argv);
+               break;
 #endif
        default:
                display_interfaces(s, fmt, argc, argv);
index 96ef8d6fb1c1a2d919fef12fb126efbec9f25274..51305e7c3319155c70c13dc72524269056a963ad 100644 (file)
@@ -319,6 +319,7 @@ enum hmsg_type {
        HMSG_GET_CHASSIS,
        HMSG_GET_VLANS,
        HMSG_SET_LOCATION,
+       HMSG_SET_POLICY,
        HMSG_SHUTDOWN
 };