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