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