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 2002 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/dlcosmk/dlcosmk_impl.h> 40 41 #define D_SM_COMMENT "IPP dlcosmk marker module" 42 43 /* DDI file for dlcosmk ipp module */ 44 45 static int dlcosmk_create_action(ipp_action_id_t, nvlist_t **, ipp_flags_t); 46 static int dlcosmk_modify_action(ipp_action_id_t, nvlist_t **, ipp_flags_t); 47 static int dlcosmk_destroy_action(ipp_action_id_t, ipp_flags_t); 48 static int dlcosmk_info(ipp_action_id_t, int (*)(nvlist_t *, void *), void *, 49 ipp_flags_t); 50 static int dlcosmk_invoke_action(ipp_action_id_t, ipp_packet_t *); 51 52 static int dlcosmk_statinit(ipp_action_id_t, dlcosmk_data_t *); 53 static int dlcosmk_update_stats(ipp_stat_t *, void *, int); 54 55 /* Entry points for this IPP module */ 56 ipp_ops_t dlcosmk_ops = { 57 IPPO_REV, 58 dlcosmk_create_action, /* ippo_action_create */ 59 dlcosmk_modify_action, /* ippo_action_modify */ 60 dlcosmk_destroy_action, /* ippo_action_destroy */ 61 dlcosmk_info, /* ippo_action_info */ 62 dlcosmk_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 " %I%", 73 &dlcosmk_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 static int 102 dlcosmk_create_action(ipp_action_id_t aid, nvlist_t **nvlpp, 103 ipp_flags_t flags) 104 { 105 nvlist_t *nvlp; 106 dlcosmk_data_t *dlcosmk_data; 107 char *next_action; 108 int err; 109 uint32_t bstats, param; 110 111 ASSERT((nvlpp != NULL) && (*nvlpp != NULL)); 112 113 nvlp = *nvlpp; 114 *nvlpp = NULL; /* nvlist should be NULL on return */ 115 116 if ((dlcosmk_data = kmem_zalloc(DLCOSMK_DATA_SZ, KM_NOSLEEP)) == NULL) { 117 nvlist_free(nvlp); 118 return (ENOMEM); 119 } 120 121 /* parse next action name */ 122 if ((err = nvlist_lookup_string(nvlp, DLCOSMK_NEXT_ACTION_NAME, 123 &next_action)) != 0) { 124 nvlist_free(nvlp); 125 dlcosmk0dbg(("dlcosmk_create_action: invalid config, "\ 126 "next_action name missing\n")); 127 kmem_free(dlcosmk_data, DLCOSMK_DATA_SZ); 128 return (err); 129 } 130 if ((dlcosmk_data->next_action = 131 ipp_action_lookup(next_action)) == IPP_ACTION_INVAL) { 132 nvlist_free(nvlp); 133 dlcosmk0dbg(("dlcosmk_create_action: next_action invalid\n")); 134 kmem_free(dlcosmk_data, DLCOSMK_DATA_SZ); 135 return (EINVAL); 136 } 137 138 /* parse cos - from the config file */ 139 if ((err = nvlist_lookup_byte(nvlp, DLCOSMK_COS, 140 &dlcosmk_data->usr_pri)) != 0) { 141 nvlist_free(nvlp); 142 dlcosmk0dbg(("dlcosmk_create_action: invalid config, "\ 143 "cos missing\n")); 144 kmem_free(dlcosmk_data, DLCOSMK_DATA_SZ); 145 return (err); 146 } 147 148 /* parse b_band - mapped from cos */ 149 if ((err = nvlist_lookup_uint32(nvlp, DLCOSMK_BAND, ¶m)) != 0) { 150 nvlist_free(nvlp); 151 dlcosmk0dbg(("dlcosmk_create_action: invalid config, "\ 152 "b_band missing\n")); 153 kmem_free(dlcosmk_data, DLCOSMK_DATA_SZ); 154 return (err); 155 } 156 dlcosmk_data->b_band = param; 157 158 /* parse dl_priority.dl_max - mapped from cos */ 159 if ((err = nvlist_lookup_uint32(nvlp, DLCOSMK_PRI, ¶m)) != 0) { 160 nvlist_free(nvlp); 161 dlcosmk0dbg(("dlcosmk_create_action: invalid config, "\ 162 "dl_priority missing\n")); 163 kmem_free(dlcosmk_data, DLCOSMK_DATA_SZ); 164 return (err); 165 } 166 dlcosmk_data->dl_max = param; 167 168 /* parse gather_stats boolean */ 169 if ((err = nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE, &bstats)) 170 != 0) { 171 dlcosmk_data->gather_stats = B_FALSE; 172 } else { 173 /* If stats is needed, initialize the stats structure */ 174 dlcosmk_data->gather_stats = (bstats != 0) ? B_TRUE : B_FALSE; 175 if (dlcosmk_data->gather_stats) { 176 if ((err = dlcosmk_statinit(aid, dlcosmk_data)) != 0) { 177 nvlist_free(nvlp); 178 kmem_free(dlcosmk_data, DLCOSMK_DATA_SZ); 179 return (err); 180 } 181 } 182 } 183 184 /* Free the nvlist */ 185 nvlist_free(nvlp); 186 187 /* set action chain reference */ 188 if ((err = ipp_action_ref(aid, dlcosmk_data->next_action, 189 flags)) != 0) { 190 dlcosmk0dbg(("dlcosmk_create_action: ipp_action_ref " \ 191 "returned with error %d\n", err)); 192 ipp_stat_destroy(dlcosmk_data->stats); 193 kmem_free(dlcosmk_data, DLCOSMK_DATA_SZ); 194 return (err); 195 } 196 197 ipp_action_set_ptr(aid, (void *)dlcosmk_data); 198 return (0); 199 } 200 201 static int 202 dlcosmk_modify_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags) 203 { 204 nvlist_t *nvlp; 205 int err = 0; 206 uint32_t band, dlpri; 207 uint8_t config_type; 208 uint8_t cos; 209 char *next_action_name; 210 ipp_action_id_t next_action; 211 dlcosmk_data_t *dlcosmk_data; 212 uint32_t bstats; 213 214 ASSERT((nvlpp != NULL) && (*nvlpp != NULL)); 215 216 nvlp = *nvlpp; 217 *nvlpp = NULL; /* nvlist should be NULL when this returns */ 218 219 if ((err = nvlist_lookup_byte(nvlp, IPP_CONFIG_TYPE, &config_type)) 220 != 0) { 221 nvlist_free(nvlp); 222 dlcosmk0dbg(("dlcosmk_modify_action: invalid configuration "\ 223 "type\n")); 224 return (err); 225 } 226 227 if (config_type != IPP_SET) { 228 nvlist_free(nvlp); 229 dlcosmk0dbg(("dlcosmk_modify_action: invalid configuration "\ 230 "type %d\n", config_type)); 231 return (EINVAL); 232 } 233 234 dlcosmk_data = (dlcosmk_data_t *)ipp_action_get_ptr(aid); 235 ASSERT(dlcosmk_data != NULL); 236 237 /* parse next action name, if present */ 238 if ((err = nvlist_lookup_string(nvlp, DLCOSMK_NEXT_ACTION_NAME, 239 &next_action_name)) == 0) { 240 /* lookup action name to get action id */ 241 if ((next_action = ipp_action_lookup(next_action_name)) 242 == IPP_ACTION_INVAL) { 243 nvlist_free(nvlp); 244 dlcosmk0dbg(("dlcosmk_modify_action: next_action "\ 245 "invalid\n")); 246 return (EINVAL); 247 } 248 /* reference new action */ 249 if ((err = ipp_action_ref(aid, next_action, flags)) != 0) { 250 nvlist_free(nvlp); 251 dlcosmk0dbg(("dlcosmk_modify_action: ipp_action_ref "\ 252 "returned with error %d\n", err)); 253 return (err); 254 } 255 /* unref old action */ 256 err = ipp_action_unref(aid, dlcosmk_data->next_action, flags); 257 ASSERT(err == 0); 258 dlcosmk_data->next_action = next_action; 259 } 260 261 /* parse cos, if present */ 262 if ((err = nvlist_lookup_byte(nvlp, DLCOSMK_COS, &cos)) == 0) { 263 264 /* parse b_band, mapped from cos */ 265 if ((err = nvlist_lookup_uint32(nvlp, DLCOSMK_BAND, 266 &band)) != 0) { 267 nvlist_free(nvlp); 268 dlcosmk0dbg(("dlcosmk_modify_action: b_band not "\ 269 "provided\n")); 270 return (err); 271 } 272 273 /* parse dl_priority, mapped from cos */ 274 if ((err = nvlist_lookup_uint32(nvlp, DLCOSMK_PRI, 275 &dlpri)) != 0) { 276 nvlist_free(nvlp); 277 dlcosmk0dbg(("dlcosmk_modify_action: dl_priority not "\ 278 "provided\n")); 279 return (err); 280 } 281 282 /* Have all the three values, change them */ 283 dlcosmk_data->usr_pri = cos; 284 dlcosmk_data->b_band = band; 285 dlcosmk_data->dl_max = dlpri; 286 } 287 288 289 /* parse gather_stats boolean, if present */ 290 if ((err = nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE, &bstats)) 291 == 0) { 292 boolean_t val = (bstats != 0) ? B_TRUE : B_FALSE; 293 /* Turning on stats */ 294 if (!dlcosmk_data->gather_stats && val) { 295 if ((err = dlcosmk_statinit(aid, dlcosmk_data)) != 0) { 296 nvlist_free(nvlp); 297 return (err); 298 } 299 /* Turning off stats */ 300 } else if (!val && dlcosmk_data->gather_stats) { 301 ipp_stat_destroy(dlcosmk_data->stats); 302 303 } 304 dlcosmk_data->gather_stats = val; 305 } 306 307 /* Free thenvlist */ 308 nvlist_free(nvlp); 309 return (0); 310 } 311 312 static int 313 dlcosmk_destroy_action(ipp_action_id_t aid, ipp_flags_t flags) 314 { 315 dlcosmk_data_t *dlcosmk_data; 316 int err; 317 318 dlcosmk_data = (dlcosmk_data_t *)ipp_action_get_ptr(aid); 319 ASSERT(dlcosmk_data != NULL); 320 321 /* Destroy stats, if gathered */ 322 if (dlcosmk_data->gather_stats) { 323 ipp_stat_destroy(dlcosmk_data->stats); 324 } 325 326 /* unreference the action */ 327 err = ipp_action_unref(aid, dlcosmk_data->next_action, flags); 328 ASSERT(err == 0); 329 330 kmem_free(dlcosmk_data, DLCOSMK_DATA_SZ); 331 return (0); 332 } 333 334 static int 335 dlcosmk_invoke_action(ipp_action_id_t aid, ipp_packet_t *packet) 336 { 337 dlcosmk_data_t *dlcosmk_data; 338 mblk_t *mp = NULL; 339 int err; 340 ip_priv_t *priv; 341 342 ASSERT(packet != NULL); 343 344 /* get mblk from ipp_packet structure */ 345 mp = ipp_packet_get_data(packet); 346 priv = (ip_priv_t *)ipp_packet_get_private(packet); 347 348 dlcosmk_data = (dlcosmk_data_t *)ipp_action_get_ptr(aid); 349 ASSERT(dlcosmk_data != NULL); 350 351 /* dlcosmk packet as configured */ 352 if ((err = dlcosmk_process(&mp, dlcosmk_data, priv->ill_index, 353 priv->proc)) != 0) { 354 return (err); 355 } else { 356 /* return packet with next action set */ 357 return (ipp_packet_next(packet, dlcosmk_data->next_action)); 358 } 359 } 360 361 static int 362 dlcosmk_statinit(ipp_action_id_t aid, dlcosmk_data_t *dlcosmk_data) 363 { 364 int err; 365 dlcosmk_stat_t *statp; 366 367 /* install stats entry */ 368 if ((err = ipp_stat_create(aid, DLCOSMK_STATS_STRING, 369 DLCOSMK_STATS_COUNT, dlcosmk_update_stats, dlcosmk_data, 370 &dlcosmk_data->stats)) != 0) { 371 dlcosmk0dbg(("dlcosmk_create_action: ipp_stat_create " \ 372 "returned with error %d\n", err)); 373 return (err); 374 } 375 376 statp = (dlcosmk_stat_t *)(dlcosmk_data->stats)->ipps_data; 377 ASSERT(statp != NULL); 378 379 if ((err = ipp_stat_named_init(dlcosmk_data->stats, "npackets", 380 IPP_STAT_UINT64, &statp->npackets)) != 0) { 381 dlcosmk0dbg(("dlcosmk_create_action: ipp_stat_named_init " \ 382 "returned with error %d\n", err)); 383 return (err); 384 } 385 386 if ((err = ipp_stat_named_init(dlcosmk_data->stats, "ipackets", 387 IPP_STAT_UINT64, &statp->ipackets)) != 0) { 388 dlcosmk0dbg(("dlcosmk_create_action: ipp_stat_named_init " \ 389 "returned with error %d\n", err)); 390 return (err); 391 } 392 393 if ((err = ipp_stat_named_init(dlcosmk_data->stats, "epackets", 394 IPP_STAT_UINT64, &statp->epackets)) != 0) { 395 dlcosmk0dbg(("dlcosmk_create_action: ipp_stat_named_init " \ 396 "returned with error %d\n", err)); 397 return (err); 398 } 399 400 if ((err = ipp_stat_named_init(dlcosmk_data->stats, "usr_pri", 401 IPP_STAT_INT32, &statp->usr_pri)) != 0) { 402 dlcosmk0dbg(("dlcosmk_create_action: ipp_stat_named_init " \ 403 "returned with error %d", err)); 404 return (err); 405 } 406 407 if ((err = ipp_stat_named_init(dlcosmk_data->stats, "b_band", 408 IPP_STAT_INT32, &statp->b_band)) != 0) { 409 dlcosmk0dbg(("dlcosmk_create_action: ipp_stat_named_init " \ 410 "returned with error %d\n", err)); 411 return (err); 412 } 413 414 if ((err = ipp_stat_named_init(dlcosmk_data->stats, "dl_max", 415 IPP_STAT_INT32, &statp->dl_max)) != 0) { 416 dlcosmk0dbg(("dlcosmk_create_action: ipp_stat_named_init " \ 417 "returned with error %d\n", err)); 418 return (err); 419 } 420 421 ipp_stat_install(dlcosmk_data->stats); 422 return (0); 423 } 424 425 static int 426 dlcosmk_update_stats(ipp_stat_t *sp, void *arg, int rw) 427 { 428 dlcosmk_data_t *dlcosmk_data = (dlcosmk_data_t *)arg; 429 dlcosmk_stat_t *snames = (dlcosmk_stat_t *)sp->ipps_data; 430 uint32_t upri, bband; 431 432 ASSERT(dlcosmk_data != NULL); 433 ASSERT(snames != NULL); 434 435 upri = dlcosmk_data->usr_pri; 436 bband = dlcosmk_data->b_band; 437 438 (void) ipp_stat_named_op(&snames->npackets, &dlcosmk_data->npackets, 439 rw); 440 (void) ipp_stat_named_op(&snames->ipackets, &dlcosmk_data->ipackets, 441 rw); 442 (void) ipp_stat_named_op(&snames->epackets, &dlcosmk_data->epackets, 443 rw); 444 (void) ipp_stat_named_op(&snames->usr_pri, &upri, rw); 445 (void) ipp_stat_named_op(&snames->b_band, &bband, rw); 446 (void) ipp_stat_named_op(&snames->dl_max, &dlcosmk_data->dl_max, rw); 447 448 return (0); 449 } 450 451 /* ARGSUSED */ 452 static int 453 dlcosmk_info(ipp_action_id_t aid, int (*fn)(nvlist_t *, void *), void *arg, 454 ipp_flags_t flags) 455 { 456 nvlist_t *nvlp; 457 dlcosmk_data_t *dlcosmk_data; 458 char *next_action; 459 int err; 460 461 ASSERT(fn != NULL); 462 463 dlcosmk_data = (dlcosmk_data_t *)ipp_action_get_ptr(aid); 464 ASSERT(dlcosmk_data != NULL); 465 466 /* allocate nvlist to be passed back */ 467 if ((err = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, KM_NOSLEEP)) != 0) { 468 dlcosmk0dbg(("dlcosmk_info: error allocating memory\n")); 469 return (err); 470 } 471 472 /* look up next action with the next action id */ 473 if ((err = ipp_action_name(dlcosmk_data->next_action, 474 &next_action)) != 0) { 475 dlcosmk0dbg(("dlcosmk_info: next action not available\n")); 476 nvlist_free(nvlp); 477 return (err); 478 } 479 480 /* add next action name */ 481 if ((err = nvlist_add_string(nvlp, DLCOSMK_NEXT_ACTION_NAME, 482 next_action)) != 0) { 483 dlcosmk0dbg(("dlcosmk_info: error adding next action\n")); 484 nvlist_free(nvlp); 485 kmem_free(next_action, (strlen(next_action) + 1)); 486 return (err); 487 } 488 489 /* free action name */ 490 kmem_free(next_action, (strlen(next_action) + 1)); 491 492 /* add config type */ 493 if ((err = nvlist_add_byte(nvlp, IPP_CONFIG_TYPE, IPP_SET)) != 0) { 494 dlcosmk0dbg(("dlcosmk_info: error adding config. type\n")); 495 nvlist_free(nvlp); 496 return (err); 497 } 498 499 /* just give the cos, since that is what is provided in the config */ 500 if ((err = nvlist_add_byte(nvlp, DLCOSMK_COS, dlcosmk_data->usr_pri)) 501 != 0) { 502 dlcosmk0dbg(("dlcosmk_info: error adding cos\n")); 503 nvlist_free(nvlp); 504 return (err); 505 } 506 507 /* add gather stats boolean */ 508 if ((err = nvlist_add_uint32(nvlp, IPP_ACTION_STATS_ENABLE, 509 (dlcosmk_data->gather_stats ? 1 : 0))) != 0) { 510 dlcosmk0dbg(("dlcosmk_info: error adding stats status\n")); 511 nvlist_free(nvlp); 512 return (err); 513 } 514 515 /* call back with nvlist */ 516 err = fn(nvlp, arg); 517 518 nvlist_free(nvlp); 519 return (err); 520 } 521