diff options
Diffstat (limited to 'usr/src/cmd/dlutil/dlled.c')
-rw-r--r-- | usr/src/cmd/dlutil/dlled.c | 285 |
1 files changed, 285 insertions, 0 deletions
diff --git a/usr/src/cmd/dlutil/dlled.c b/usr/src/cmd/dlutil/dlled.c new file mode 100644 index 0000000000..65f2cdc6f7 --- /dev/null +++ b/usr/src/cmd/dlutil/dlled.c @@ -0,0 +1,285 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2017, Joyent, Inc. + */ + +/* + * Private utility to get and set LED information on NICs. This should really + * all be integrated into FM. Until we have figured out that plumbing, this + * allows us to have a little something that we can use to drive work. + */ + +#include <unistd.h> +#include <stdio.h> +#include <stdarg.h> +#include <libgen.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <strings.h> + +#include <libdladm.h> +#include <libdllink.h> +#include <sys/mac.h> +#include <sys/dld.h> +#include <sys/dld_ioc.h> + +static const char *dlled_progname; +static dladm_handle_t dlled_hdl; +static char dlled_dlerrmsg[DLADM_STRSIZE]; + +typedef struct dlled_led_map { + const char *dlm_name; + mac_led_mode_t dlm_bits; +} dlled_led_map_t; + +static dlled_led_map_t dlled_map[] = { + { "default", MAC_LED_DEFAULT }, + { "off", MAC_LED_OFF }, + { "on", MAC_LED_ON }, + { "ident", MAC_LED_IDENT } +}; + +#define DLLED_MAP_NENTRIES \ + (sizeof (dlled_map) / sizeof (dlled_led_map_t)) + +static void +dlled_usage(const char *fmt, ...) +{ + if (fmt != NULL) { + va_list ap; + + (void) fprintf(stderr, "%s: ", dlled_progname); + va_start(ap, fmt); + (void) vfprintf(stderr, fmt, ap); + va_end(ap); + } + + (void) fprintf(stderr, "Usage: %s [-s mode] [link]\n" + "\n" + "\t-s mode set LED to mode\n", + dlled_progname); +} + +static mac_led_mode_t +dlled_parse_mode(const char *orig) +{ + char *mode; + char *part; + mac_led_mode_t m = 0; + + mode = strdup(orig); + if (orig == NULL) { + fprintf(stderr, "failed to allocate memory to dup led " + "mode: %s\n", strerror(errno)); + exit(1); + } + + part = strtok(mode, ","); + while (part != NULL) { + int i; + + for (i = 0; i < DLLED_MAP_NENTRIES; i++) { + if (strcmp(dlled_map[i].dlm_name, part) == 0) { + m |= dlled_map[i].dlm_bits; + break; + } + } + + if (i == DLLED_MAP_NENTRIES) { + fprintf(stderr, "unknown LED mode: %s\n", part); + exit(1); + } + + part = strtok(NULL, ","); + } + + free(mode); + if (m == 0) { + fprintf(stderr, "failed to parse %s: no valid modes " + "specified\n", orig); + exit(1); + } + + return (m); +} + +static void +dlled_mode2str(mac_led_mode_t mode, char *buf, size_t len) +{ + int i; + boolean_t first = B_TRUE; + mac_led_mode_t orig = mode; + + for (i = 0; i < DLLED_MAP_NENTRIES; i++) { + if ((mode & dlled_map[i].dlm_bits) != 0) { + if (first) { + first = B_FALSE; + } else { + (void) strlcat(buf, ",", len); + } + (void) strlcat(buf, dlled_map[i].dlm_name, len); + mode &= ~dlled_map[i].dlm_bits; + } + } + + if (mode != 0) { + (void) snprintf(buf, len, "unknown mode: 0x%x\n", orig); + } +} + + +static int +dlled_set(const char *link, mac_led_mode_t mode) +{ + datalink_id_t linkid; + dladm_status_t status; + dld_ioc_led_t dil; + + if ((status = dladm_name2info(dlled_hdl, link, &linkid, NULL, NULL, + NULL)) != DLADM_STATUS_OK) { + (void) fprintf(stderr, "failed to get link " + "id for link %s: %s\n", link, + dladm_status2str(status, dlled_dlerrmsg)); + return (1); + } + + bzero(&dil, sizeof (dil)); + dil.dil_linkid = linkid; + dil.dil_active = mode; + + if (ioctl(dladm_dld_fd(dlled_hdl), DLDIOC_SETLED, &dil) != 0) { + (void) fprintf(stderr, "failed to set LED on " + "device %s: %s\n", link, strerror(errno)); + return (1); + } + + return (0); +} + +static int +dlled_get_led(dladm_handle_t hdl, datalink_id_t linkid, void *arg) +{ + dladm_status_t status; + char name[MAXLINKNAMELEN]; + char supported[128], active[128]; + dld_ioc_led_t dil; + + if ((status = dladm_datalink_id2info(hdl, linkid, NULL, NULL, NULL, + name, sizeof (name))) != DLADM_STATUS_OK) { + (void) fprintf(stderr, "failed to get datalink name for link " + "%d: %s", linkid, dladm_status2str(status, + dlled_dlerrmsg)); + return (DLADM_WALK_CONTINUE); + } + + + + bzero(&dil, sizeof (dil)); + dil.dil_linkid = linkid; + + if (ioctl(dladm_dld_fd(hdl), DLDIOC_GETLED, &dil) != 0) { + (void) fprintf(stderr, "failed to get LED information for " + "device %s: %s\n", name, strerror(errno)); + return (DLADM_WALK_CONTINUE); + } + + active[0] = '\0'; + supported[0] = '\0'; + dlled_mode2str(dil.dil_active, active, sizeof (active)); + dlled_mode2str(dil.dil_supported, supported, sizeof (supported)); + + printf("%-20s %-12s %s\n", name, active, supported); + + return (DLADM_WALK_CONTINUE); +} + +int +main(int argc, char *argv[]) +{ + int c, ret; + boolean_t opt_s = B_FALSE; + mac_led_mode_t set_mode = 0; + dladm_status_t status; + + dlled_progname = basename(argv[0]); + + while ((c = getopt(argc, argv, ":s:")) != -1) { + switch (c) { + case 's': + opt_s = B_TRUE; + set_mode = dlled_parse_mode(optarg); + break; + case ':': + dlled_usage("option -%c requires an operand\n", optopt); + return (2); + case '?': + default: + dlled_usage("unknown option: -%c\n", optopt); + return (2); + } + } + + argc -= optind; + argv += optind; + + if (opt_s && argc > 1) { + dlled_usage("-s only operates on a single datalink\n"); + return (2); + } + + if (opt_s && argc <= 0) { + dlled_usage("-s requires a datalink\n"); + return (2); + } + + if ((status = dladm_open(&dlled_hdl)) != DLADM_STATUS_OK) { + (void) fprintf(stderr, "failed to open /dev/dld: %s\n", + dladm_status2str(status, dlled_dlerrmsg)); + return (1); + } + + if (opt_s) { + return (dlled_set(argv[0], set_mode)); + } + + (void) printf("%-20s %-12s %s\n", "LINK", "ACTIVE", "SUPPORTED"); + + ret = 0; + if (argc == 0) { + (void) dladm_walk_datalink_id(dlled_get_led, dlled_hdl, NULL, + DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, + DLADM_OPT_ACTIVE); + } else { + int i, dlret; + datalink_id_t linkid; + + for (i = 0; i < argc; i++) { + if ((status = dladm_name2info(dlled_hdl, argv[i], + &linkid, NULL, NULL, NULL)) != DLADM_STATUS_OK) { + (void) fprintf(stderr, "failed to get link " + "id for link %s: %s\n", link, + dladm_status2str(status, dlled_dlerrmsg)); + return (1); + } + + dlret = dlled_get_led(dlled_hdl, linkid, NULL); + if (dlret != DLADM_WALK_CONTINUE) { + ret = 1; + break; + } + } + } + + return (ret); +} |