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