]> git.ipfire.org Git - thirdparty/lldpd.git/commitdiff
Start support of LLDP-MED: send support is implemented
authorVincent Bernat <vbernat@wanadooportails.com>
Wed, 26 Nov 2008 11:47:12 +0000 (12:47 +0100)
committerVincent Bernat <vbernat@wanadooportails.com>
Wed, 26 Nov 2008 11:47:12 +0000 (12:47 +0100)
configure.ac
man/lldpd.8
src/features.c
src/lldp.c
src/lldp.h
src/lldpd.c
src/lldpd.h
src/priv.c

index db13cb9ccadc3e7b2249e8e6a902b726027da802..806a83bc3c0e3dd6a2f792aceef3e512c792b6fd 100644 (file)
@@ -88,6 +88,7 @@ if test "${with_snmp}" != "no"; then
 fi
 
 # Options
+# CDP
 AC_ARG_ENABLE(cdp, AC_HELP_STRING([--enable-cdp],
                   [Enable Cisco Discovery Protocol]),
              [enable_cdp=$enableval],[enable_cdp=yes])
@@ -99,6 +100,7 @@ else
        AC_MSG_RESULT(no)
 fi
 
+# FDP
 AC_ARG_ENABLE(fdp, AC_HELP_STRING([--enable-fdp],
                   [Enable Foundry Discovery Protocol]),
              [enable_fdp=$enableval],[enable_fdp=yes])
@@ -110,6 +112,7 @@ else
        AC_MSG_RESULT(no)
 fi
 
+# EDP
 AC_ARG_ENABLE(edp, AC_HELP_STRING([--enable-edp],
                   [Enable Extreme Discovery Protocol]),
              [enable_edp=$enableval],[enable_edp=yes])
@@ -121,6 +124,7 @@ else
        AC_MSG_RESULT(no)
 fi
 
+# SONMP
 AC_ARG_ENABLE(sonmp, AC_HELP_STRING([--enable-sonmp],
                   [Enable SynOptics Network Management Protocol]),
              [enable_sonmp=$enableval],[enable_sonmp=yes])
@@ -132,4 +136,16 @@ else
        AC_MSG_RESULT(no)
 fi
 
+#LLDPMED
+AC_ARG_ENABLE(lldpmed, AC_HELP_STRING([--enable-lldpmed],
+                  [Enable LLDP-MED extension]),
+             [enable_lldpmed=$enableval],[enable_lldpmed=yes])
+AC_MSG_CHECKING(whether to enable LLDP-MED)
+if test x$enable_lldpmed = xyes; then
+       AC_MSG_RESULT(yes)
+       AC_DEFINE([ENABLE_LLDPMED],, [Enable LLDP-MED extension])
+else
+       AC_MSG_RESULT(no)
+fi
+
 AC_OUTPUT
index d1fb04b95d561677b4fa5c399a846e63120e3112..701642b5b5ddba1afbb70075f3e5fff0910bb3c2 100644 (file)
@@ -24,6 +24,7 @@
 .Op Fl dvxcse
 .Op Fl m Ar management
 .Op Fl p Ar probe time
+.Op Fl M Ar class
 .Sh DESCRIPTION
 .Nm
 is a daemon able to receive and send
@@ -91,6 +92,18 @@ protocol. This time will be used by
 to detect false positives like SONMP frames running through a switch
 only supporting CDP. This value is only used when multiple protocols
 are enabled.
+.It Fl M Ar class
+Enable emission of LLDP-MED frame. The class should be one of the
+following value:
+.Bl -tag -width "0:XX" -compact
+.It Ar 1
+Generic Endpoint (Class I)
+.It Ar 2
+Media Endpoint (Class II)
+.It Ar 3
+Communication Device Endpoints (Class III)
+.It Ar 4
+Network Connectivity Device
 .El
 .Sh FILES
 .Bl -tag -width "/var/run/lldpd.socketXX" -compact
index af8fdd39325212904f6cbe2633141fc9ad8a1229..bdcaa58b3a79791f4e1472f93b79aa75e7d2e258 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/sockios.h>
 
 #define SYSFS_PATH_MAX 256
-#define SYSFS_CLASS_NET "/sys/class/net/"
 #define MAX_PORTS 1024
 
 /* net/if.h */
@@ -207,3 +206,76 @@ iface_is_enslaved(struct lldpd *cfg, const char *name)
        freeifaddrs(ifap);
        return -1;
 }
+
+#ifdef ENABLE_LLDPMED
+       /* Fill in inventory stuff:
+           - hardware version: /sys/class/dmi/id/product_version
+           - firmware version: /sys/class/dmi/id/bios_version
+           - software version: `uname -r`
+           - serial number: /sys/class/dmi/id/product_serial
+           - manufacturer: /sys/class/dmi/id/sys_vendor
+           - model: /sys/class/dmi/id/product_name
+           - asset: /sys/class/dmi/id/chassis_asset_tag
+       */
+
+char*
+dmi_get(char *file)
+{
+       int dmi, s;
+       char buffer[100];
+       
+       if ((dmi = priv_open(file)) < 0) {
+               LLOG_DEBUG("cannot get DMI file %s", file);
+               return NULL;
+       }
+       memset(buffer, 0, sizeof(buffer));
+       if ((s = read(dmi, buffer, sizeof(buffer))) == -1) {
+               LLOG_DEBUG("cannot read DMI file %s", file);
+               close(dmi);
+               return NULL;
+       }
+       close(dmi);
+       buffer[sizeof(buffer) - 1] = '\0';
+       if ((s > 0) && (buffer[s-1] == '\n'))
+               buffer[s-1] = '\0';
+       if (strlen(buffer))
+               return strdup(buffer);
+       return NULL;
+}
+
+char*
+dmi_hw()
+{
+       return dmi_get(SYSFS_CLASS_DMI "product_version");
+}
+
+char*
+dmi_fw()
+{
+       return dmi_get(SYSFS_CLASS_DMI "bios_version");
+}
+
+char*
+dmi_sn()
+{
+       return dmi_get(SYSFS_CLASS_DMI "product_serial");
+}
+
+char*
+dmi_manuf()
+{
+       return dmi_get(SYSFS_CLASS_DMI "sys_vendor");
+}
+
+char*
+dmi_model()
+{
+       return dmi_get(SYSFS_CLASS_DMI "product_name");
+}
+
+char*
+dmi_asset()
+{
+       return dmi_get(SYSFS_CLASS_DMI "chassis_asset_tag");
+}
+#endif
index 0eb945a4bd26d00282c4d90ad9f15010749226ce..d705a2f0ff173b494e6348f1367f0626e7425cb3 100644 (file)
@@ -45,6 +45,12 @@ lldp_send(struct lldpd *global, struct lldpd_chassis *chassis,
        struct lldp_mgmt mgmt;
        struct lldp_aggreg aggreg;
        struct lldp_macphy macphy;
+#ifdef ENABLE_LLDPMED
+       const u_int8_t med[] = LLDP_TLV_ORG_MED;
+       struct lldpmed_cap medcap;
+       struct lldp_org medhw, medfw, medsw, medsn,
+           medmodel, medasset, medmanuf;
+#endif
        struct lldpd_vlan *vlan;
        struct lldpd_port *port = &hardware->h_lport;
        u_int c = -1, len = 0, v;
@@ -234,6 +240,59 @@ lldp_send(struct lldpd *global, struct lldpd_chassis *chassis,
        iov[c].iov_base = &macphy;
        iov[c].iov_len = sizeof(macphy);
 
+#ifdef ENABLE_LLDPMED
+       if (global->g_lchassis.c_med_cap) {
+               /* LLDP-MED cap */
+               memset(&medcap, 0, sizeof(medcap));
+               medcap.tlv_head.type_len = LLDP_TLV_HEAD(LLDP_TLV_ORG,
+                   sizeof(medcap.tlv_org_id) +
+                   sizeof(medcap.tlv_org_subtype) + 
+                   sizeof(medcap.tlv_cap) + sizeof(medcap.tlv_type));
+               memcpy(medcap.tlv_org_id, med, sizeof(medcap.tlv_org_id));
+               medcap.tlv_org_subtype = LLDP_TLV_MED_CAP;
+               medcap.tlv_cap = htons(global->g_lchassis.c_med_cap);
+               medcap.tlv_type = global->g_lchassis.c_med_type;
+               IOV_NEW;
+               iov[c].iov_base = &medcap;
+               iov[c].iov_len = sizeof(medcap);
+
+               /* LLDP-MED inventory */
+#define LLDP_INVENTORY(value, target, subtype)                         \
+               if (value) {                                            \
+                   memset(&target, 0, sizeof(target));                 \
+                   len = (strlen(value)>32)?32:strlen(value);          \
+                   target.tlv_head.type_len =                          \
+                       LLDP_TLV_HEAD(LLDP_TLV_ORG,                     \
+                           sizeof(target.tlv_org_id) +                 \
+                           sizeof(target.tlv_org_subtype) +            \
+                           len);                                       \
+                   memcpy(target.tlv_org_id, med,                      \
+                       sizeof(target.tlv_org_id));                     \
+                   target.tlv_org_subtype = subtype;                   \
+                   IOV_NEW;                                            \
+                   iov[c].iov_base = &target;                          \
+                   iov[c].iov_len = sizeof(target);                    \
+                   IOV_NEW;                                            \
+                   iov[c].iov_base = value;                            \
+                   iov[c].iov_len = len;                               \
+               }
+               LLDP_INVENTORY(global->g_lchassis.c_med_hw,
+                   medhw, LLDP_TLV_MED_IV_HW);
+               LLDP_INVENTORY(global->g_lchassis.c_med_fw,
+                   medfw, LLDP_TLV_MED_IV_FW);
+               LLDP_INVENTORY(global->g_lchassis.c_med_sw,
+                   medsw, LLDP_TLV_MED_IV_SW);
+               LLDP_INVENTORY(global->g_lchassis.c_med_sn,
+                   medsn, LLDP_TLV_MED_IV_SN);
+               LLDP_INVENTORY(global->g_lchassis.c_med_manuf,
+                   medmanuf, LLDP_TLV_MED_IV_MANUF);
+               LLDP_INVENTORY(global->g_lchassis.c_med_model,
+                   medmodel, LLDP_TLV_MED_IV_MODEL);
+               LLDP_INVENTORY(global->g_lchassis.c_med_asset,
+                   medasset, LLDP_TLV_MED_IV_ASSET);
+       }
+#endif
+
        /* END */
        memset(&end, 0, sizeof(end));
        IOV_NEW;
index 54ef45e033c6e9ebcff270ff4668c4d55da7d88c..a16d26dd35abad754c47c443ee59805c98f20321 100644 (file)
@@ -46,6 +46,7 @@ enum {
 
 #define LLDP_TLV_ORG_DOT1 {0x00, 0x80, 0xc2}
 #define LLDP_TLV_ORG_DOT3 {0x00, 0x12, 0x0f}
+#define LLDP_TLV_ORG_MED {0x00, 0x12, 0xbb}
 
 enum {
        LLDP_TLV_DOT1_PVID              = 1,
@@ -230,4 +231,42 @@ struct lldp_end {
        struct lldp_tlv_head     tlv_head;
 } __attribute__ ((__packed__));
 
+#ifdef ENABLE_LLDPMED
+enum {
+       LLDP_TLV_MED_CAP        = 1,
+       LLDP_TLV_MED_POLICY     = 2,
+       LLDP_TLV_MED_LOCATION   = 3,
+       LLDP_TLV_MED_MDI        = 4,
+       LLDP_TLV_MED_IV_HW      = 5,
+       LLDP_TLV_MED_IV_FW      = 6,
+       LLDP_TLV_MED_IV_SW      = 7,
+       LLDP_TLV_MED_IV_SN      = 8,
+       LLDP_TLV_MED_IV_MANUF   = 9,
+       LLDP_TLV_MED_IV_MODEL   = 10,
+       LLDP_TLV_MED_IV_ASSET   = 11
+};
+
+#define LLDPMED_CLASS_I 1
+#define LLDPMED_CLASS_II 2
+#define LLDPMED_CLASS_III 3
+#define LLDPMED_NETWORK_DEVICE 4
+
+#define LLDPMED_CAP_CAP 0x01
+#define LLDPMED_CAP_POLICY 0x02
+#define LLDPMED_CAP_LOCATION 0x04
+#define LLDPMED_CAP_MDI1 0x08
+#define LLDPMED_CAP_MDI2 0x10
+#define LLDPMED_CAP_IV 0x20
+
+struct lldpmed_cap {
+       struct lldp_tlv_head     tlv_head;
+       u_int8_t                 tlv_org_id[3];
+       u_int8_t                 tlv_org_subtype;
+       u_int16_t                tlv_cap;
+       u_int8_t                 tlv_type;
+} __attribute__ ((__packed__));
+
+#endif /* ENABLE_LLDPMED */
+
+
 #endif /* _LLDP_H */
index 28deec8311d1eba9c16d05fd9fdd27777ab71777..fe5dbbfff14018d07190258d575a617a4c79930a 100644 (file)
@@ -168,6 +168,9 @@ void                         lldpd_recv_all(struct lldpd *);
 int                     lldpd_guess_type(struct lldpd *, char *, int);
 void                    lldpd_decode(struct lldpd *, char *, int,
                            struct lldpd_hardware *, int);
+#ifdef ENABLE_LLDPMED
+void                    lldpd_med(struct lldpd_chassis *);
+#endif
 
 char   **saved_argv;
 
@@ -375,6 +378,14 @@ lldpd_port_cleanup(struct lldpd_port *port)
 void
 lldpd_chassis_cleanup(struct lldpd_chassis *chassis)
 {
+#ifdef ENABLE_LLDPMED
+       free(chassis->c_med_hw);
+       free(chassis->c_med_fw);
+       free(chassis->c_med_sn);
+       free(chassis->c_med_manuf);
+       free(chassis->c_med_model);
+       free(chassis->c_med_asset);
+#endif
        free(chassis->c_id);
        free(chassis->c_name);
        free(chassis->c_descr);
@@ -1159,6 +1170,25 @@ lldpd_send_all(struct lldpd *cfg)
        }
 }
 
+#ifdef ENABLE_LLDPMED
+void
+lldpd_med(struct lldpd_chassis *chassis)
+{
+       free(chassis->c_med_hw);
+       free(chassis->c_med_fw);
+       free(chassis->c_med_sn);
+       free(chassis->c_med_manuf);
+       free(chassis->c_med_model);
+       free(chassis->c_med_asset);
+       chassis->c_med_hw = dmi_hw();
+       chassis->c_med_fw = dmi_fw();
+       chassis->c_med_sn = dmi_sn();
+       chassis->c_med_manuf = dmi_manuf();
+       chassis->c_med_model = dmi_model();
+       chassis->c_med_asset = dmi_asset();
+}
+#endif
+
 void
 lldpd_loop(struct lldpd *cfg)
 {
@@ -1185,7 +1215,6 @@ lldpd_loop(struct lldpd *cfg)
        if (asprintf(&cfg->g_lchassis.c_descr, "%s %s %s %s",
                un->sysname, un->release, un->version, un->machine) == -1)
                fatal("failed to set system description");
-       free(un);
 
        /* Check forwarding */
        cfg->g_lchassis.c_cap_enabled = 0;
@@ -1195,6 +1224,14 @@ lldpd_loop(struct lldpd *cfg)
                }
                close(f);
        }
+#ifdef ENABLE_LLDPMED
+       if (cfg->g_lchassis.c_cap_available & LLDP_CAP_TELEPHONE)
+               cfg->g_lchassis.c_cap_enabled |= LLDP_CAP_TELEPHONE;
+       lldpd_med(&cfg->g_lchassis);
+       free(cfg->g_lchassis.c_med_sw);
+       cfg->g_lchassis.c_med_sw = strdup(un->release);
+#endif
+       free(un);
 
        TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries)
            hardware->h_flags = 0;
@@ -1319,6 +1356,9 @@ main(int argc, char *argv[])
        char *mgmtp = NULL;
        char *popt, opts[] = "vdxm:p:@                    ";
        int probe = 0, i, found, vlan = 0;
+#ifdef ENABLE_LLDPMED
+       int lldpmed = 0;
+#endif
 
        saved_argv = argv;
 
@@ -1330,6 +1370,10 @@ main(int argc, char *argv[])
                if (protos[i].enabled == 1) continue;
                *(popt++) = protos[i].arg;
        }
+#ifdef ENABLE_LLDPMED
+       *(popt++) = 'M';
+       *(popt++) = ':';
+#endif
        *popt = '\0';
        while ((ch = getopt(argc, argv, opts)) != -1) {
                switch (ch) {
@@ -1342,6 +1386,13 @@ main(int argc, char *argv[])
                case 'm':
                        mgmtp = optarg;
                        break;
+#ifdef ENABLE_LLDPMED
+               case 'M':
+                       lldpmed = atoi(optarg);
+                       if ((lldpmed < 1) || (lldpmed > 4))
+                               usage();
+                       break;
+#endif
                case 'p':
                        probe = atoi(optarg);
                        break;
@@ -1399,6 +1450,14 @@ main(int argc, char *argv[])
        /* Set system capabilities */
        cfg->g_lchassis.c_cap_available = LLDP_CAP_BRIDGE | LLDP_CAP_WLAN |
            LLDP_CAP_ROUTER;
+#ifdef ENABLE_LLDPMED
+       if (lldpmed > 0) {
+               if (lldpmed == LLDPMED_CLASS_III)
+                       cfg->g_lchassis.c_cap_available |= LLDP_CAP_TELEPHONE;
+               cfg->g_lchassis.c_med_type = lldpmed;
+               cfg->g_lchassis.c_med_cap = LLDPMED_CAP_CAP | LLDPMED_CAP_IV;
+       }
+#endif
 
        /* Set TTL */
        cfg->g_lchassis.c_ttl = LLDPD_TTL;
index 56c517c0ca6f04dfa3d2f7a22821306ee0b14744..c811f315725cf8218974c114ff97e23f5c8bb934 100644 (file)
@@ -47,6 +47,8 @@
 #include "edp.h"
 #endif
 
+#define SYSFS_CLASS_NET "/sys/class/net/"
+#define SYSFS_CLASS_DMI "/sys/class/dmi/id/"
 #define LLDPD_TTL              120
 #define LLDPD_TX_DELAY         30
 #define LLDPD_TX_MSGDELAY      1
@@ -78,8 +80,25 @@ struct lldpd_chassis {
 
        struct in_addr           c_mgmt;
        u_int32_t                c_mgmt_if;
+
+#ifdef ENABLE_LLDPMED
+       u_int16_t                c_med_cap;
+       u_int8_t                 c_med_type;
+       char                    *c_med_hw;
+       char                    *c_med_fw;
+       char                    *c_med_sw;
+       char                    *c_med_sn;
+       char                    *c_med_manuf;
+       char                    *c_med_model;
+       char                    *c_med_asset;
+#endif
+
 };
+#ifndef ENABLE_LLDP_MED
 #define STRUCT_LLDPD_CHASSIS "bCsswwwll"
+#else
+#define STRUCT_LLDPD_CHASSIS "bCsswwwllwbsssssss"
+#endif
 
 struct lldpd_port {
        u_int8_t                 p_id_subtype;
@@ -301,6 +320,14 @@ int         iface_is_bond(struct lldpd *, const char *);
 int     iface_is_bond_slave(struct lldpd *,
            const char *, const char *);
 int     iface_is_enslaved(struct lldpd *, const char *);
+#ifdef ENABLE_LLDPMED
+char   *dmi_hw();
+char   *dmi_fw();
+char   *dmi_sn();
+char   *dmi_manuf();
+char   *dmi_model();
+char   *dmi_asset();
+#endif
 
 /* log.c */
 void             log_init(int);
index 513bc0051e8eeaa65f118619f253039581382381..deeb2e190f455c6d9d71043aed7b42417daa2ce4 100644 (file)
@@ -246,8 +246,14 @@ asroot_open()
 {
        const char* authorized[] = {
                "/proc/sys/net/ipv4/ip_forward",
-               "/sys/class/net/[^.][^/]*/brforward",
-               "/sys/class/net/[^.][^/]*/brport",
+               SYSFS_CLASS_NET "[^.][^/]*/brforward",
+               SYSFS_CLASS_NET "[^.][^/]*/brport",
+               SYSFS_CLASS_DMI "product_version",
+               SYSFS_CLASS_DMI "product_serial",
+               SYSFS_CLASS_DMI "product_name",
+               SYSFS_CLASS_DMI "bios_version",
+               SYSFS_CLASS_DMI "sys_vendor",
+               SYSFS_CLASS_DMI "chassis_asset_tag",
                NULL
        };
        char **f;