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