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 2010 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", { "", MPL_RESET }, 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", extract_maxbw},
81 {"priority", 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
dladm_set_flowprop(dladm_handle_t handle,const char * flow,const char * prop_name,char ** prop_val,uint_t val_cnt,uint_t flags,char ** errprop)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
dladm_walk_flowprop(int (* func)(void *,const char *),const char * flow,void * arg)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
dladm_get_flowprop(dladm_handle_t handle,const char * flow,uint32_t type,const char * prop_name,char ** prop_val,uint_t * val_cntp)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
i_dladm_set_flowprop_db(dladm_handle_t handle,const char * flow,const char * prop_name,char ** prop_val,uint_t val_cnt)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
i_dladm_get_flowprop_db(dladm_handle_t handle,const char * flow,const char * prop_name,char ** prop_val,uint_t * val_cntp)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
i_dladm_init_flowprop_db(dladm_handle_t handle)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
dladm_flow_info(dladm_handle_t handle,const char * flow,dladm_flow_attr_t * attr)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
do_get_maxbw(dladm_handle_t handle,const char * flow,char ** prop_val,uint_t * val_cnt)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
do_set_maxbw(dladm_handle_t handle,const char * flow,val_desc_t * vdp,uint_t val_cnt)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
do_check_maxbw(fprop_desc_t * pdp,char ** prop_val,uint_t val_cnt,val_desc_t ** vdpp)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
do_get_priority(dladm_handle_t handle,const char * flow,char ** prop_val,uint_t * val_cnt)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
do_set_priority(dladm_handle_t handle,const char * flow,val_desc_t * vdp,uint_t val_cnt)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
391 if (val_cnt != 1)
392 return (DLADM_STATUS_BADVALCNT);
393
394 bzero(&mrp, sizeof (mrp));
395 if (vdp != NULL) {
396 bcopy(&vdp->vd_val, &mrp.mrp_priority,
397 sizeof (mac_priority_level_t));
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
do_check_priority(fprop_desc_t * pdp,char ** prop_val,uint_t val_cnt,val_desc_t ** vdpp)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 status = dladm_str2pri(*prop_val, &pri);
426 if (status != DLADM_STATUS_OK)
427 return (status);
428
429 if (pri == -1)
430 return (DLADM_STATUS_BADVAL);
431
432 vdp = malloc(sizeof (val_desc_t));
433 if (vdp == NULL)
434 return (DLADM_STATUS_NOMEM);
435
436 vdp->vd_val = (uint_t)pri;
437 *vdpp = vdp;
438 return (DLADM_STATUS_OK);
439 }
440
441 static dladm_status_t
flow_proplist_check(dladm_arg_list_t * proplist)442 flow_proplist_check(dladm_arg_list_t *proplist)
443 {
444 int i, j;
445 boolean_t matched;
446
447 for (i = 0; i < proplist->al_count; i++) {
448 matched = B_FALSE;
449 for (j = 0; j < DLADM_MAX_FLOWPROPS; j++) {
450 if (strcmp(proplist->al_info[i].ai_name,
451 prop_table[j].pd_name) == 0)
452 matched = B_TRUE;
453 }
454 if (!matched)
455 return (DLADM_STATUS_BADPROP);
456 }
457 return (DLADM_STATUS_OK);
458
459 }
460
461 dladm_status_t
dladm_parse_flow_props(char * str,dladm_arg_list_t ** listp,boolean_t novalues)462 dladm_parse_flow_props(char *str, dladm_arg_list_t **listp, boolean_t novalues)
463 {
464 dladm_status_t status;
465
466 status = dladm_parse_args(str, listp, novalues);
467 if (status != DLADM_STATUS_OK)
468 return (status);
469
470 if (*listp != NULL && (status = flow_proplist_check(*listp)
471 != DLADM_STATUS_OK)) {
472 dladm_free_props(*listp);
473 return (status);
474 }
475
476 return (DLADM_STATUS_OK);
477 }
478
479 /*
480 * Retrieve the named property from a proplist, check the value and
481 * convert to a kernel structure.
482 */
483 static dladm_status_t
i_dladm_flow_proplist_extract_one(dladm_arg_list_t * proplist,const char * name,void * arg)484 i_dladm_flow_proplist_extract_one(dladm_arg_list_t *proplist,
485 const char *name, void *arg)
486 {
487 dladm_status_t status;
488 dladm_arg_info_t *aip = NULL;
489 int i, j;
490
491 /* Find named property in proplist */
492 for (i = 0; i < proplist->al_count; i++) {
493 aip = &proplist->al_info[i];
494 if (strcasecmp(aip->ai_name, name) == 0)
495 break;
496 }
497
498 /* Property not in list */
499 if (i == proplist->al_count)
500 return (DLADM_STATUS_OK);
501
502 for (i = 0; i < DLADM_MAX_FLOWPROPS; i++) {
503 fprop_desc_t *pdp = &prop_table[i];
504 val_desc_t *vdp;
505
506 vdp = malloc(sizeof (val_desc_t) * aip->ai_count);
507 if (vdp == NULL)
508 return (DLADM_STATUS_NOMEM);
509
510 if (strcasecmp(aip->ai_name, pdp->pd_name) != 0)
511 continue;
512
513 if (aip->ai_val == NULL)
514 return (DLADM_STATUS_BADARG);
515
516 /* Check property value */
517 if (pdp->pd_check != NULL) {
518 status = pdp->pd_check(pdp, aip->ai_val,
519 aip->ai_count, &vdp);
520 } else {
521 status = DLADM_STATUS_BADARG;
522 }
523
524 if (status != DLADM_STATUS_OK)
525 return (status);
526
527 for (j = 0; j < DLADM_MAX_RSRC_PROP; j++) {
528 resource_prop_t *rpp = &rsrc_prop_table[j];
529
530 if (strcasecmp(aip->ai_name, rpp->rp_name) != 0)
531 continue;
532
533 /* Extract kernel structure */
534 if (rpp->rp_extract != NULL) {
535 status = rpp->rp_extract(vdp,
536 aip->ai_count, arg);
537 } else {
538 status = DLADM_STATUS_BADARG;
539 }
540 break;
541 }
542
543 if (status != DLADM_STATUS_OK)
544 return (status);
545
546 break;
547 }
548 return (status);
549 }
550
551 /*
552 * Extract properties from a proplist and convert to mac_resource_props_t.
553 */
554 dladm_status_t
dladm_flow_proplist_extract(dladm_arg_list_t * proplist,mac_resource_props_t * mrp)555 dladm_flow_proplist_extract(dladm_arg_list_t *proplist,
556 mac_resource_props_t *mrp)
557 {
558 dladm_status_t status = DLADM_STATUS_OK;
559
560 status = i_dladm_flow_proplist_extract_one(proplist, "maxbw", mrp);
561 if (status != DLADM_STATUS_OK)
562 return (status);
563 status = i_dladm_flow_proplist_extract_one(proplist, "priority", mrp);
564 if (status != DLADM_STATUS_OK)
565 return (status);
566 return (status);
567 }
568
569 dladm_status_t
i_dladm_set_flow_proplist_db(dladm_handle_t handle,char * flow,dladm_arg_list_t * proplist)570 i_dladm_set_flow_proplist_db(dladm_handle_t handle, char *flow,
571 dladm_arg_list_t *proplist)
572 {
573 dladm_status_t status, ssave = DLADM_STATUS_OK;
574 dladm_arg_info_t ai;
575 int i;
576
577 for (i = 0; i < proplist->al_count; i++) {
578 ai = proplist->al_info[i];
579 status = i_dladm_set_flowprop_db(handle, flow, ai.ai_name,
580 ai.ai_val, ai.ai_count);
581 if (status != DLADM_STATUS_OK)
582 ssave = status;
583 }
584 return (ssave);
585 }
586