1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright (c) 2017, Joyent, Inc. 14 */ 15 16 /* 17 * Private utility to get and set LED information on NICs. This should really 18 * all be integrated into FM. Until we have figured out that plumbing, this 19 * allows us to have a little something that we can use to drive work. 20 */ 21 22 #include <unistd.h> 23 #include <stdio.h> 24 #include <stdarg.h> 25 #include <libgen.h> 26 #include <string.h> 27 #include <stdlib.h> 28 #include <errno.h> 29 #include <strings.h> 30 31 #include <libdladm.h> 32 #include <libdllink.h> 33 #include <sys/mac.h> 34 #include <sys/dld.h> 35 #include <sys/dld_ioc.h> 36 37 static const char *dlled_progname; 38 static dladm_handle_t dlled_hdl; 39 static char dlled_dlerrmsg[DLADM_STRSIZE]; 40 41 typedef struct dlled_led_map { 42 const char *dlm_name; 43 mac_led_mode_t dlm_bits; 44 } dlled_led_map_t; 45 46 static dlled_led_map_t dlled_map[] = { 47 { "default", MAC_LED_DEFAULT }, 48 { "off", MAC_LED_OFF }, 49 { "on", MAC_LED_ON }, 50 { "ident", MAC_LED_IDENT } 51 }; 52 53 #define DLLED_MAP_NENTRIES \ 54 (sizeof (dlled_map) / sizeof (dlled_led_map_t)) 55 56 static void 57 dlled_usage(const char *fmt, ...) 58 { 59 if (fmt != NULL) { 60 va_list ap; 61 62 (void) fprintf(stderr, "%s: ", dlled_progname); 63 va_start(ap, fmt); 64 (void) vfprintf(stderr, fmt, ap); 65 va_end(ap); 66 } 67 68 (void) fprintf(stderr, "Usage: %s [-s mode] [link]\n" 69 "\n" 70 "\t-s mode set LED to mode\n", 71 dlled_progname); 72 } 73 74 static mac_led_mode_t 75 dlled_parse_mode(const char *orig) 76 { 77 char *mode; 78 char *part; 79 mac_led_mode_t m = 0; 80 81 mode = strdup(orig); 82 if (mode == NULL) { 83 fprintf(stderr, "failed to allocate memory to dup led " 84 "mode: %s\n", strerror(errno)); 85 exit(1); 86 } 87 88 part = strtok(mode, ","); 89 while (part != NULL) { 90 int i; 91 92 for (i = 0; i < DLLED_MAP_NENTRIES; i++) { 93 if (strcmp(dlled_map[i].dlm_name, part) == 0) { 94 m |= dlled_map[i].dlm_bits; 95 break; 96 } 97 } 98 99 if (i == DLLED_MAP_NENTRIES) { 100 fprintf(stderr, "unknown LED mode: %s\n", part); 101 exit(1); 102 } 103 104 part = strtok(NULL, ","); 105 } 106 107 free(mode); 108 if (m == 0) { 109 fprintf(stderr, "failed to parse %s: no valid modes " 110 "specified\n", orig); 111 exit(1); 112 } 113 114 return (m); 115 } 116 117 static void 118 dlled_mode2str(mac_led_mode_t mode, char *buf, size_t len) 119 { 120 int i; 121 boolean_t first = B_TRUE; 122 mac_led_mode_t orig = mode; 123 124 for (i = 0; i < DLLED_MAP_NENTRIES; i++) { 125 if ((mode & dlled_map[i].dlm_bits) != 0) { 126 if (first) { 127 first = B_FALSE; 128 } else { 129 (void) strlcat(buf, ",", len); 130 } 131 (void) strlcat(buf, dlled_map[i].dlm_name, len); 132 mode &= ~dlled_map[i].dlm_bits; 133 } 134 } 135 136 if (mode != 0) { 137 (void) snprintf(buf, len, "unknown mode: 0x%x\n", orig); 138 } 139 } 140 141 142 static int 143 dlled_set(const char *link, mac_led_mode_t mode) 144 { 145 datalink_id_t linkid; 146 dladm_status_t status; 147 dld_ioc_led_t dil; 148 149 if ((status = dladm_name2info(dlled_hdl, link, &linkid, NULL, NULL, 150 NULL)) != DLADM_STATUS_OK) { 151 (void) fprintf(stderr, "failed to get link " 152 "id for link %s: %s\n", link, 153 dladm_status2str(status, dlled_dlerrmsg)); 154 return (1); 155 } 156 157 bzero(&dil, sizeof (dil)); 158 dil.dil_linkid = linkid; 159 dil.dil_active = mode; 160 161 if (ioctl(dladm_dld_fd(dlled_hdl), DLDIOC_SETLED, &dil) != 0) { 162 (void) fprintf(stderr, "failed to set LED on " 163 "device %s: %s\n", link, strerror(errno)); 164 return (1); 165 } 166 167 return (0); 168 } 169 170 static int 171 dlled_get_led(dladm_handle_t hdl, datalink_id_t linkid, void *arg) 172 { 173 dladm_status_t status; 174 char name[MAXLINKNAMELEN]; 175 char supported[128], active[128]; 176 dld_ioc_led_t dil; 177 178 if ((status = dladm_datalink_id2info(hdl, linkid, NULL, NULL, NULL, 179 name, sizeof (name))) != DLADM_STATUS_OK) { 180 (void) fprintf(stderr, "failed to get datalink name for link " 181 "%d: %s", linkid, dladm_status2str(status, 182 dlled_dlerrmsg)); 183 return (DLADM_WALK_CONTINUE); 184 } 185 186 187 188 bzero(&dil, sizeof (dil)); 189 dil.dil_linkid = linkid; 190 191 if (ioctl(dladm_dld_fd(hdl), DLDIOC_GETLED, &dil) != 0) { 192 (void) fprintf(stderr, "failed to get LED information for " 193 "device %s: %s\n", name, strerror(errno)); 194 return (DLADM_WALK_CONTINUE); 195 } 196 197 active[0] = '\0'; 198 supported[0] = '\0'; 199 dlled_mode2str(dil.dil_active, active, sizeof (active)); 200 dlled_mode2str(dil.dil_supported, supported, sizeof (supported)); 201 202 printf("%-20s %-12s %s\n", name, active, supported); 203 204 return (DLADM_WALK_CONTINUE); 205 } 206 207 int 208 main(int argc, char *argv[]) 209 { 210 int c, ret; 211 boolean_t opt_s = B_FALSE; 212 mac_led_mode_t set_mode = 0; 213 dladm_status_t status; 214 215 dlled_progname = basename(argv[0]); 216 217 while ((c = getopt(argc, argv, ":s:")) != -1) { 218 switch (c) { 219 case 's': 220 opt_s = B_TRUE; 221 set_mode = dlled_parse_mode(optarg); 222 break; 223 case ':': 224 dlled_usage("option -%c requires an operand\n", optopt); 225 return (2); 226 case '?': 227 default: 228 dlled_usage("unknown option: -%c\n", optopt); 229 return (2); 230 } 231 } 232 233 argc -= optind; 234 argv += optind; 235 236 if (opt_s && argc > 1) { 237 dlled_usage("-s only operates on a single datalink\n"); 238 return (2); 239 } 240 241 if (opt_s && argc <= 0) { 242 dlled_usage("-s requires a datalink\n"); 243 return (2); 244 } 245 246 if ((status = dladm_open(&dlled_hdl)) != DLADM_STATUS_OK) { 247 (void) fprintf(stderr, "failed to open /dev/dld: %s\n", 248 dladm_status2str(status, dlled_dlerrmsg)); 249 return (1); 250 } 251 252 if (opt_s) { 253 return (dlled_set(argv[0], set_mode)); 254 } 255 256 (void) printf("%-20s %-12s %s\n", "LINK", "ACTIVE", "SUPPORTED"); 257 258 ret = 0; 259 if (argc == 0) { 260 (void) dladm_walk_datalink_id(dlled_get_led, dlled_hdl, NULL, 261 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, 262 DLADM_OPT_ACTIVE); 263 } else { 264 int i, dlret; 265 datalink_id_t linkid; 266 267 for (i = 0; i < argc; i++) { 268 if ((status = dladm_name2info(dlled_hdl, argv[i], 269 &linkid, NULL, NULL, NULL)) != DLADM_STATUS_OK) { 270 (void) fprintf(stderr, "failed to get link " 271 "id for link %s: %s\n", link, 272 dladm_status2str(status, dlled_dlerrmsg)); 273 return (1); 274 } 275 276 dlret = dlled_get_led(dlled_hdl, linkid, NULL); 277 if (dlret != DLADM_WALK_CONTINUE) { 278 ret = 1; 279 break; 280 } 281 } 282 } 283 284 return (ret); 285 } 286