xref: /illumos-gate/usr/src/lib/libdladm/common/flowprop.c (revision b424305435881ac456a9343be2898f1f86440f31)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <stdlib.h>
27 #include <strings.h>
28 #include <errno.h>
29 #include <ctype.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <sys/dld.h>
33 #include <fcntl.h>
34 #include <unistd.h>
35 #include <libdevinfo.h>
36 #include <libdladm_impl.h>
37 #include <libdlflow.h>
38 #include <libdlflow_impl.h>
39 #include <libintl.h>
40 
41 #include <dlfcn.h>
42 #include <link.h>
43 
44 /*
45  * XXX duplicate define
46  */
47 #define	DLADM_PROP_VAL_MAX	32
48 
49 static dladm_status_t	i_dladm_set_flowprop_db(const char *, const char *,
50 			    char **, uint_t);
51 static dladm_status_t	i_dladm_get_flowprop_db(const char *, const char *,
52 			    char **, uint_t *);
53 
54 static fpd_getf_t	do_get_maxbw;
55 static fpd_setf_t	do_set_maxbw;
56 static fpd_checkf_t	do_check_maxbw;
57 
58 static fpd_getf_t	do_get_priority;
59 static fpd_setf_t	do_set_priority;
60 static fpd_checkf_t	do_check_priority;
61 
62 static fprop_desc_t	prop_table[] = {
63 	{ "maxbw",	{ "", NULL }, NULL, 0, B_FALSE,
64 	    do_set_maxbw, NULL,
65 	    do_get_maxbw, do_check_maxbw},
66 	{ "priority",	{ "", NULL }, NULL, 0, B_FALSE,
67 	    do_set_priority, NULL,
68 	    do_get_priority, do_check_priority}
69 };
70 
71 #define	DLADM_MAX_FLOWPROPS	(sizeof (prop_table) / sizeof (fprop_desc_t))
72 
73 static prop_table_t	prop_tbl = {
74 	prop_table,
75 	DLADM_MAX_FLOWPROPS
76 };
77 
78 static resource_prop_t rsrc_prop_table[] = {
79 	{"maxbw",	do_extract_maxbw},
80 	{"priority",	do_extract_priority}
81 };
82 #define	DLADM_MAX_RSRC_PROP (sizeof (rsrc_prop_table) / \
83 	sizeof (resource_prop_t))
84 
85 static dladm_status_t	flow_proplist_check(dladm_arg_list_t *);
86 
87 dladm_status_t
88 dladm_set_flowprop(const char *flow, const char *prop_name, char **prop_val,
89     uint_t val_cnt, uint_t flags, char **errprop)
90 {
91 	dladm_status_t		status = DLADM_STATUS_BADARG;
92 
93 	if (flow == NULL || (prop_val == NULL && val_cnt > 0) ||
94 	    (prop_val != NULL && val_cnt == 0) || flags == 0)
95 		return (DLADM_STATUS_BADARG);
96 
97 	if ((flags & DLADM_OPT_ACTIVE) != 0) {
98 		status = i_dladm_set_prop_temp(flow, prop_name, prop_val,
99 		    val_cnt, flags, errprop, &prop_tbl);
100 		if (status == DLADM_STATUS_TEMPONLY &&
101 		    (flags & DLADM_OPT_PERSIST) != 0)
102 			return (DLADM_STATUS_TEMPONLY);
103 		if (status != DLADM_STATUS_OK)
104 			return (status);
105 	}
106 	if ((flags & DLADM_OPT_PERSIST) != 0) {
107 		if (i_dladm_is_prop_temponly(prop_name, errprop, &prop_tbl))
108 			return (DLADM_STATUS_TEMPONLY);
109 
110 		status = i_dladm_set_flowprop_db(flow, prop_name,
111 		    prop_val, val_cnt);
112 	}
113 	return (status);
114 }
115 
116 dladm_status_t
117 dladm_walk_flowprop(int (*func)(void *, const char *), const char *flow,
118     void *arg)
119 {
120 	int	i;
121 
122 	if (flow == NULL || func == NULL)
123 		return (DLADM_STATUS_BADARG);
124 
125 	/* Then show data-flow properties if there are any */
126 	for (i = 0; i < DLADM_MAX_FLOWPROPS; i++) {
127 		if (func(arg, prop_table[i].pd_name) != DLADM_WALK_CONTINUE)
128 			break;
129 	}
130 	return (DLADM_STATUS_OK);
131 }
132 
133 dladm_status_t
134 dladm_get_flowprop(const char *flow, uint32_t type,
135     const char *prop_name, char **prop_val, uint_t *val_cntp)
136 {
137 	dladm_status_t status;
138 
139 	if (flow == NULL || prop_name == NULL || prop_val == NULL ||
140 	    val_cntp == NULL || *val_cntp == 0)
141 		return (DLADM_STATUS_BADARG);
142 
143 	if (type == DLADM_PROP_VAL_PERSISTENT) {
144 		if (i_dladm_is_prop_temponly(prop_name, NULL, &prop_tbl))
145 			return (DLADM_STATUS_TEMPONLY);
146 		return (i_dladm_get_flowprop_db(flow, prop_name,
147 		    prop_val, val_cntp));
148 	}
149 
150 	status = i_dladm_get_prop_temp(flow, type, prop_name,
151 	    prop_val, val_cntp, &prop_tbl);
152 	if (status != DLADM_STATUS_NOTFOUND)
153 		return (status);
154 
155 	return (DLADM_STATUS_BADARG);
156 }
157 
158 #define	FLOWPROP_RW_DB(statep, writeop) \
159 	(i_dladm_rw_db("/etc/dladm/flowprop.conf", \
160 	S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, process_prop_db, \
161 	(statep), (writeop)))
162 
163 static dladm_status_t
164 i_dladm_set_flowprop_db(const char *flow, const char *prop_name,
165     char **prop_val, uint_t val_cnt)
166 {
167 	prop_db_state_t	state;
168 
169 	state.ls_op = process_prop_set;
170 	state.ls_name = flow;
171 	state.ls_propname = prop_name;
172 	state.ls_propval = prop_val;
173 	state.ls_valcntp = &val_cnt;
174 	state.ls_initop = NULL;
175 
176 	return (FLOWPROP_RW_DB(&state, B_TRUE));
177 }
178 
179 static dladm_status_t
180 i_dladm_get_flowprop_db(const char *flow, const char *prop_name,
181     char **prop_val, uint_t *val_cntp)
182 {
183 	prop_db_state_t	state;
184 
185 	state.ls_op = process_prop_get;
186 	state.ls_name = flow;
187 	state.ls_propname = prop_name;
188 	state.ls_propval = prop_val;
189 	state.ls_valcntp = val_cntp;
190 	state.ls_initop = NULL;
191 
192 	return (FLOWPROP_RW_DB(&state, B_FALSE));
193 }
194 
195 dladm_status_t
196 i_dladm_init_flowprop_db(void)
197 {
198 	prop_db_state_t	state;
199 
200 	state.ls_op = process_prop_init;
201 	state.ls_name = NULL;
202 	state.ls_propname = NULL;
203 	state.ls_propval = NULL;
204 	state.ls_valcntp = NULL;
205 	state.ls_initop = dladm_set_flowprop;
206 
207 	return (FLOWPROP_RW_DB(&state, B_FALSE));
208 }
209 
210 #define	MIN_INFO_SIZE (4 * 1024)
211 
212 dladm_status_t
213 dladm_flow_info(const char *flow, dladm_flow_attr_t *attr)
214 {
215 	dld_ioc_walkflow_t	*ioc;
216 	int			bufsize, fd;
217 	dld_flowinfo_t		*flowinfo;
218 
219 	if ((flow == NULL) || (attr == NULL))
220 		return (DLADM_STATUS_BADARG);
221 
222 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
223 		return (dladm_errno2status(errno));
224 
225 	bufsize = MIN_INFO_SIZE;
226 	if ((ioc = calloc(1, bufsize)) == NULL) {
227 		(void) close(fd);
228 		return (dladm_errno2status(errno));
229 	}
230 
231 	(void) strlcpy(ioc->wf_name, flow, sizeof (ioc->wf_name));
232 	ioc->wf_len = bufsize - sizeof (*ioc);
233 
234 	while (ioctl(fd, DLDIOC_WALKFLOW, ioc) < 0) {
235 		if (errno == ENOSPC) {
236 			bufsize *= 2;
237 			ioc = realloc(ioc, bufsize);
238 			if (ioc != NULL) {
239 				(void) strlcpy(ioc->wf_name, flow,
240 				    MAXNAMELEN);
241 				ioc->wf_len = bufsize - sizeof (*ioc);
242 				continue;
243 			}
244 		}
245 		free(ioc);
246 		(void) close(fd);
247 		return (dladm_errno2status(errno));
248 	}
249 
250 	bzero(attr, sizeof (*attr));
251 
252 	flowinfo = (dld_flowinfo_t *)(void *)(ioc + 1);
253 
254 	attr->fa_linkid = flowinfo->fi_linkid;
255 	bcopy(&flowinfo->fi_flowname, &attr->fa_flowname,
256 	    sizeof (attr->fa_flowname));
257 	bcopy(&flowinfo->fi_flow_desc, &attr->fa_flow_desc,
258 	    sizeof (attr->fa_flow_desc));
259 	bcopy(&flowinfo->fi_resource_props, &attr->fa_resource_props,
260 	    sizeof (attr->fa_resource_props));
261 
262 	free(ioc);
263 	(void) close(fd);
264 	return (DLADM_STATUS_OK);
265 }
266 
267 /* ARGSUSED */
268 static dladm_status_t
269 do_get_maxbw(const char *flow, char **prop_val, uint_t *val_cnt)
270 {
271 	mac_resource_props_t	*mrp;
272 	char 			buf[DLADM_STRSIZE];
273 	dladm_flow_attr_t	fa;
274 	dladm_status_t		status;
275 
276 	status = dladm_flow_info(flow, &fa);
277 	if (status != DLADM_STATUS_OK)
278 		return (status);
279 	mrp = &(fa.fa_resource_props);
280 
281 	*val_cnt = 1;
282 	if (mrp->mrp_mask & MRP_MAXBW) {
283 		(void) snprintf(prop_val[0], DLADM_STRSIZE, "%s",
284 		    dladm_bw2str(mrp->mrp_maxbw, buf));
285 	} else {
286 		return (DLADM_STATUS_NOTSUP);
287 	}
288 	return (DLADM_STATUS_OK);
289 }
290 
291 /* ARGSUSED */
292 static dladm_status_t
293 do_set_maxbw(const char *flow, val_desc_t *vdp, uint_t val_cnt)
294 {
295 	dld_ioc_modifyflow_t	attr;
296 	int			fd;
297 	mac_resource_props_t	mrp;
298 	void			*val;
299 
300 	if (val_cnt != 1)
301 		return (DLADM_STATUS_BADVALCNT);
302 
303 	bzero(&mrp, sizeof (mrp));
304 	if (vdp != NULL && (val = (void *)vdp->vd_val) != NULL) {
305 		bcopy(val, &mrp.mrp_maxbw, sizeof (int64_t));
306 		free(val);
307 	} else {
308 		mrp.mrp_maxbw = MRP_MAXBW_RESETVAL;
309 	}
310 	mrp.mrp_mask = MRP_MAXBW;
311 
312 	bzero(&attr, sizeof (attr));
313 	(void) strlcpy(attr.mf_name, flow, sizeof (attr.mf_name));
314 	bcopy(&mrp, &attr.mf_resource_props, sizeof (mac_resource_props_t));
315 
316 	fd = open(DLD_CONTROL_DEV, O_RDWR);
317 	if (fd < 0) {
318 		return (dladm_errno2status(errno));
319 	}
320 
321 	if (ioctl(fd, DLDIOC_MODIFYFLOW, &attr) < 0) {
322 		(void) close(fd);
323 		return (dladm_errno2status(errno));
324 	}
325 	(void) close(fd);
326 	return (DLADM_STATUS_OK);
327 }
328 
329 /* ARGSUSED */
330 static dladm_status_t
331 do_check_maxbw(fprop_desc_t *pdp, char **prop_val, uint_t val_cnt,
332     val_desc_t **vdpp)
333 {
334 	uint64_t	*maxbw;
335 	val_desc_t	*vdp = NULL;
336 	dladm_status_t	status = DLADM_STATUS_OK;
337 
338 	if (val_cnt != 1)
339 		return (DLADM_STATUS_BADVALCNT);
340 
341 	maxbw = malloc(sizeof (uint64_t));
342 	if (maxbw == NULL)
343 		return (DLADM_STATUS_NOMEM);
344 
345 	status = dladm_str2bw(*prop_val, maxbw);
346 	if (status != DLADM_STATUS_OK) {
347 		free(maxbw);
348 		return (status);
349 	}
350 
351 	if ((*maxbw < MRP_MAXBW_MINVAL) && (*maxbw != 0)) {
352 		free(maxbw);
353 		return (DLADM_STATUS_MINMAXBW);
354 	}
355 
356 	vdp = malloc(sizeof (val_desc_t));
357 	if (vdp == NULL) {
358 		free(maxbw);
359 		return (DLADM_STATUS_NOMEM);
360 	}
361 
362 	vdp->vd_val = (uintptr_t)maxbw;
363 	*vdpp = vdp;
364 	return (DLADM_STATUS_OK);
365 }
366 
367 /* ARGSUSED */
368 static dladm_status_t
369 do_get_priority(const char *flow, char **prop_val, uint_t *val_cnt)
370 {
371 	mac_resource_props_t	*mrp;
372 	char 			buf[DLADM_STRSIZE];
373 	dladm_flow_attr_t	fa;
374 	dladm_status_t		status;
375 
376 	bzero(&fa, sizeof (dladm_flow_attr_t));
377 	status = dladm_flow_info(flow, &fa);
378 	if (status != DLADM_STATUS_OK)
379 		return (status);
380 	mrp = &(fa.fa_resource_props);
381 
382 	*val_cnt = 1;
383 	if (mrp->mrp_mask & MRP_PRIORITY) {
384 		(void) snprintf(prop_val[0], DLADM_STRSIZE, "%s",
385 		    dladm_pri2str(mrp->mrp_priority, buf));
386 	} else {
387 		return (DLADM_STATUS_NOTSUP);
388 	}
389 	return (DLADM_STATUS_OK);
390 }
391 
392 /* ARGSUSED */
393 static dladm_status_t
394 do_set_priority(const char *flow, val_desc_t *vdp, uint_t val_cnt)
395 {
396 	dld_ioc_modifyflow_t	attr;
397 	int			fd;
398 	mac_resource_props_t	mrp;
399 	void			*val;
400 
401 	if (val_cnt != 1)
402 		return (DLADM_STATUS_BADVALCNT);
403 
404 	bzero(&mrp, sizeof (mrp));
405 	if (vdp != NULL && (val = (void *)vdp->vd_val) != NULL) {
406 		bcopy(val, &mrp.mrp_priority, sizeof (mac_priority_level_t));
407 		free(val);
408 	} else {
409 		mrp.mrp_priority = MPL_RESET;
410 	}
411 	mrp.mrp_mask = MRP_PRIORITY;
412 
413 	bzero(&attr, sizeof (attr));
414 	(void) strlcpy(attr.mf_name, flow, sizeof (attr.mf_name));
415 	bcopy(&mrp, &attr.mf_resource_props, sizeof (mac_resource_props_t));
416 
417 	fd = open(DLD_CONTROL_DEV, O_RDWR);
418 	if (fd < 0) {
419 		return (dladm_errno2status(errno));
420 	}
421 
422 	if (ioctl(fd, DLDIOC_MODIFYFLOW, &attr) < 0) {
423 		(void) close(fd);
424 		return (dladm_errno2status(errno));
425 	}
426 	(void) close(fd);
427 	return (DLADM_STATUS_OK);
428 }
429 
430 /* ARGSUSED */
431 static dladm_status_t
432 do_check_priority(fprop_desc_t *pdp, char **prop_val, uint_t val_cnt,
433     val_desc_t **vdpp)
434 {
435 	mac_priority_level_t	*pri;
436 	val_desc_t	*vdp = NULL;
437 	dladm_status_t	status = DLADM_STATUS_OK;
438 
439 	if (val_cnt != 1)
440 		return (DLADM_STATUS_BADVALCNT);
441 
442 	pri = malloc(sizeof (mac_priority_level_t));
443 	if (pri == NULL)
444 		return (DLADM_STATUS_NOMEM);
445 
446 	status = dladm_str2pri(*prop_val, pri);
447 	if (status != DLADM_STATUS_OK) {
448 		free(pri);
449 		return (status);
450 	}
451 
452 	if (*pri == -1) {
453 		free(pri);
454 		return (DLADM_STATUS_BADVAL);
455 	}
456 
457 	vdp = malloc(sizeof (val_desc_t));
458 	if (vdp == NULL) {
459 		free(pri);
460 		return (DLADM_STATUS_NOMEM);
461 	}
462 
463 	vdp->vd_val = (uintptr_t)pri;
464 	*vdpp = vdp;
465 	return (DLADM_STATUS_OK);
466 }
467 
468 static dladm_status_t
469 flow_proplist_check(dladm_arg_list_t *proplist)
470 {
471 	int		i, j;
472 	boolean_t	matched;
473 
474 	for (i = 0; i < proplist->al_count; i++) {
475 		matched = B_FALSE;
476 		for (j = 0; j < DLADM_MAX_FLOWPROPS; j++) {
477 			if (strcmp(proplist->al_info[i].ai_name,
478 			    prop_table[j].pd_name) == 0)
479 				matched = B_TRUE;
480 			}
481 		if (!matched)
482 			return (DLADM_STATUS_BADPROP);
483 	}
484 	return (DLADM_STATUS_OK);
485 
486 }
487 
488 dladm_status_t
489 dladm_parse_flow_props(char *str, dladm_arg_list_t **listp, boolean_t novalues)
490 {
491 	dladm_status_t	status;
492 
493 	status = dladm_parse_args(str, listp, novalues);
494 	if (status != DLADM_STATUS_OK)
495 		return (status);
496 
497 	status = flow_proplist_check(*listp);
498 	if (status != DLADM_STATUS_OK) {
499 		dladm_free_props(*listp);
500 		return (status);
501 	}
502 
503 	return (DLADM_STATUS_OK);
504 }
505 
506 /*
507  * Retrieve the named property from a proplist, check the value and
508  * convert to a kernel structure.
509  */
510 static dladm_status_t
511 i_dladm_flow_proplist_extract_one(dladm_arg_list_t *proplist,
512     const char *name, void *val)
513 {
514 	dladm_status_t		status;
515 	dladm_arg_info_t	*aip = NULL;
516 	int			i, j;
517 
518 	/* Find named property in proplist */
519 	for (i = 0; i < proplist->al_count; i++) {
520 		aip = &proplist->al_info[i];
521 		if (strcasecmp(aip->ai_name, name) == 0)
522 			break;
523 	}
524 
525 	/* Property not in list */
526 	if (i == proplist->al_count)
527 		return (DLADM_STATUS_OK);
528 
529 	for (i = 0; i < DLADM_MAX_FLOWPROPS; i++) {
530 		fprop_desc_t	*pdp = &prop_table[i];
531 		val_desc_t	*vdp;
532 
533 		vdp = malloc(sizeof (val_desc_t) * aip->ai_count);
534 		if (vdp == NULL)
535 			return (DLADM_STATUS_NOMEM);
536 
537 		if (strcasecmp(aip->ai_name, pdp->pd_name) != 0)
538 			continue;
539 
540 		if (aip->ai_val == NULL)
541 			return (DLADM_STATUS_BADARG);
542 
543 		/* Check property value */
544 		if (pdp->pd_check != NULL) {
545 			status = pdp->pd_check(pdp, aip->ai_val,
546 			    aip->ai_count, &vdp);
547 		} else {
548 			status = DLADM_STATUS_BADARG;
549 		}
550 
551 		if (status != DLADM_STATUS_OK)
552 			return (status);
553 
554 		for (j = 0; j < DLADM_MAX_RSRC_PROP; j++) {
555 			resource_prop_t	*rpp = &rsrc_prop_table[j];
556 
557 			if (strcasecmp(aip->ai_name, rpp->rp_name) != 0)
558 				continue;
559 
560 			/* Extract kernel structure */
561 			if (rpp->rp_extract != NULL) {
562 				status = rpp->rp_extract(vdp, val,
563 				    aip->ai_count);
564 			} else {
565 				status = DLADM_STATUS_BADARG;
566 			}
567 			break;
568 		}
569 
570 		if (status != DLADM_STATUS_OK)
571 			return (status);
572 
573 		break;
574 	}
575 	return (status);
576 }
577 
578 /*
579  * Extract properties from a proplist and convert to mac_resource_props_t.
580  */
581 dladm_status_t
582 dladm_flow_proplist_extract(dladm_arg_list_t *proplist,
583     mac_resource_props_t *mrp)
584 {
585 	dladm_status_t	status = DLADM_STATUS_OK;
586 
587 	status = i_dladm_flow_proplist_extract_one(proplist, "maxbw", mrp);
588 	if (status != DLADM_STATUS_OK)
589 		return (status);
590 	status = i_dladm_flow_proplist_extract_one(proplist, "priority", mrp);
591 	if (status != DLADM_STATUS_OK)
592 		return (status);
593 	return (status);
594 }
595 
596 dladm_status_t
597 i_dladm_set_flow_proplist_db(char *flow, dladm_arg_list_t *proplist)
598 {
599 	dladm_status_t		status, ssave = DLADM_STATUS_OK;
600 	dladm_arg_info_t	ai;
601 	int			i;
602 
603 	for (i = 0; i < proplist->al_count; i++) {
604 		ai = proplist->al_info[i];
605 		status = i_dladm_set_flowprop_db(flow, ai.ai_name,
606 		    ai.ai_val, ai.ai_count);
607 		if (status != DLADM_STATUS_OK)
608 			ssave = status;
609 	}
610 	return (ssave);
611 }
612