xref: /illumos-gate/usr/src/cmd/dlutil/dlled.c (revision 6e6545bfaed3bab9ce836ee82d1abd8f2edba89a)
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