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 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/types.h> 28 #include <sys/atomic.h> 29 #include <sys/systm.h> 30 #include <sys/socket.h> 31 #include <netinet/in.h> 32 #include <sys/modctl.h> 33 #include <sys/sunddi.h> 34 #include <ipp/ipp.h> 35 #include <ipp/ipp_config.h> 36 #include <inet/common.h> 37 #include <ipp/meters/meter_impl.h> 38 39 #define D_SM_COMMENT "IPP Sliding Window Meter" 40 41 /* DDI file for tswtcl ipp module */ 42 43 static int tswtcl_create_action(ipp_action_id_t, nvlist_t **, ipp_flags_t); 44 static int tswtcl_modify_action(ipp_action_id_t, nvlist_t **, ipp_flags_t); 45 static int tswtcl_destroy_action(ipp_action_id_t, ipp_flags_t); 46 static int tswtcl_info(ipp_action_id_t, int (*)(nvlist_t *, void *), void *, 47 ipp_flags_t); 48 static int tswtcl_invoke_action(ipp_action_id_t, ipp_packet_t *); 49 50 /* Stats init function */ 51 static int tswtcl_statinit(ipp_action_id_t, tswtcl_data_t *); 52 53 /* Stats callback function */ 54 static int tswtcl_update_stats(ipp_stat_t *, void *, int); 55 56 ipp_ops_t tswtcl_ops = { 57 IPPO_REV, 58 tswtcl_create_action, /* ippo_action_create */ 59 tswtcl_modify_action, /* ippo_action_modify */ 60 tswtcl_destroy_action, /* ippo_action_destroy */ 61 tswtcl_info, /* ippo_action_info */ 62 tswtcl_invoke_action /* ippo_action_invoke */ 63 }; 64 65 extern struct mod_ops mod_ippops; 66 67 /* 68 * Module linkage information for the kernel. 69 */ 70 static struct modlipp modlipp = { 71 &mod_ippops, 72 D_SM_COMMENT, 73 &tswtcl_ops 74 }; 75 76 static struct modlinkage modlinkage = { 77 MODREV_1, 78 { (void *)&modlipp, NULL } 79 }; 80 81 82 int 83 _init(void) 84 { 85 return (mod_install(&modlinkage)); 86 } 87 88 int 89 _fini(void) 90 { 91 return (mod_remove(&modlinkage)); 92 } 93 94 int 95 _info(struct modinfo *modinfop) 96 { 97 return (mod_info(&modlinkage, modinfop)); 98 } 99 100 /* ARGSUSED */ 101 static int 102 tswtcl_create_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags) 103 { 104 nvlist_t *nvlp; 105 tswtcl_data_t *tswtcl_data; 106 tswtcl_cfg_t *cfg_parms; 107 char *next_action; 108 uint32_t bstats; 109 int rc, rc2; 110 111 nvlp = *nvlpp; 112 *nvlpp = NULL; /* nvlist should be NULL on return */ 113 114 115 if ((cfg_parms = kmem_alloc(TSWTCL_CFG_SZ, KM_NOSLEEP)) == NULL) { 116 nvlist_free(nvlp); 117 return (ENOMEM); 118 } 119 120 /* parse red next action name */ 121 if ((rc = nvlist_lookup_string(nvlp, TSWTCL_RED_ACTION_NAME, 122 &next_action)) != 0) { 123 nvlist_free(nvlp); 124 tswtcl0dbg(("tswtcl_create_action:invalid config, red action" \ 125 " name missing\n")); 126 kmem_free(cfg_parms, TSWTCL_CFG_SZ); 127 return (rc); 128 } 129 if ((cfg_parms->red_action = ipp_action_lookup(next_action)) 130 == IPP_ACTION_INVAL) { 131 nvlist_free(nvlp); 132 tswtcl0dbg(("tswtcl_create_action: red action invalid\n")); 133 kmem_free(cfg_parms, TSWTCL_CFG_SZ); 134 return (EINVAL); 135 } 136 137 /* parse yellow next action name */ 138 if ((rc = nvlist_lookup_string(nvlp, TSWTCL_YELLOW_ACTION_NAME, 139 &next_action)) != 0) { 140 nvlist_free(nvlp); 141 tswtcl0dbg(("tswtcl_create_action:invalid config, yellow " \ 142 "action name missing\n")); 143 kmem_free(cfg_parms, TSWTCL_CFG_SZ); 144 return (rc); 145 } 146 if ((cfg_parms->yellow_action = ipp_action_lookup(next_action)) 147 == IPP_ACTION_INVAL) { 148 nvlist_free(nvlp); 149 tswtcl0dbg(("tswtcl_create_action: yellow action invalid\n")); 150 kmem_free(cfg_parms, TSWTCL_CFG_SZ); 151 return (EINVAL); 152 } 153 154 /* parse green next action name */ 155 if ((rc = nvlist_lookup_string(nvlp, TSWTCL_GREEN_ACTION_NAME, 156 &next_action)) != 0) { 157 nvlist_free(nvlp); 158 tswtcl0dbg(("tswtcl_create_action:invalid config, green " \ 159 "action name missing\n")); 160 kmem_free(cfg_parms, TSWTCL_CFG_SZ); 161 return (rc); 162 } 163 if ((cfg_parms->green_action = ipp_action_lookup(next_action)) 164 == IPP_ACTION_INVAL) { 165 nvlist_free(nvlp); 166 tswtcl0dbg(("tswtcl_create_action: green action invalid\n")); 167 kmem_free(cfg_parms, TSWTCL_CFG_SZ); 168 return (EINVAL); 169 } 170 171 /* parse committed rate - in bits / sec */ 172 if ((rc = nvlist_lookup_uint32(nvlp, TSWTCL_COMMITTED_RATE, 173 &cfg_parms->committed_rate)) != 0) { 174 nvlist_free(nvlp); 175 tswtcl0dbg(("tswtcl_create_action: invalid config, "\ 176 " committed rate missing\n")); 177 kmem_free(cfg_parms, TSWTCL_CFG_SZ); 178 return (rc); 179 } 180 181 /* parse peak rate - in bits / sec */ 182 if ((rc = nvlist_lookup_uint32(nvlp, TSWTCL_PEAK_RATE, 183 &cfg_parms->peak_rate)) != 0) { 184 nvlist_free(nvlp); 185 tswtcl0dbg(("tswtcl_create_action: invalid config, "\ 186 " peak rate missing\n")); 187 kmem_free(cfg_parms, TSWTCL_CFG_SZ); 188 return (rc); 189 } 190 191 if (cfg_parms->peak_rate < cfg_parms->committed_rate) { 192 nvlist_free(nvlp); 193 tswtcl0dbg(("tswtcl_create_action: invalid config, "\ 194 " peak rate < committed rate\n")); 195 kmem_free(cfg_parms, TSWTCL_CFG_SZ); 196 return (EINVAL); 197 } 198 199 /* parse window - in msec */ 200 if ((rc = nvlist_lookup_uint32(nvlp, TSWTCL_WINDOW, 201 &cfg_parms->window)) != 0) { 202 nvlist_free(nvlp); 203 tswtcl0dbg(("tswtcl_create_action: invalid config, "\ 204 " window missing\n")); 205 kmem_free(cfg_parms, TSWTCL_CFG_SZ); 206 return (rc); 207 } 208 /* convert to nsec */ 209 cfg_parms->nsecwindow = (uint64_t)cfg_parms->window * 210 METER_MSEC_TO_NSEC; 211 212 /* parse stats */ 213 if ((rc = nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE, &bstats)) 214 != 0) { 215 cfg_parms->stats = B_FALSE; 216 } else { 217 cfg_parms->stats = (boolean_t)bstats; 218 } 219 220 nvlist_free(nvlp); 221 222 /* Initialize other stuff */ 223 tswtcl_data = kmem_zalloc(TSWTCL_DATA_SZ, KM_NOSLEEP); 224 if (tswtcl_data == NULL) { 225 kmem_free(cfg_parms, TSWTCL_CFG_SZ); 226 return (ENOMEM); 227 } 228 229 if (cfg_parms->stats) { 230 if ((rc = tswtcl_statinit(aid, tswtcl_data)) != 0) { 231 kmem_free(cfg_parms, TSWTCL_CFG_SZ); 232 kmem_free(tswtcl_data, TSWTCL_DATA_SZ); 233 return (rc); 234 } 235 } 236 237 /* set action chain reference */ 238 if ((rc = ipp_action_ref(aid, cfg_parms->red_action, flags)) != 0) { 239 tswtcl0dbg(("tswtcl_create_action: ipp_action_ref " \ 240 "returned with error %d", rc)); 241 goto cleanup; 242 } 243 if ((rc = ipp_action_ref(aid, cfg_parms->yellow_action, flags)) != 0) { 244 tswtcl0dbg(("tswtcl_create_action: ipp_action_ref " \ 245 "returned with error %d", rc)); 246 rc2 = ipp_action_unref(aid, cfg_parms->red_action, flags); 247 ASSERT(rc2 == 0); 248 goto cleanup; 249 } 250 if ((rc = ipp_action_ref(aid, cfg_parms->green_action, flags)) != 0) { 251 tswtcl0dbg(("tswtcl_create_action: ipp_action_ref " \ 252 "returned with error %d", rc)); 253 rc2 = ipp_action_unref(aid, cfg_parms->red_action, flags); 254 ASSERT(rc2 == 0); 255 rc2 = ipp_action_unref(aid, cfg_parms->yellow_action, flags); 256 ASSERT(rc2 == 0); 257 goto cleanup; 258 } 259 260 /* Initializations */ 261 cfg_parms->pminusc = cfg_parms->peak_rate - cfg_parms->committed_rate; 262 tswtcl_data->cfg_parms = cfg_parms; 263 tswtcl_data->avg_rate = cfg_parms->committed_rate; 264 mutex_init(&tswtcl_data->tswtcl_lock, NULL, MUTEX_DEFAULT, 0); 265 tswtcl_data->win_front = gethrtime(); 266 ipp_action_set_ptr(aid, (void *)tswtcl_data); 267 268 return (0); 269 270 cleanup: 271 if (cfg_parms->stats) { 272 ipp_stat_destroy(tswtcl_data->stats); 273 } 274 kmem_free(cfg_parms, TSWTCL_CFG_SZ); 275 kmem_free(tswtcl_data, TSWTCL_DATA_SZ); 276 return (rc); 277 278 } 279 280 static int 281 tswtcl_modify_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags) 282 { 283 284 nvlist_t *nvlp; 285 int err = 0, err2; 286 uint8_t config_type; 287 char *next_action_name; 288 ipp_action_id_t next_action; 289 uint32_t rate; 290 tswtcl_cfg_t *cfg_parms, *old_cfg; 291 tswtcl_data_t *tswtcl_data; 292 uint32_t bstats; 293 294 nvlp = *nvlpp; 295 *nvlpp = NULL; /* nvlist should be NULL when this returns */ 296 297 if ((err = nvlist_lookup_byte(nvlp, IPP_CONFIG_TYPE, &config_type)) 298 != 0) { 299 nvlist_free(nvlp); 300 tswtcl0dbg(("tswtcl_modify_action:invalid configuration type")); 301 return (err); 302 } 303 304 if (config_type != IPP_SET) { 305 nvlist_free(nvlp); 306 tswtcl0dbg(("tswtcl_modify_action:invalid configuration type " \ 307 "%d", config_type)); 308 return (EINVAL); 309 } 310 311 tswtcl_data = (tswtcl_data_t *)ipp_action_get_ptr(aid); 312 old_cfg = tswtcl_data->cfg_parms; 313 314 cfg_parms = kmem_alloc(TSWTCL_CFG_SZ, KM_NOSLEEP); 315 if (cfg_parms == NULL) { 316 nvlist_free(nvlp); 317 tswtcl0dbg(("tswtcl_modify_action:mem. allocation failure\n")); 318 return (ENOMEM); 319 } 320 321 /* Just copy all and change as needed */ 322 bcopy(old_cfg, cfg_parms, TSWTCL_CFG_SZ); 323 324 /* parse red action name, if present */ 325 if ((err = nvlist_lookup_string(nvlp, TSWTCL_RED_ACTION_NAME, 326 &next_action_name)) == 0) { 327 /* Get action id */ 328 if ((next_action = ipp_action_lookup(next_action_name)) 329 == IPP_ACTION_INVAL) { 330 nvlist_free(nvlp); 331 tswtcl0dbg(("tswtcl_modify_action: red next_action"\ 332 " invalid\n")); 333 kmem_free(cfg_parms, TSWTCL_CFG_SZ); 334 return (EINVAL); 335 } 336 cfg_parms->red_action = next_action; 337 } 338 339 /* parse yellow action name, if present */ 340 if ((err = nvlist_lookup_string(nvlp, TSWTCL_YELLOW_ACTION_NAME, 341 &next_action_name)) == 0) { 342 /* Get action id */ 343 if ((next_action = ipp_action_lookup(next_action_name)) 344 == IPP_ACTION_INVAL) { 345 nvlist_free(nvlp); 346 tswtcl0dbg(("tswtcl_modify_action: yellow next_action"\ 347 " invalid\n")); 348 kmem_free(cfg_parms, TSWTCL_CFG_SZ); 349 return (EINVAL); 350 } 351 cfg_parms->yellow_action = next_action; 352 } 353 354 /* parse green action name, if present */ 355 if ((err = nvlist_lookup_string(nvlp, TSWTCL_GREEN_ACTION_NAME, 356 &next_action_name)) == 0) { 357 /* Get action id */ 358 if ((next_action = ipp_action_lookup(next_action_name)) 359 == IPP_ACTION_INVAL) { 360 nvlist_free(nvlp); 361 tswtcl0dbg(("tswtcl_modify_action: green next_action"\ 362 " invalid\n")); 363 kmem_free(cfg_parms, TSWTCL_CFG_SZ); 364 return (EINVAL); 365 } 366 cfg_parms->green_action = next_action; 367 } 368 369 /* parse committed rate, if present */ 370 if ((err = nvlist_lookup_uint32(nvlp, TSWTCL_COMMITTED_RATE, &rate)) 371 == 0) { 372 cfg_parms->committed_rate = rate; 373 } 374 375 /* parse peak rate, if present */ 376 if ((err = nvlist_lookup_uint32(nvlp, TSWTCL_PEAK_RATE, &rate)) 377 == 0) { 378 cfg_parms->peak_rate = rate; 379 } 380 381 if (cfg_parms->peak_rate < cfg_parms->committed_rate) { 382 nvlist_free(nvlp); 383 tswtcl0dbg(("tswtcl_create_action: invalid config, "\ 384 " peak rate < committed rate\n")); 385 kmem_free(cfg_parms, TSWTCL_CFG_SZ); 386 return (EINVAL); 387 } 388 389 /* parse window - in msec */ 390 if ((err = nvlist_lookup_uint32(nvlp, TSWTCL_WINDOW, 391 &cfg_parms->window)) != 0) { 392 cfg_parms->nsecwindow = (uint64_t)cfg_parms->window * 393 METER_MSEC_TO_NSEC; 394 } 395 396 /* parse stats, if present */ 397 if (nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE, &bstats) == 0) { 398 cfg_parms->stats = (boolean_t)bstats; 399 if (cfg_parms->stats && !old_cfg->stats) { 400 if ((err = tswtcl_statinit(aid, tswtcl_data)) != 0) { 401 nvlist_free(nvlp); 402 kmem_free(cfg_parms, TSWTCL_CFG_SZ); 403 return (err); 404 } 405 } else if (!cfg_parms->stats && old_cfg->stats) { 406 ipp_stat_destroy(tswtcl_data->stats); 407 } 408 } 409 410 /* Can we ref all the new actions? */ 411 if ((err = ipp_action_ref(aid, cfg_parms->red_action, flags)) != 0) { 412 tswtcl0dbg(("tswtcl_modify_data: can't ref. red action\n")); 413 nvlist_free(nvlp); 414 kmem_free(cfg_parms, TSWTCL_CFG_SZ); 415 return (err); 416 } 417 418 if ((err = ipp_action_ref(aid, cfg_parms->yellow_action, flags)) != 0) { 419 tswtcl0dbg(("tswtcl_modify_data:can't ref. yellow action\n")); 420 nvlist_free(nvlp); 421 err2 = ipp_action_unref(aid, cfg_parms->red_action, flags); 422 ASSERT(err2 == 0); 423 kmem_free(cfg_parms, TSWTCL_CFG_SZ); 424 return (err); 425 } 426 427 if ((err = ipp_action_ref(aid, cfg_parms->green_action, flags)) != 0) { 428 tswtcl0dbg(("tswtcl_modify_data:can't ref. green action\n")); 429 nvlist_free(nvlp); 430 err2 = ipp_action_unref(aid, cfg_parms->red_action, flags); 431 ASSERT(err2 == 0); 432 err2 = ipp_action_unref(aid, cfg_parms->yellow_action, flags); 433 ASSERT(err2 == 0); 434 kmem_free(cfg_parms, TSWTCL_CFG_SZ); 435 return (err); 436 } 437 438 /* Re-compute pminusc */ 439 cfg_parms->pminusc = cfg_parms->peak_rate - cfg_parms->committed_rate; 440 441 /* Actually modify the configuration */ 442 mutex_enter(&tswtcl_data->tswtcl_lock); 443 tswtcl_data->cfg_parms = cfg_parms; 444 mutex_exit(&tswtcl_data->tswtcl_lock); 445 446 /* Un-ref the old actions */ 447 err = ipp_action_unref(aid, old_cfg->red_action, flags); 448 ASSERT(err == 0); 449 err = ipp_action_unref(aid, old_cfg->yellow_action, flags); 450 ASSERT(err == 0); 451 err = ipp_action_unref(aid, old_cfg->green_action, flags); 452 ASSERT(err == 0); 453 454 /* Free the old configuration */ 455 kmem_free(old_cfg, TSWTCL_CFG_SZ); 456 457 nvlist_free(nvlp); 458 459 return (0); 460 } 461 462 static int 463 tswtcl_destroy_action(ipp_action_id_t aid, ipp_flags_t flags) 464 { 465 tswtcl_data_t *tswtcl_data; 466 tswtcl_cfg_t *cfg_parms; 467 int rc; 468 469 tswtcl_data = (tswtcl_data_t *)ipp_action_get_ptr(aid); 470 ASSERT(tswtcl_data != NULL); 471 472 cfg_parms = tswtcl_data->cfg_parms; 473 474 if (cfg_parms->stats) { 475 ipp_stat_destroy(tswtcl_data->stats); 476 } 477 478 /* unreference the action */ 479 rc = ipp_action_unref(aid, cfg_parms->red_action, flags); 480 ASSERT(rc == 0); 481 rc = ipp_action_unref(aid, cfg_parms->yellow_action, flags); 482 ASSERT(rc == 0); 483 rc = ipp_action_unref(aid, cfg_parms->green_action, flags); 484 ASSERT(rc == 0); 485 486 mutex_destroy(&tswtcl_data->tswtcl_lock); 487 kmem_free(cfg_parms, TSWTCL_CFG_SZ); 488 kmem_free(tswtcl_data, TSWTCL_DATA_SZ); 489 return (0); 490 } 491 492 static int 493 tswtcl_invoke_action(ipp_action_id_t aid, ipp_packet_t *packet) 494 { 495 tswtcl_data_t *tswtcl_data; 496 ipp_action_id_t next_action; 497 mblk_t *mp = NULL; 498 int rc; 499 500 /* get mblk from ipp_packet structure */ 501 mp = ipp_packet_get_data(packet); 502 tswtcl_data = (tswtcl_data_t *)ipp_action_get_ptr(aid); 503 ASSERT(tswtcl_data != NULL); 504 505 /* tswtcl packet as configured */ 506 if ((rc = tswtcl_process(&mp, tswtcl_data, &next_action)) != 0) { 507 return (rc); 508 } else { 509 return (ipp_packet_next(packet, next_action)); 510 } 511 } 512 513 static int 514 tswtcl_statinit(ipp_action_id_t aid, tswtcl_data_t *tswtcl_data) 515 { 516 int rc = 0; 517 meter_stat_t *statsp; 518 519 /* install stats entry */ 520 if ((rc = ipp_stat_create(aid, TSWTCL_STATS_STRING, METER_STATS_COUNT, 521 tswtcl_update_stats, tswtcl_data, &tswtcl_data->stats)) != 0) { 522 tswtcl0dbg(("tswtcl_statinit:ipp_stat_create failed "\ 523 " with %d\n", rc)); 524 return (rc); 525 } 526 527 statsp = (meter_stat_t *)(tswtcl_data->stats)->ipps_data; 528 ASSERT(statsp != NULL); 529 530 if ((rc = ipp_stat_named_init(tswtcl_data->stats, "red_packets", 531 IPP_STAT_UINT64, &statsp->red_packets)) != 0) { 532 tswtcl0dbg(("tswtcl_statinit:ipp_stat_create failed "\ 533 " with %d\n", rc)); 534 return (rc); 535 } 536 if ((rc = ipp_stat_named_init(tswtcl_data->stats, "red_bits", 537 IPP_STAT_UINT64, &statsp->red_bits)) != 0) { 538 tswtcl0dbg(("tswtcl_statinit:ipp_stat_create failed "\ 539 " with %d\n", rc)); 540 return (rc); 541 } 542 if ((rc = ipp_stat_named_init(tswtcl_data->stats, "yellow_packets", 543 IPP_STAT_UINT64, &statsp->yellow_packets)) != 0) { 544 tswtcl0dbg(("tswtcl_statinit:ipp_stat_named_init failed "\ 545 " with %d\n", rc)); 546 return (rc); 547 } 548 if ((rc = ipp_stat_named_init(tswtcl_data->stats, "yellow_bits", 549 IPP_STAT_UINT64, &statsp->yellow_bits)) != 0) { 550 tswtcl0dbg(("tswtcl_statinit:ipp_stat_create failed "\ 551 " with %d\n", rc)); 552 return (rc); 553 } 554 if ((rc = ipp_stat_named_init(tswtcl_data->stats, "green_packets", 555 IPP_STAT_UINT64, &statsp->green_packets)) != 0) { 556 tswtcl0dbg(("tswtcl_statinit:ipp_stat_named_init failed "\ 557 " with %d\n", rc)); 558 return (rc); 559 } 560 if ((rc = ipp_stat_named_init(tswtcl_data->stats, "green_bits", 561 IPP_STAT_UINT64, &statsp->green_bits)) != 0) { 562 tswtcl0dbg(("tswtcl_statinit:ipp_stat_create failed "\ 563 " with %d\n", rc)); 564 return (rc); 565 } 566 if ((rc = ipp_stat_named_init(tswtcl_data->stats, "epackets", 567 IPP_STAT_UINT64, &statsp->epackets)) != 0) { 568 tswtcl0dbg(("tswtcl_statinit:ipp_stat_named_init failed "\ 569 " with %d\n", rc)); 570 return (rc); 571 } 572 ipp_stat_install(tswtcl_data->stats); 573 574 return (rc); 575 576 } 577 578 static int 579 tswtcl_update_stats(ipp_stat_t *sp, void *args, int rw) 580 { 581 tswtcl_data_t *tswtcl_data = (tswtcl_data_t *)args; 582 meter_stat_t *stats = (meter_stat_t *)sp->ipps_data; 583 584 ASSERT((tswtcl_data != NULL) && (stats != NULL)); 585 586 (void) ipp_stat_named_op(&stats->red_packets, &tswtcl_data->red_packets, 587 rw); 588 (void) ipp_stat_named_op(&stats->yellow_packets, 589 &tswtcl_data->yellow_packets, rw); 590 (void) ipp_stat_named_op(&stats->green_packets, 591 &tswtcl_data->green_packets, rw); 592 593 (void) ipp_stat_named_op(&stats->red_bits, &tswtcl_data->red_bits, rw); 594 (void) ipp_stat_named_op(&stats->yellow_bits, 595 &tswtcl_data->yellow_bits, rw); 596 (void) ipp_stat_named_op(&stats->green_bits, 597 &tswtcl_data->green_bits, rw); 598 599 (void) ipp_stat_named_op(&stats->epackets, &tswtcl_data->epackets, 600 rw); 601 602 return (0); 603 } 604 605 /* ARGSUSED */ 606 static int 607 tswtcl_info(ipp_action_id_t aid, int (*fn)(nvlist_t *, void *), void *arg, 608 ipp_flags_t flags) 609 { 610 nvlist_t *nvlp; 611 tswtcl_data_t *tswtcl_data; 612 tswtcl_cfg_t *cfg_parms; 613 char *next_action; 614 int rc; 615 616 tswtcl_data = (tswtcl_data_t *)ipp_action_get_ptr(aid); 617 ASSERT(tswtcl_data != NULL); 618 619 cfg_parms = tswtcl_data->cfg_parms; 620 621 /* allocate nvlist to be passed back */ 622 if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, KM_NOSLEEP)) != 0) { 623 tswtcl0dbg(("tswtcl_info: memory allocation failure\n")); 624 return (rc); 625 } 626 627 /* look up red next action with the next action id */ 628 if ((rc = ipp_action_name(cfg_parms->red_action, &next_action)) != 0) { 629 tswtcl0dbg(("tswtcl_info: red action not available\n")); 630 nvlist_free(nvlp); 631 return (rc); 632 } 633 634 /* add next action name */ 635 if ((rc = nvlist_add_string(nvlp, TSWTCL_RED_ACTION_NAME, 636 next_action)) != 0) { 637 tswtcl0dbg(("tswtcl_info: error adding\n")); 638 nvlist_free(nvlp); 639 kmem_free(next_action, (strlen(next_action) + 1)); 640 return (rc); 641 } 642 643 /* free action name */ 644 kmem_free(next_action, (strlen(next_action) + 1)); 645 646 /* look up yellow next action with the next action id */ 647 if ((rc = ipp_action_name(cfg_parms->yellow_action, 648 &next_action)) != 0) { 649 tswtcl0dbg(("tswtcl_info: yellow action not available\n")); 650 nvlist_free(nvlp); 651 return (rc); 652 } 653 654 /* add next action name */ 655 if ((rc = nvlist_add_string(nvlp, TSWTCL_YELLOW_ACTION_NAME, 656 next_action)) != 0) { 657 tswtcl0dbg(("tswtcl_info: error adding yellow action\n")); 658 nvlist_free(nvlp); 659 kmem_free(next_action, (strlen(next_action) + 1)); 660 return (rc); 661 } 662 /* free action name */ 663 kmem_free(next_action, (strlen(next_action) + 1)); 664 665 /* look up green next action with the next action id */ 666 if ((rc = ipp_action_name(cfg_parms->green_action, 667 &next_action)) != 0) { 668 tswtcl0dbg(("tswtcl_info: green action not available\n")); 669 nvlist_free(nvlp); 670 return (rc); 671 } 672 673 /* add next action name */ 674 if ((rc = nvlist_add_string(nvlp, TSWTCL_GREEN_ACTION_NAME, 675 next_action)) != 0) { 676 tswtcl0dbg(("tswtcl_info: error adding green action\n")); 677 nvlist_free(nvlp); 678 kmem_free(next_action, (strlen(next_action) + 1)); 679 return (rc); 680 } 681 682 /* free action name */ 683 kmem_free(next_action, (strlen(next_action) + 1)); 684 685 /* add config type */ 686 if ((rc = nvlist_add_byte(nvlp, IPP_CONFIG_TYPE, IPP_SET)) != 0) { 687 tswtcl0dbg(("tswtcl_info: error adding config_type\n")); 688 nvlist_free(nvlp); 689 return (rc); 690 } 691 692 /* add committed_rate */ 693 if ((rc = nvlist_add_uint32(nvlp, TSWTCL_COMMITTED_RATE, 694 cfg_parms->committed_rate)) != 0) { 695 tswtcl0dbg(("tswtcl_info: error adding committed_rate\n")); 696 nvlist_free(nvlp); 697 return (rc); 698 } 699 700 /* add peak_rate */ 701 if ((rc = nvlist_add_uint32(nvlp, TSWTCL_PEAK_RATE, 702 cfg_parms->peak_rate)) != 0) { 703 tswtcl0dbg(("tswtcl_info: error adding peak_rate\n")); 704 nvlist_free(nvlp); 705 return (rc); 706 } 707 708 /* add window */ 709 if ((rc = nvlist_add_uint32(nvlp, TSWTCL_WINDOW, 710 cfg_parms->window)) != 0) { 711 tswtcl0dbg(("tswtcl_info: error adding window\n")); 712 nvlist_free(nvlp); 713 return (rc); 714 } 715 716 if ((rc = nvlist_add_uint32(nvlp, IPP_ACTION_STATS_ENABLE, 717 (uint32_t)(uintptr_t)tswtcl_data->stats)) != 0) { 718 tswtcl0dbg(("tswtcl_info: error adding stats status\n")); 719 nvlist_free(nvlp); 720 return (rc); 721 } 722 723 /* call back with nvlist */ 724 rc = fn(nvlp, arg); 725 726 nvlist_free(nvlp); 727 return (rc); 728 }