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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/types.h>
27 #include <sys/systm.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <sys/modctl.h>
31 #include <sys/sunddi.h>
33 #include <ipp/ipp_config.h>
34 #include <inet/common.h>
35 #include <ipp/dscpmk/dscpmk_impl.h>
37 #define D_SM_COMMENT "IPP dscpmk marker module"
39 /* DDI file for dscpmk ipp module */
41 /* default dscp map - dscp unchanged */
42 uint8_t default_dscp_map
[DSCPMK_ARRAY_COUNT
] = {
61 static int dscpmk_create_action(ipp_action_id_t
, nvlist_t
**, ipp_flags_t
);
62 static int dscpmk_modify_action(ipp_action_id_t
, nvlist_t
**, ipp_flags_t
);
63 static int dscpmk_destroy_action(ipp_action_id_t
, ipp_flags_t
);
64 static int dscpmk_info(ipp_action_id_t
, int (*)(nvlist_t
*, void *), void *,
66 static int dscpmk_invoke_action(ipp_action_id_t
, ipp_packet_t
*);
68 /* Creating and updating summary stats */
69 static int dscpmk_summ_statinit(ipp_action_id_t
, dscpmk_data_t
*);
70 static int dscpmk_update_stats(ipp_stat_t
*, void *, int);
72 /* Creating and updating per-dscp stats */
73 static int dscpmk_det_statinit(ipp_action_id_t
, dscpmk_data_t
*, int);
74 static int dscpmk_update_det_stats(ipp_stat_t
*, void *, int);
76 /* Entry points for this IPP module */
77 ipp_ops_t dscpmk_ops
= {
79 dscpmk_create_action
, /* ippo_action_create */
80 dscpmk_modify_action
, /* ippo_action_modify */
81 dscpmk_destroy_action
, /* ippo_action_destroy */
82 dscpmk_info
, /* ippo_action_info */
83 dscpmk_invoke_action
/* ippo_action_invoke */
86 extern struct mod_ops mod_ippops
;
89 * Module linkage information for the kernel.
91 static struct modlipp modlipp
= {
97 static struct modlinkage modlinkage
= {
107 return (mod_install(&modlinkage
));
113 return (mod_remove(&modlinkage
));
117 _info(struct modinfo
*modinfop
)
119 return (mod_info(&modlinkage
, modinfop
));
123 dscpmk_create_action(ipp_action_id_t aid
, nvlist_t
**nvlpp
, ipp_flags_t flags
)
126 dscpmk_data_t
*dscpmk_data
;
130 uint_t nelem
= DSCPMK_ARRAY_COUNT
;
133 ASSERT((nvlpp
!= NULL
) && (*nvlpp
!= NULL
));
136 *nvlpp
= NULL
; /* nvlist should be NULL on return */
138 if ((dscpmk_data
= kmem_zalloc(DSCPMK_DATA_SZ
, KM_NOSLEEP
)) == NULL
) {
143 /* parse next action name */
144 if ((err
= nvlist_lookup_string(nvlp
, DSCPMK_NEXT_ACTION_NAME
,
145 &next_action
)) != 0) {
147 dscpmk0dbg(("dscpmk_create_action: invalid config, " \
148 "next_action name missing\n"));
149 kmem_free(dscpmk_data
, DSCPMK_DATA_SZ
);
153 if ((dscpmk_data
->next_action
= ipp_action_lookup(next_action
))
154 == IPP_ACTION_INVAL
) {
156 dscpmk0dbg(("dscpmk_create_action: next_action "\
158 kmem_free(dscpmk_data
, DSCPMK_DATA_SZ
);
162 /* Fill in the default value */
163 bcopy(default_dscp_map
, dscpmk_data
->dscp_map
,
164 sizeof (default_dscp_map
));
166 * parse dscp_map, if present. Note that the module gets
167 * the entire array with unchanged entries marked with -1.
169 if ((err
= nvlist_lookup_int32_array(nvlp
, DSCPMK_DSCP_MAP
,
170 &tbl
, &nelem
)) == 0) {
171 for (cnt
= 0; cnt
< DSCPMK_ARRAY_COUNT
; cnt
++) {
172 if ((tbl
[cnt
] != DSCPMK_UNCHANGED_DSCP
) && (tbl
[cnt
] !=
173 dscpmk_data
->dscp_map
[cnt
])) {
174 dscpmk_data
->dscp_map
[cnt
] = tbl
[cnt
];
180 /* parse summary_stats boolean */
181 if ((err
= nvlist_lookup_uint32(nvlp
, IPP_ACTION_STATS_ENABLE
, &bstats
))
183 dscpmk_data
->summary_stats
= B_FALSE
;
185 dscpmk_data
->summary_stats
= (bstats
!= 0) ? B_TRUE
: B_FALSE
;
186 /* If stats is needed, initialize the stats structure */
187 if (dscpmk_data
->summary_stats
) {
188 if ((err
= dscpmk_summ_statinit(aid
, dscpmk_data
))
191 kmem_free(dscpmk_data
, DSCPMK_DATA_SZ
);
198 * Initialize per-dscp stats; B_FALSE in present indicates a dscp
199 * with this value (count) is not present in the map.
201 for (cnt
= 0; cnt
< DSCPMK_ARRAY_COUNT
; cnt
++) {
202 dscpmk_data
->dscp_stats
[cnt
].present
= B_FALSE
;
203 dscpmk_data
->dscp_stats
[cnt
].npackets
= 0;
206 /* parse detailed_stats boolean */
207 if ((err
= nvlist_lookup_uint32(nvlp
, DSCPMK_DETAILED_STATS
, &bstats
))
209 dscpmk_data
->detailed_stats
= B_FALSE
;
211 dscpmk_data
->detailed_stats
= (bstats
!= 0) ? B_TRUE
: B_FALSE
;
212 /* If stats is needed, initialize the stats structure */
213 if (dscpmk_data
->detailed_stats
) {
214 for (cnt
= 0; cnt
< DSCPMK_ARRAY_COUNT
; cnt
++) {
215 int val
= dscpmk_data
->dscp_map
[cnt
];
216 if (dscpmk_data
->dscp_stats
[val
].present
) {
219 dscpmk_data
->dscp_stats
[val
].present
= B_TRUE
;
220 if ((err
= dscpmk_det_statinit(aid
, dscpmk_data
,
223 kmem_free(dscpmk_data
, DSCPMK_DATA_SZ
);
230 /* Free the nvlist */
233 /* set action chain reference */
234 if ((err
= ipp_action_ref(aid
, dscpmk_data
->next_action
, flags
)) != 0) {
235 dscpmk0dbg(("dscpmk_create_action: ipp_action_ref " \
236 "returned with error %d\n", err
));
237 if (dscpmk_data
->summary_stats
) {
238 ipp_stat_destroy(dscpmk_data
->stats
);
240 if (dscpmk_data
->detailed_stats
) {
241 for (cnt
= 0; cnt
< DSCPMK_ARRAY_COUNT
; cnt
++) {
242 if (dscpmk_data
->dscp_stats
[cnt
].present
) {
244 dscpmk_data
->dscp_stats
[cnt
].stats
);
248 kmem_free(dscpmk_data
, DSCPMK_DATA_SZ
);
252 ipp_action_set_ptr(aid
, (void *)dscpmk_data
);
257 dscpmk_modify_action(ipp_action_id_t aid
, nvlist_t
**nvlpp
, ipp_flags_t flags
)
262 char *next_action_name
;
264 uint_t nelem
= DSCPMK_ARRAY_COUNT
;
266 ipp_action_id_t next_action
;
267 dscpmk_data_t
*dscpmk_data
;
269 ASSERT((nvlpp
!= NULL
) && (*nvlpp
!= NULL
));
272 *nvlpp
= NULL
; /* nvlist should be NULL when this returns */
274 if ((err
= nvlist_lookup_byte(nvlp
, IPP_CONFIG_TYPE
, &config_type
))
277 dscpmk0dbg(("dscpmk_modify_action: invalid cfg. type\n"));
281 if (config_type
!= IPP_SET
) {
283 dscpmk0dbg(("dscpmk_modify_action: invalid cfg. type " \
284 "%d\n", config_type
));
288 dscpmk_data
= (dscpmk_data_t
*)ipp_action_get_ptr(aid
);
289 ASSERT(dscpmk_data
!= NULL
);
291 /* parse next action name, if present */
292 if ((err
= nvlist_lookup_string(nvlp
, DSCPMK_NEXT_ACTION_NAME
,
293 &next_action_name
)) == 0) {
294 /* lookup action name to get action id */
295 if ((next_action
= ipp_action_lookup(next_action_name
))
296 == IPP_ACTION_INVAL
) {
298 dscpmk0dbg(("dscpmk_modify_action: next_action "\
302 /* reference new action */
303 if ((err
= ipp_action_ref(aid
, next_action
, flags
)) != 0) {
305 dscpmk0dbg(("dscpmk_modify_action: ipp_action_ref " \
306 "returned with error %d\n", err
));
309 /* unref old action */
310 err
= ipp_action_unref(aid
, dscpmk_data
->next_action
, flags
);
312 dscpmk_data
->next_action
= next_action
;
316 * parse dscp_map, if present. Note that the module gets
317 * the entire array with unchanged entries marked with -1.
318 * If this array is absent during modification, it means revert to
321 if ((err
= nvlist_lookup_int32_array(nvlp
, DSCPMK_DSCP_MAP
,
322 &tbl
, &nelem
)) == 0) {
323 for (cnt
= 0; cnt
< DSCPMK_ARRAY_COUNT
; cnt
++) {
324 if ((tbl
[cnt
] != DSCPMK_UNCHANGED_DSCP
) && (tbl
[cnt
] !=
325 dscpmk_data
->dscp_map
[cnt
])) {
326 dscpmk_data
->dscp_map
[cnt
] = tbl
[cnt
];
330 bcopy(default_dscp_map
, dscpmk_data
->dscp_map
,
331 sizeof (default_dscp_map
));
334 /* parse summary_stats boolean, if present */
335 if ((err
= nvlist_lookup_uint32(nvlp
, IPP_ACTION_STATS_ENABLE
, &bstats
))
337 boolean_t val
= (bstats
!= 0) ? B_TRUE
: B_FALSE
;
338 /* Turning on stats */
339 if (!dscpmk_data
->summary_stats
&& val
) {
340 if ((err
= dscpmk_summ_statinit(aid
, dscpmk_data
))
345 /* Turning off stats */
346 } else if (!val
&& dscpmk_data
->summary_stats
) {
347 ipp_stat_destroy(dscpmk_data
->stats
);
350 dscpmk_data
->summary_stats
= val
;
353 /* parse detailed_stats boolean */
354 if ((err
= nvlist_lookup_uint32(nvlp
, DSCPMK_DETAILED_STATS
, &bstats
))
356 boolean_t val
= (bstats
!= 0) ? B_TRUE
: B_FALSE
;
357 if (dscpmk_data
->detailed_stats
&& !val
) {
358 for (cnt
= 0; cnt
< DSCPMK_ARRAY_COUNT
; cnt
++) {
359 if (dscpmk_data
->dscp_stats
[cnt
].present
) {
360 dscpmk_data
->dscp_stats
[cnt
].present
=
362 ipp_stat_destroy(dscpmk_data
->
363 dscp_stats
[cnt
].stats
);
367 dscpmk_data
->detailed_stats
= val
;
370 /* The map might have changed */
371 if (dscpmk_data
->detailed_stats
) {
372 for (cnt
= 0; cnt
< DSCPMK_ARRAY_COUNT
; cnt
++) {
373 int val
= dscpmk_data
->dscp_map
[cnt
];
374 if (!dscpmk_data
->dscp_stats
[val
].present
) {
375 dscpmk_data
->dscp_stats
[val
].present
= B_TRUE
;
376 if ((err
= dscpmk_det_statinit(aid
, dscpmk_data
,
385 /* Free the nvlist */
391 dscpmk_destroy_action(ipp_action_id_t aid
, ipp_flags_t flags
)
393 dscpmk_data_t
*dscpmk_data
;
396 dscpmk_data
= (dscpmk_data_t
*)ipp_action_get_ptr(aid
);
397 ASSERT(dscpmk_data
!= NULL
);
399 /* Destroy stats, if gathered */
400 if (dscpmk_data
->summary_stats
) {
401 ipp_stat_destroy(dscpmk_data
->stats
);
404 if (dscpmk_data
->detailed_stats
) {
405 for (cnt
= 0; cnt
< DSCPMK_ARRAY_COUNT
; cnt
++) {
406 if (dscpmk_data
->dscp_stats
[cnt
].present
) {
407 ipp_stat_destroy(dscpmk_data
->dscp_stats
[cnt
].
413 /* unreference the action */
414 err
= ipp_action_unref(aid
, dscpmk_data
->next_action
, flags
);
417 kmem_free(dscpmk_data
, DSCPMK_DATA_SZ
);
422 dscpmk_invoke_action(ipp_action_id_t aid
, ipp_packet_t
*packet
)
424 dscpmk_data_t
*dscpmk_data
;
429 ASSERT(packet
!= NULL
);
431 /* get mblk from ipp_packet structure */
432 mp
= ipp_packet_get_data(packet
);
433 priv
= (ip_priv_t
*)ipp_packet_get_private(packet
);
435 dscpmk_data
= (dscpmk_data_t
*)ipp_action_get_ptr(aid
);
436 ASSERT(dscpmk_data
!= NULL
);
438 /* dscpmk packet as configured */
439 if ((err
= dscpmk_process(&mp
, dscpmk_data
, priv
->proc
)) != 0) {
442 /* return packet with next action set */
443 return (ipp_packet_next(packet
, dscpmk_data
->next_action
));
448 dscpmk_det_statinit(ipp_action_id_t aid
, dscpmk_data_t
*dscpmk_data
, int val
)
451 dscpmk_dscp_stats_t
*statp
;
452 char stats_string
[15];
454 (void) sprintf(stats_string
, "dscpmk_dscp0x%x", val
);
456 /* install stats entry */
457 if ((err
= ipp_stat_create(aid
, stats_string
, DSCPMK_DSCP_STATS_COUNT
,
458 dscpmk_update_det_stats
, dscpmk_data
,
459 &dscpmk_data
->dscp_stats
[val
].stats
)) != 0) {
460 dscpmk0dbg(("dscpmk_det_statinit: ipp_stat_create returned "\
461 "with error %d\n", err
));
465 statp
= (dscpmk_dscp_stats_t
*)
466 (dscpmk_data
->dscp_stats
[val
].stats
)->ipps_data
;
467 ASSERT(statp
!= NULL
);
469 if ((err
= ipp_stat_named_init(dscpmk_data
->dscp_stats
[val
].stats
,
470 "dscp", IPP_STAT_UINT32
, &statp
->dscp
)) != 0) {
471 dscpmk0dbg(("dscpmk_det_statinit: ipp_stat_named_init "\
472 "returned with error %d\n", err
));
476 if ((err
= ipp_stat_named_init(dscpmk_data
->dscp_stats
[val
].stats
,
477 "npackets", IPP_STAT_UINT64
, &statp
->npackets
)) != 0) {
478 dscpmk0dbg(("dscpmk_det_statinit: ipp_stat_named_init "\
479 "returned with error %d\n", err
));
483 ipp_stat_install(dscpmk_data
->dscp_stats
[val
].stats
);
489 dscpmk_summ_statinit(ipp_action_id_t aid
, dscpmk_data_t
*dscpmk_data
)
492 dscpmk_stat_t
*statp
;
494 /* install stats entry */
495 if ((err
= ipp_stat_create(aid
, DSCPMK_STATS_STRING
, DSCPMK_STATS_COUNT
,
496 dscpmk_update_stats
, dscpmk_data
, &dscpmk_data
->stats
)) != 0) {
497 dscpmk0dbg(("dscpmk_create_action: ipp_stat_create returned " \
498 "with error %d\n", err
));
502 statp
= (dscpmk_stat_t
*)(dscpmk_data
->stats
)->ipps_data
;
503 ASSERT(statp
!= NULL
);
505 if ((err
= ipp_stat_named_init(dscpmk_data
->stats
, "npackets",
506 IPP_STAT_UINT64
, &statp
->npackets
)) != 0) {
507 dscpmk0dbg(("dscpmk_summ_statinit: ipp_stat_named_init " \
508 "returned with error %d\n", err
));
512 if ((err
= ipp_stat_named_init(dscpmk_data
->stats
, "dscp_changed",
513 IPP_STAT_UINT64
, &statp
->dscp_changed
)) != 0) {
514 dscpmk0dbg(("dscpmk_summ_statinit: ipp_stat_named_init " \
515 "returned with error %d\n", err
));
519 if ((err
= ipp_stat_named_init(dscpmk_data
->stats
, "dscp_unchanged",
520 IPP_STAT_UINT64
, &statp
->dscp_unchanged
)) != 0) {
521 dscpmk0dbg(("dscpmk_summ_statinit: ipp_stat_named_init " \
522 "returned with error %d\n", err
));
526 if ((err
= ipp_stat_named_init(dscpmk_data
->stats
, "ipackets",
527 IPP_STAT_UINT64
, &statp
->ipackets
)) != 0) {
528 dscpmk0dbg(("dscpmk_summ_statinit: ipp_stat_named_init " \
529 "returned with error %d\n", err
));
533 if ((err
= ipp_stat_named_init(dscpmk_data
->stats
, "epackets",
534 IPP_STAT_UINT64
, &statp
->epackets
)) != 0) {
535 dscpmk0dbg(("dscpmk_summ_statinit: ipp_stat_named_init " \
536 "returned with error %d\n", err
));
540 ipp_stat_install(dscpmk_data
->stats
);
546 dscpmk_update_det_stats(ipp_stat_t
*sp
, void *arg
, int rw
)
548 dscpmk_data_t
*dscpmk_data
= (dscpmk_data_t
*)arg
;
549 dscpmk_dscp_stats_t
*statp
;
552 for (count
= 0; count
< DSCPMK_ARRAY_COUNT
; count
++) {
553 if (!dscpmk_data
->dscp_stats
[count
].present
)
555 statp
= (dscpmk_dscp_stats_t
*)
556 (dscpmk_data
->dscp_stats
[count
].stats
)->ipps_data
;
557 ASSERT(statp
!= NULL
);
558 (void) ipp_stat_named_op(&statp
->npackets
,
559 &dscpmk_data
->dscp_stats
[count
].npackets
, rw
);
560 (void) ipp_stat_named_op(&statp
->dscp
, &count
, rw
);
566 dscpmk_update_stats(ipp_stat_t
*sp
, void *arg
, int rw
)
568 dscpmk_data_t
*dscpmk_data
= (dscpmk_data_t
*)arg
;
569 dscpmk_stat_t
*snames
= (dscpmk_stat_t
*)sp
->ipps_data
;
570 ASSERT(dscpmk_data
!= NULL
);
571 ASSERT(snames
!= NULL
);
573 (void) ipp_stat_named_op(&snames
->npackets
, &dscpmk_data
->npackets
, rw
);
574 (void) ipp_stat_named_op(&snames
->dscp_changed
, &dscpmk_data
->changed
,
576 (void) ipp_stat_named_op(&snames
->dscp_unchanged
,
577 &dscpmk_data
->unchanged
, rw
);
578 (void) ipp_stat_named_op(&snames
->ipackets
, &dscpmk_data
->ipackets
, rw
);
579 (void) ipp_stat_named_op(&snames
->epackets
, &dscpmk_data
->epackets
, rw
);
586 dscpmk_info(ipp_action_id_t aid
, int (*fn
)(nvlist_t
*, void *), void *arg
,
590 dscpmk_data_t
*dscpmk_data
;
593 int32_t dscp_map
[DSCPMK_ARRAY_COUNT
];
597 dscpmk_data
= (dscpmk_data_t
*)ipp_action_get_ptr(aid
);
598 ASSERT(dscpmk_data
!= NULL
);
600 /* allocate nvlist to be passed back */
601 if ((err
= nvlist_alloc(&nvlp
, NV_UNIQUE_NAME
, KM_NOSLEEP
)) != 0) {
602 dscpmk0dbg(("dscpmk_info: error allocating memory\n"));
606 /* look up next action with the next action id */
607 if ((err
= ipp_action_name(dscpmk_data
->next_action
,
608 &next_action
)) != 0) {
609 dscpmk0dbg(("dscpmk_info: next action not available\n"));
614 /* add next action name */
615 if ((err
= nvlist_add_string(nvlp
, DSCPMK_NEXT_ACTION_NAME
,
616 next_action
)) != 0) {
617 dscpmk0dbg(("dscpmk_info: error adding next action\n"));
619 kmem_free(next_action
, (strlen(next_action
) + 1));
623 /* free action name */
624 kmem_free(next_action
, (strlen(next_action
) + 1));
626 /* add config type */
627 if ((err
= nvlist_add_byte(nvlp
, IPP_CONFIG_TYPE
, IPP_SET
)) != 0) {
628 dscpmk0dbg(("dscpmk_info: error adding config type\n"));
634 bcopy(dscpmk_data
->dscp_map
, dscp_map
, sizeof (dscp_map
));
635 for (cnt
= 0; cnt
< DSCPMK_ARRAY_COUNT
; cnt
++) {
636 dscp_map
[cnt
] = dscpmk_data
->dscp_map
[cnt
];
638 if ((err
= nvlist_add_int32_array(nvlp
, DSCPMK_DSCP_MAP
,
639 dscp_map
, DSCPMK_ARRAY_COUNT
)) != 0) {
640 dscpmk0dbg(("dscpmk_info: error adding dscp map\n"));
645 /* add summary stats boolean */
646 if ((err
= nvlist_add_uint32(nvlp
, IPP_ACTION_STATS_ENABLE
,
647 (dscpmk_data
->summary_stats
? 1 : 0))) != 0) {
648 dscpmk0dbg(("dscpmk_info: error adding stats status\n"));
653 /* add detailed stats boolean */
654 if ((err
= nvlist_add_uint32(nvlp
, DSCPMK_DETAILED_STATS
,
655 (dscpmk_data
->detailed_stats
? 1 : 0))) != 0) {
656 dscpmk0dbg(("dscpmk_info: error adding det stats status\n"));
661 /* call back with nvlist */