Merge commit 'ea01a15a654b9e1c7b37d958f4d1911882ed7781'
[unleashed.git] / kernel / net / sctp / sctp_snmp.c
blob37f71be0b6fa7c6e4d6948414792e42d38a6b75e
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
23 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <sys/types.h>
27 #include <sys/stream.h>
28 #include <sys/cmn_err.h>
29 #define _SUN_TPI_VERSION 2
30 #include <sys/tihdr.h>
31 #include <sys/ddi.h>
32 #include <sys/sunddi.h>
34 #include <netinet/in.h>
36 #include <inet/common.h>
37 #include <inet/ip.h>
38 #include <inet/mib2.h>
39 #include <inet/snmpcom.h>
40 #include <inet/kstatcom.h>
41 #include <inet/ipclassifier.h>
42 #include <inet/sctp/sctp_impl.h>
43 #include <inet/sctp/sctp_addr.h>
45 static void sctp_clr_kstats2(sctp_kstat_t *);
46 static void sctp_add_kstats2(sctp_kstat_counter_t *, sctp_kstat_t *);
47 static int sctp_snmp_state(sctp_t *);
48 static void sctp_sum_mib(sctp_stack_t *, mib2_sctp_t *);
49 static void sctp_add_mib(mib2_sctp_t *, mib2_sctp_t *);
51 static int
52 sctp_kstat_update(kstat_t *kp, int rw)
54 sctp_named_kstat_t *sctpkp;
55 sctp_t *sctp, *sctp_prev;
56 zoneid_t myzoneid;
57 netstackid_t stackid = (netstackid_t)(uintptr_t)kp->ks_private;
58 netstack_t *ns;
59 sctp_stack_t *sctps;
60 mib2_sctp_t sctp_mib;
62 if (kp == NULL|| kp->ks_data == NULL)
63 return (EIO);
65 if (rw == KSTAT_WRITE)
66 return (EACCES);
68 ns = netstack_find_by_stackid(stackid);
69 if (ns == NULL)
70 return (-1);
71 sctps = ns->netstack_sctp;
72 if (sctps == NULL) {
73 netstack_rele(ns);
74 return (-1);
78 * For all exclusive netstacks, the zone ID is always GLOBAL_ZONEID.
80 if (stackid != GLOBAL_NETSTACKID)
81 myzoneid = GLOBAL_ZONEID;
82 else
83 myzoneid = curproc->p_zone->zone_id;
85 bzero(&sctp_mib, sizeof (sctp_mib));
88 * Get the number of current associations and gather their
89 * individual set of statistics.
91 sctp_prev = NULL;
92 mutex_enter(&sctps->sctps_g_lock);
93 sctp = list_head(&sctps->sctps_g_list);
94 while (sctp != NULL) {
95 mutex_enter(&sctp->sctp_reflock);
96 if (sctp->sctp_condemned) {
97 mutex_exit(&sctp->sctp_reflock);
98 sctp = list_next(&sctps->sctps_g_list, sctp);
99 continue;
101 sctp->sctp_refcnt++;
102 mutex_exit(&sctp->sctp_reflock);
103 mutex_exit(&sctps->sctps_g_lock);
104 if (sctp_prev != NULL)
105 SCTP_REFRELE(sctp_prev);
106 if (sctp->sctp_connp->conn_zoneid != myzoneid)
107 goto next_sctp;
108 if (sctp->sctp_state == SCTPS_ESTABLISHED ||
109 sctp->sctp_state == SCTPS_SHUTDOWN_PENDING ||
110 sctp->sctp_state == SCTPS_SHUTDOWN_RECEIVED) {
112 * Just bump the local sctp_mib. The number of
113 * existing associations is not kept in kernel.
115 BUMP_MIB(&sctp_mib, sctpCurrEstab);
118 if (sctp->sctp_opkts) {
119 SCTPS_UPDATE_MIB(sctps, sctpOutSCTPPkts,
120 sctp->sctp_opkts);
121 sctp->sctp_opkts = 0;
124 if (sctp->sctp_obchunks) {
125 SCTPS_UPDATE_MIB(sctps, sctpOutCtrlChunks,
126 sctp->sctp_obchunks);
127 UPDATE_LOCAL(sctp->sctp_cum_obchunks,
128 sctp->sctp_obchunks);
129 sctp->sctp_obchunks = 0;
132 if (sctp->sctp_odchunks) {
133 SCTPS_UPDATE_MIB(sctps, sctpOutOrderChunks,
134 sctp->sctp_odchunks);
135 UPDATE_LOCAL(sctp->sctp_cum_odchunks,
136 sctp->sctp_odchunks);
137 sctp->sctp_odchunks = 0;
140 if (sctp->sctp_oudchunks) {
141 SCTPS_UPDATE_MIB(sctps, sctpOutUnorderChunks,
142 sctp->sctp_oudchunks);
143 UPDATE_LOCAL(sctp->sctp_cum_oudchunks,
144 sctp->sctp_oudchunks);
145 sctp->sctp_oudchunks = 0;
148 if (sctp->sctp_rxtchunks) {
149 SCTPS_UPDATE_MIB(sctps, sctpRetransChunks,
150 sctp->sctp_rxtchunks);
151 UPDATE_LOCAL(sctp->sctp_cum_rxtchunks,
152 sctp->sctp_rxtchunks);
153 sctp->sctp_rxtchunks = 0;
156 if (sctp->sctp_ipkts) {
157 SCTPS_UPDATE_MIB(sctps, sctpInSCTPPkts,
158 sctp->sctp_ipkts);
159 sctp->sctp_ipkts = 0;
162 if (sctp->sctp_ibchunks) {
163 SCTPS_UPDATE_MIB(sctps, sctpInCtrlChunks,
164 sctp->sctp_ibchunks);
165 UPDATE_LOCAL(sctp->sctp_cum_ibchunks,
166 sctp->sctp_ibchunks);
167 sctp->sctp_ibchunks = 0;
170 if (sctp->sctp_idchunks) {
171 SCTPS_UPDATE_MIB(sctps, sctpInOrderChunks,
172 sctp->sctp_idchunks);
173 UPDATE_LOCAL(sctp->sctp_cum_idchunks,
174 sctp->sctp_idchunks);
175 sctp->sctp_idchunks = 0;
178 if (sctp->sctp_iudchunks) {
179 SCTPS_UPDATE_MIB(sctps, sctpInUnorderChunks,
180 sctp->sctp_iudchunks);
181 UPDATE_LOCAL(sctp->sctp_cum_iudchunks,
182 sctp->sctp_iudchunks);
183 sctp->sctp_iudchunks = 0;
186 if (sctp->sctp_fragdmsgs) {
187 SCTPS_UPDATE_MIB(sctps, sctpFragUsrMsgs,
188 sctp->sctp_fragdmsgs);
189 sctp->sctp_fragdmsgs = 0;
192 if (sctp->sctp_reassmsgs) {
193 SCTPS_UPDATE_MIB(sctps, sctpReasmUsrMsgs,
194 sctp->sctp_reassmsgs);
195 sctp->sctp_reassmsgs = 0;
198 next_sctp:
199 sctp_prev = sctp;
200 mutex_enter(&sctps->sctps_g_lock);
201 sctp = list_next(&sctps->sctps_g_list, sctp);
203 mutex_exit(&sctps->sctps_g_lock);
204 if (sctp_prev != NULL)
205 SCTP_REFRELE(sctp_prev);
207 sctp_sum_mib(sctps, &sctp_mib);
209 /* Copy data from the SCTP MIB */
210 sctpkp = (sctp_named_kstat_t *)kp->ks_data;
212 /* These are from global ndd params. */
213 sctpkp->sctpRtoMin.value.ui32 = sctps->sctps_rto_ming;
214 sctpkp->sctpRtoMax.value.ui32 = sctps->sctps_rto_maxg;
215 sctpkp->sctpRtoInitial.value.ui32 = sctps->sctps_rto_initialg;
216 sctpkp->sctpValCookieLife.value.ui32 = sctps->sctps_cookie_life;
217 sctpkp->sctpMaxInitRetr.value.ui32 = sctps->sctps_max_init_retr;
219 /* Copy data from the local sctp_mib to the provided kstat. */
220 sctpkp->sctpCurrEstab.value.i32 = sctp_mib.sctpCurrEstab;
221 sctpkp->sctpActiveEstab.value.i32 = sctp_mib.sctpActiveEstab;
222 sctpkp->sctpPassiveEstab.value.i32 = sctp_mib.sctpPassiveEstab;
223 sctpkp->sctpAborted.value.i32 = sctp_mib.sctpAborted;
224 sctpkp->sctpShutdowns.value.i32 = sctp_mib.sctpShutdowns;
225 sctpkp->sctpOutOfBlue.value.i32 = sctp_mib.sctpOutOfBlue;
226 sctpkp->sctpChecksumError.value.i32 = sctp_mib.sctpChecksumError;
227 sctpkp->sctpOutCtrlChunks.value.i64 = sctp_mib.sctpOutCtrlChunks;
228 sctpkp->sctpOutOrderChunks.value.i64 = sctp_mib.sctpOutOrderChunks;
229 sctpkp->sctpOutUnorderChunks.value.i64 = sctp_mib.sctpOutUnorderChunks;
230 sctpkp->sctpRetransChunks.value.i64 = sctp_mib.sctpRetransChunks;
231 sctpkp->sctpOutAck.value.i32 = sctp_mib.sctpOutAck;
232 sctpkp->sctpOutAckDelayed.value.i32 = sctp_mib.sctpOutAckDelayed;
233 sctpkp->sctpOutWinUpdate.value.i32 = sctp_mib.sctpOutWinUpdate;
234 sctpkp->sctpOutFastRetrans.value.i32 = sctp_mib.sctpOutFastRetrans;
235 sctpkp->sctpOutWinProbe.value.i32 = sctp_mib.sctpOutWinProbe;
236 sctpkp->sctpInCtrlChunks.value.i64 = sctp_mib.sctpInCtrlChunks;
237 sctpkp->sctpInOrderChunks.value.i64 = sctp_mib.sctpInOrderChunks;
238 sctpkp->sctpInUnorderChunks.value.i64 = sctp_mib.sctpInUnorderChunks;
239 sctpkp->sctpInAck.value.i32 = sctp_mib.sctpInAck;
240 sctpkp->sctpInDupAck.value.i32 = sctp_mib.sctpInDupAck;
241 sctpkp->sctpInAckUnsent.value.i32 = sctp_mib.sctpInAckUnsent;
242 sctpkp->sctpFragUsrMsgs.value.i64 = sctp_mib.sctpFragUsrMsgs;
243 sctpkp->sctpReasmUsrMsgs.value.i64 = sctp_mib.sctpReasmUsrMsgs;
244 sctpkp->sctpOutSCTPPkts.value.i64 = sctp_mib.sctpOutSCTPPkts;
245 sctpkp->sctpInSCTPPkts.value.i64 = sctp_mib.sctpInSCTPPkts;
246 sctpkp->sctpInInvalidCookie.value.i32 = sctp_mib.sctpInInvalidCookie;
247 sctpkp->sctpTimRetrans.value.i32 = sctp_mib.sctpTimRetrans;
248 sctpkp->sctpTimRetransDrop.value.i32 = sctp_mib.sctpTimRetransDrop;
249 sctpkp->sctpTimHeartBeatProbe.value.i32 =
250 sctp_mib.sctpTimHeartBeatProbe;
251 sctpkp->sctpTimHeartBeatDrop.value.i32 = sctp_mib.sctpTimHeartBeatDrop;
252 sctpkp->sctpListenDrop.value.i32 = sctp_mib.sctpListenDrop;
253 sctpkp->sctpInClosed.value.i32 = sctp_mib.sctpInClosed;
255 netstack_rele(ns);
256 return (0);
259 void *
260 sctp_kstat_init(netstackid_t stackid)
262 kstat_t *ksp;
264 sctp_named_kstat_t template = {
265 { "sctpRtoAlgorithm", KSTAT_DATA_INT32, 0 },
266 { "sctpRtoMin", KSTAT_DATA_UINT32, 0 },
267 { "sctpRtoMax", KSTAT_DATA_UINT32, 0 },
268 { "sctpRtoInitial", KSTAT_DATA_UINT32, 0 },
269 { "sctpMaxAssocs", KSTAT_DATA_INT32, 0 },
270 { "sctpValCookieLife", KSTAT_DATA_UINT32, 0 },
271 { "sctpMaxInitRetr", KSTAT_DATA_UINT32, 0 },
272 { "sctpCurrEstab", KSTAT_DATA_INT32, 0 },
273 { "sctpActiveEstab", KSTAT_DATA_INT32, 0 },
274 { "sctpPassiveEstab", KSTAT_DATA_INT32, 0 },
275 { "sctpAborted", KSTAT_DATA_INT32, 0 },
276 { "sctpShutdowns", KSTAT_DATA_INT32, 0 },
277 { "sctpOutOfBlue", KSTAT_DATA_INT32, 0 },
278 { "sctpChecksumError", KSTAT_DATA_INT32, 0 },
279 { "sctpOutCtrlChunks", KSTAT_DATA_INT64, 0 },
280 { "sctpOutOrderChunks", KSTAT_DATA_INT64, 0 },
281 { "sctpOutUnorderChunks", KSTAT_DATA_INT64, 0 },
282 { "sctpRetransChunks", KSTAT_DATA_INT64, 0 },
283 { "sctpOutAck", KSTAT_DATA_INT32, 0 },
284 { "sctpOutAckDelayed", KSTAT_DATA_INT32, 0 },
285 { "sctpOutWinUpdate", KSTAT_DATA_INT32, 0 },
286 { "sctpOutFastRetrans", KSTAT_DATA_INT32, 0 },
287 { "sctpOutWinProbe", KSTAT_DATA_INT32, 0 },
288 { "sctpInCtrlChunks", KSTAT_DATA_INT64, 0 },
289 { "sctpInOrderChunks", KSTAT_DATA_INT64, 0 },
290 { "sctpInUnorderChunks", KSTAT_DATA_INT64, 0 },
291 { "sctpInAck", KSTAT_DATA_INT32, 0 },
292 { "sctpInDupAck", KSTAT_DATA_INT32, 0 },
293 { "sctpInAckUnsent", KSTAT_DATA_INT32, 0 },
294 { "sctpFragUsrMsgs", KSTAT_DATA_INT64, 0 },
295 { "sctpReasmUsrMsgs", KSTAT_DATA_INT64, 0 },
296 { "sctpOutSCTPPkts", KSTAT_DATA_INT64, 0 },
297 { "sctpInSCTPPkts", KSTAT_DATA_INT64, 0 },
298 { "sctpInInvalidCookie", KSTAT_DATA_INT32, 0 },
299 { "sctpTimRetrans", KSTAT_DATA_INT32, 0 },
300 { "sctpTimRetransDrop", KSTAT_DATA_INT32, 0 },
301 { "sctpTimHearBeatProbe", KSTAT_DATA_INT32, 0 },
302 { "sctpTimHearBeatDrop", KSTAT_DATA_INT32, 0 },
303 { "sctpListenDrop", KSTAT_DATA_INT32, 0 },
304 { "sctpInClosed", KSTAT_DATA_INT32, 0 }
307 ksp = kstat_create_netstack(SCTP_MOD_NAME, 0, "sctp", "mib2",
308 KSTAT_TYPE_NAMED, NUM_OF_FIELDS(sctp_named_kstat_t), 0, stackid);
310 if (ksp == NULL)
311 return (NULL);
313 /* These won't change. */
314 template.sctpRtoAlgorithm.value.i32 = MIB2_SCTP_RTOALGO_VANJ;
315 template.sctpMaxAssocs.value.i32 = -1;
317 bcopy(&template, ksp->ks_data, sizeof (template));
318 ksp->ks_update = sctp_kstat_update;
319 ksp->ks_private = (void *)(uintptr_t)stackid;
321 kstat_install(ksp);
322 return (ksp);
326 * To set all sctp_stat_t counters to 0.
328 static void
329 sctp_clr_kstats2(sctp_kstat_t *stats)
331 stats->sctp_add_faddr.value.ui64 = 0;
332 stats->sctp_add_timer.value.ui64 = 0;
333 stats->sctp_conn_create.value.ui64 = 0;
334 stats->sctp_find_next_tq.value.ui64 = 0;
335 stats->sctp_fr_add_hdr.value.ui64 = 0;
336 stats->sctp_fr_not_found.value.ui64 = 0;
337 stats->sctp_output_failed.value.ui64 = 0;
338 stats->sctp_rexmit_failed.value.ui64 = 0;
339 stats->sctp_send_init_failed.value.ui64 = 0;
340 stats->sctp_send_cookie_failed.value.ui64 = 0;
341 stats->sctp_send_cookie_ack_failed.value.ui64 = 0;
342 stats->sctp_send_err_failed.value.ui64 = 0;
343 stats->sctp_send_sack_failed.value.ui64 = 0;
344 stats->sctp_send_shutdown_failed.value.ui64 = 0;
345 stats->sctp_send_shutdown_ack_failed.value.ui64 = 0;
346 stats->sctp_send_shutdown_comp_failed.value.ui64 = 0;
347 stats->sctp_send_user_abort_failed.value.ui64 = 0;
348 stats->sctp_send_asconf_failed.value.ui64 = 0;
349 stats->sctp_send_asconf_ack_failed.value.ui64 = 0;
350 stats->sctp_send_ftsn_failed.value.ui64 = 0;
351 stats->sctp_send_hb_failed.value.ui64 = 0;
352 stats->sctp_return_hb_failed.value.ui64 = 0;
353 stats->sctp_ss_rexmit_failed.value.ui64 = 0;
354 stats->sctp_reclaim_cnt.value.ui64 = 0;
355 stats->sctp_listen_cnt_drop.value.ui64 = 0;
359 * To add counters from the per CPU sctp_kstat_counter_t to the stack
360 * sctp_kstat_t.
362 static void
363 sctp_add_kstats2(sctp_kstat_counter_t *from, sctp_kstat_t *to)
365 to->sctp_add_faddr.value.ui64 += from->sctp_add_faddr;
366 to->sctp_add_timer.value.ui64 += from->sctp_add_timer;
367 to->sctp_conn_create.value.ui64 += from->sctp_conn_create;
368 to->sctp_find_next_tq.value.ui64 += from->sctp_find_next_tq;
369 to->sctp_fr_add_hdr.value.ui64 += from->sctp_fr_add_hdr;
370 to->sctp_fr_not_found.value.ui64 += from->sctp_fr_not_found;
371 to->sctp_output_failed.value.ui64 += from->sctp_output_failed;
372 to->sctp_rexmit_failed.value.ui64 += from->sctp_rexmit_failed;
373 to->sctp_send_init_failed.value.ui64 += from->sctp_send_init_failed;
374 to->sctp_send_cookie_failed.value.ui64 += from->sctp_send_cookie_failed;
375 to->sctp_send_cookie_ack_failed.value.ui64 +=
376 from->sctp_send_cookie_ack_failed;
377 to->sctp_send_err_failed.value.ui64 += from->sctp_send_err_failed;
378 to->sctp_send_sack_failed.value.ui64 += from->sctp_send_sack_failed;
379 to->sctp_send_shutdown_failed.value.ui64 +=
380 from->sctp_send_shutdown_failed;
381 to->sctp_send_shutdown_ack_failed.value.ui64 +=
382 from->sctp_send_shutdown_ack_failed;
383 to->sctp_send_shutdown_comp_failed.value.ui64 +=
384 from->sctp_send_shutdown_comp_failed;
385 to->sctp_send_user_abort_failed.value.ui64 +=
386 from->sctp_send_user_abort_failed;
387 to->sctp_send_asconf_failed.value.ui64 += from->sctp_send_asconf_failed;
388 to->sctp_send_asconf_ack_failed.value.ui64 +=
389 from->sctp_send_asconf_ack_failed;
390 to->sctp_send_ftsn_failed.value.ui64 += from->sctp_send_ftsn_failed;
391 to->sctp_send_hb_failed.value.ui64 += from->sctp_send_hb_failed;
392 to->sctp_return_hb_failed.value.ui64 += from->sctp_return_hb_failed;
393 to->sctp_ss_rexmit_failed.value.ui64 += from->sctp_ss_rexmit_failed;
397 * Sum up all per CPU tcp_stat_t kstat counters.
399 static int
400 sctp_kstat2_update(kstat_t *kp, int rw)
402 netstackid_t stackid = (netstackid_t)(uintptr_t)kp->ks_private;
403 netstack_t *ns;
404 sctp_stack_t *sctps;
405 sctp_kstat_t *stats;
406 int i;
407 int cnt;
409 if (rw == KSTAT_WRITE)
410 return (EACCES);
412 ns = netstack_find_by_stackid(stackid);
413 if (ns == NULL)
414 return (-1);
415 sctps = ns->netstack_sctp;
416 if (sctps == NULL) {
417 netstack_rele(ns);
418 return (-1);
421 stats = (sctp_kstat_t *)kp->ks_data;
422 sctp_clr_kstats2(stats);
425 * sctps_sc_cnt may change in the middle of the loop. It is better
426 * to get its value first.
428 cnt = sctps->sctps_sc_cnt;
429 for (i = 0; i < cnt; i++)
430 sctp_add_kstats2(&sctps->sctps_sc[i]->sctp_sc_stats, stats);
432 netstack_rele(ns);
433 return (0);
437 * The following kstats are for debugging purposes. They keep
438 * track of problems which should not happen normally. But in
439 * those cases which they do happen, these kstats would be handy
440 * for engineers to diagnose the problems. They are not intended
441 * to be consumed by customers.
443 void *
444 sctp_kstat2_init(netstackid_t stackid)
446 kstat_t *ksp;
448 sctp_kstat_t template = {
449 { "sctp_add_faddr", KSTAT_DATA_UINT64 },
450 { "sctp_add_timer", KSTAT_DATA_UINT64 },
451 { "sctp_conn_create", KSTAT_DATA_UINT64 },
452 { "sctp_find_next_tq", KSTAT_DATA_UINT64 },
453 { "sctp_fr_add_hdr", KSTAT_DATA_UINT64 },
454 { "sctp_fr_not_found", KSTAT_DATA_UINT64 },
455 { "sctp_output_failed", KSTAT_DATA_UINT64 },
456 { "sctp_rexmit_failed", KSTAT_DATA_UINT64 },
457 { "sctp_send_init_failed", KSTAT_DATA_UINT64 },
458 { "sctp_send_cookie_failed", KSTAT_DATA_UINT64 },
459 { "sctp_send_cookie_ack_failed", KSTAT_DATA_UINT64 },
460 { "sctp_send_err_failed", KSTAT_DATA_UINT64 },
461 { "sctp_send_sack_failed", KSTAT_DATA_UINT64 },
462 { "sctp_send_shutdown_failed", KSTAT_DATA_UINT64 },
463 { "sctp_send_shutdown_ack_failed", KSTAT_DATA_UINT64 },
464 { "sctp_send_shutdown_comp_failed", KSTAT_DATA_UINT64 },
465 { "sctp_send_user_abort_failed", KSTAT_DATA_UINT64 },
466 { "sctp_send_asconf_failed", KSTAT_DATA_UINT64 },
467 { "sctp_send_asconf_ack_failed", KSTAT_DATA_UINT64 },
468 { "sctp_send_ftsn_failed", KSTAT_DATA_UINT64 },
469 { "sctp_send_hb_failed", KSTAT_DATA_UINT64 },
470 { "sctp_return_hb_failed", KSTAT_DATA_UINT64 },
471 { "sctp_ss_rexmit_failed", KSTAT_DATA_UINT64 },
472 { "sctp_reclaim_drop", KSTAT_DATA_UINT64 },
473 { "sctp_listen_cnt_drop", KSTAT_DATA_UINT64 },
476 ksp = kstat_create_netstack(SCTP_MOD_NAME, 0, "sctpstat", "net",
477 KSTAT_TYPE_NAMED, NUM_OF_FIELDS(template), 0, stackid);
479 if (ksp == NULL)
480 return (NULL);
482 bcopy(&template, ksp->ks_data, sizeof (template));
483 ksp->ks_private = (void *)(uintptr_t)stackid;
484 ksp->ks_update = sctp_kstat2_update;
486 kstat_install(ksp);
487 return (ksp);
490 void
491 sctp_kstat_fini(netstackid_t stackid, kstat_t *ksp)
493 if (ksp != NULL) {
494 ASSERT(stackid == (netstackid_t)(uintptr_t)ksp->ks_private);
495 kstat_delete_netstack(ksp, stackid);
499 void
500 sctp_kstat2_fini(netstackid_t stackid, kstat_t *ksp)
502 if (ksp != NULL) {
503 ASSERT(stackid == (netstackid_t)(uintptr_t)ksp->ks_private);
504 kstat_delete_netstack(ksp, stackid);
509 * Return SNMP global stats in buffer in mpdata.
510 * Return associatiation table in mp_conn_data,
511 * local address table in mp_local_data, and
512 * remote address table in mp_rem_data.
514 mblk_t *
515 sctp_snmp_get_mib2(queue_t *q, mblk_t *mpctl, sctp_stack_t *sctps)
517 mblk_t *mpdata, *mp_ret;
518 mblk_t *mp_conn_ctl = NULL;
519 mblk_t *mp_conn_data;
520 mblk_t *mp_conn_tail = NULL;
521 mblk_t *mp_local_ctl = NULL;
522 mblk_t *mp_local_data;
523 mblk_t *mp_local_tail = NULL;
524 mblk_t *mp_rem_ctl = NULL;
525 mblk_t *mp_rem_data;
526 mblk_t *mp_rem_tail = NULL;
527 struct opthdr *optp;
528 sctp_t *sctp, *sctp_prev = NULL;
529 sctp_faddr_t *fp;
530 mib2_sctpConnEntry_t sce;
531 mib2_sctpConnLocalEntry_t scle;
532 mib2_sctpConnRemoteEntry_t scre;
533 int i;
534 int l;
535 int scanned = 0;
536 zoneid_t zoneid = Q_TO_CONN(q)->conn_zoneid;
537 conn_t *connp;
538 int idx;
539 mib2_sctp_t sctp_mib;
542 * Make copies of the original message.
543 * mpctl will hold SCTP counters,
544 * mp_conn_ctl will hold list of connections.
546 mp_ret = copymsg(mpctl);
547 mp_conn_ctl = copymsg(mpctl);
548 mp_local_ctl = copymsg(mpctl);
549 mp_rem_ctl = copymsg(mpctl);
551 mpdata = mpctl->b_cont;
553 if (mp_conn_ctl == NULL || mp_local_ctl == NULL ||
554 mp_rem_ctl == NULL || mpdata == NULL) {
555 freemsg(mp_rem_ctl);
556 freemsg(mp_local_ctl);
557 freemsg(mp_conn_ctl);
558 freemsg(mp_ret);
559 freemsg(mpctl);
560 return (NULL);
562 mp_conn_data = mp_conn_ctl->b_cont;
563 mp_local_data = mp_local_ctl->b_cont;
564 mp_rem_data = mp_rem_ctl->b_cont;
566 bzero(&sctp_mib, sizeof (sctp_mib));
568 /* hostname address parameters are not supported in Solaris */
569 sce.sctpAssocRemHostName.o_length = 0;
570 sce.sctpAssocRemHostName.o_bytes[0] = 0;
572 /* build table of connections -- need count in fixed part */
574 idx = 0;
575 mutex_enter(&sctps->sctps_g_lock);
576 sctp = list_head(&sctps->sctps_g_list);
577 while (sctp != NULL) {
578 mutex_enter(&sctp->sctp_reflock);
579 if (sctp->sctp_condemned) {
580 mutex_exit(&sctp->sctp_reflock);
581 sctp = list_next(&sctps->sctps_g_list, sctp);
582 continue;
584 sctp->sctp_refcnt++;
585 mutex_exit(&sctp->sctp_reflock);
586 mutex_exit(&sctps->sctps_g_lock);
587 if (sctp_prev != NULL)
588 SCTP_REFRELE(sctp_prev);
589 if (sctp->sctp_connp->conn_zoneid != zoneid)
590 goto next_sctp;
591 if (sctp->sctp_state == SCTPS_ESTABLISHED ||
592 sctp->sctp_state == SCTPS_SHUTDOWN_PENDING ||
593 sctp->sctp_state == SCTPS_SHUTDOWN_RECEIVED) {
595 * Just bump the local sctp_mib. The number of
596 * existing associations is not kept in kernel.
598 BUMP_MIB(&sctp_mib, sctpCurrEstab);
600 SCTPS_UPDATE_MIB(sctps, sctpOutSCTPPkts, sctp->sctp_opkts);
601 sctp->sctp_opkts = 0;
602 SCTPS_UPDATE_MIB(sctps, sctpOutCtrlChunks, sctp->sctp_obchunks);
603 UPDATE_LOCAL(sctp->sctp_cum_obchunks,
604 sctp->sctp_obchunks);
605 sctp->sctp_obchunks = 0;
606 SCTPS_UPDATE_MIB(sctps, sctpOutOrderChunks,
607 sctp->sctp_odchunks);
608 UPDATE_LOCAL(sctp->sctp_cum_odchunks,
609 sctp->sctp_odchunks);
610 sctp->sctp_odchunks = 0;
611 SCTPS_UPDATE_MIB(sctps, sctpOutUnorderChunks,
612 sctp->sctp_oudchunks);
613 UPDATE_LOCAL(sctp->sctp_cum_oudchunks,
614 sctp->sctp_oudchunks);
615 sctp->sctp_oudchunks = 0;
616 SCTPS_UPDATE_MIB(sctps, sctpRetransChunks,
617 sctp->sctp_rxtchunks);
618 UPDATE_LOCAL(sctp->sctp_cum_rxtchunks,
619 sctp->sctp_rxtchunks);
620 sctp->sctp_rxtchunks = 0;
621 SCTPS_UPDATE_MIB(sctps, sctpInSCTPPkts, sctp->sctp_ipkts);
622 sctp->sctp_ipkts = 0;
623 SCTPS_UPDATE_MIB(sctps, sctpInCtrlChunks, sctp->sctp_ibchunks);
624 UPDATE_LOCAL(sctp->sctp_cum_ibchunks,
625 sctp->sctp_ibchunks);
626 sctp->sctp_ibchunks = 0;
627 SCTPS_UPDATE_MIB(sctps, sctpInOrderChunks, sctp->sctp_idchunks);
628 UPDATE_LOCAL(sctp->sctp_cum_idchunks,
629 sctp->sctp_idchunks);
630 sctp->sctp_idchunks = 0;
631 SCTPS_UPDATE_MIB(sctps, sctpInUnorderChunks,
632 sctp->sctp_iudchunks);
633 UPDATE_LOCAL(sctp->sctp_cum_iudchunks,
634 sctp->sctp_iudchunks);
635 sctp->sctp_iudchunks = 0;
636 SCTPS_UPDATE_MIB(sctps, sctpFragUsrMsgs, sctp->sctp_fragdmsgs);
637 sctp->sctp_fragdmsgs = 0;
638 SCTPS_UPDATE_MIB(sctps, sctpReasmUsrMsgs, sctp->sctp_reassmsgs);
639 sctp->sctp_reassmsgs = 0;
641 sce.sctpAssocId = ntohl(sctp->sctp_lvtag);
642 sce.sctpAssocLocalPort = ntohs(sctp->sctp_connp->conn_lport);
643 sce.sctpAssocRemPort = ntohs(sctp->sctp_connp->conn_fport);
645 RUN_SCTP(sctp);
646 if (sctp->sctp_primary != NULL) {
647 fp = sctp->sctp_primary;
649 if (IN6_IS_ADDR_V4MAPPED(&fp->sf_faddr)) {
650 sce.sctpAssocRemPrimAddrType =
651 MIB2_SCTP_ADDR_V4;
652 } else {
653 sce.sctpAssocRemPrimAddrType =
654 MIB2_SCTP_ADDR_V6;
656 sce.sctpAssocRemPrimAddr = fp->sf_faddr;
657 sce.sctpAssocLocPrimAddr = fp->sf_saddr;
658 sce.sctpAssocHeartBeatInterval = TICK_TO_MSEC(
659 fp->sf_hb_interval);
660 } else {
661 sce.sctpAssocRemPrimAddrType = MIB2_SCTP_ADDR_V4;
662 bzero(&sce.sctpAssocRemPrimAddr,
663 sizeof (sce.sctpAssocRemPrimAddr));
664 bzero(&sce.sctpAssocLocPrimAddr,
665 sizeof (sce.sctpAssocLocPrimAddr));
666 sce.sctpAssocHeartBeatInterval =
667 sctps->sctps_heartbeat_interval;
671 * Table for local addresses
673 scanned = 0;
674 for (i = 0; i < SCTP_IPIF_HASH; i++) {
675 sctp_saddr_ipif_t *obj;
677 if (sctp->sctp_saddrs[i].ipif_count == 0)
678 continue;
679 obj = list_head(&sctp->sctp_saddrs[i].sctp_ipif_list);
680 for (l = 0; l < sctp->sctp_saddrs[i].ipif_count; l++) {
681 sctp_ipif_t *sctp_ipif;
682 in6_addr_t addr;
684 sctp_ipif = obj->saddr_ipifp;
685 addr = sctp_ipif->sctp_ipif_saddr;
686 scanned++;
687 scle.sctpAssocId = ntohl(sctp->sctp_lvtag);
688 if (IN6_IS_ADDR_V4MAPPED(&addr)) {
689 scle.sctpAssocLocalAddrType =
690 MIB2_SCTP_ADDR_V4;
691 } else {
692 scle.sctpAssocLocalAddrType =
693 MIB2_SCTP_ADDR_V6;
695 scle.sctpAssocLocalAddr = addr;
696 (void) snmp_append_data2(mp_local_data,
697 &mp_local_tail, (char *)&scle,
698 sizeof (scle));
699 if (scanned >= sctp->sctp_nsaddrs)
700 goto done;
701 obj = list_next(&sctp->
702 sctp_saddrs[i].sctp_ipif_list, obj);
705 done:
707 * Table for remote addresses
709 for (fp = sctp->sctp_faddrs; fp; fp = fp->sf_next) {
710 scre.sctpAssocId = ntohl(sctp->sctp_lvtag);
711 if (IN6_IS_ADDR_V4MAPPED(&fp->sf_faddr)) {
712 scre.sctpAssocRemAddrType = MIB2_SCTP_ADDR_V4;
713 } else {
714 scre.sctpAssocRemAddrType = MIB2_SCTP_ADDR_V6;
716 scre.sctpAssocRemAddr = fp->sf_faddr;
717 if (fp->sf_state == SCTP_FADDRS_ALIVE) {
718 scre.sctpAssocRemAddrActive =
719 scre.sctpAssocRemAddrHBActive =
720 MIB2_SCTP_ACTIVE;
721 } else {
722 scre.sctpAssocRemAddrActive =
723 scre.sctpAssocRemAddrHBActive =
724 MIB2_SCTP_INACTIVE;
726 scre.sctpAssocRemAddrRTO = TICK_TO_MSEC(fp->sf_rto);
727 scre.sctpAssocRemAddrMaxPathRtx = fp->sf_max_retr;
728 scre.sctpAssocRemAddrRtx = fp->sf_T3expire;
729 (void) snmp_append_data2(mp_rem_data, &mp_rem_tail,
730 (char *)&scre, sizeof (scre));
732 connp = sctp->sctp_connp;
733 WAKE_SCTP(sctp);
734 sce.sctpAssocState = sctp_snmp_state(sctp);
735 sce.sctpAssocInStreams = sctp->sctp_num_istr;
736 sce.sctpAssocOutStreams = sctp->sctp_num_ostr;
737 sce.sctpAssocMaxRetr = sctp->sctp_pa_max_rxt;
738 /* A 0 here indicates that no primary process is known */
739 sce.sctpAssocPrimProcess = 0;
740 sce.sctpAssocT1expired = sctp->sctp_T1expire;
741 sce.sctpAssocT2expired = sctp->sctp_T2expire;
742 sce.sctpAssocRtxChunks = sctp->sctp_T3expire;
743 sce.sctpAssocStartTime = sctp->sctp_assoc_start_time;
744 sce.sctpConnEntryInfo.ce_sendq = sctp->sctp_unacked +
745 sctp->sctp_unsent;
746 sce.sctpConnEntryInfo.ce_recvq = sctp->sctp_rxqueued;
747 sce.sctpConnEntryInfo.ce_swnd = sctp->sctp_frwnd;
748 sce.sctpConnEntryInfo.ce_rwnd = sctp->sctp_rwnd;
749 sce.sctpConnEntryInfo.ce_mss = sctp->sctp_mss;
750 (void) snmp_append_data2(mp_conn_data, &mp_conn_tail,
751 (char *)&sce, sizeof (sce));
752 next_sctp:
753 sctp_prev = sctp;
754 mutex_enter(&sctps->sctps_g_lock);
755 sctp = list_next(&sctps->sctps_g_list, sctp);
757 mutex_exit(&sctps->sctps_g_lock);
758 if (sctp_prev != NULL)
759 SCTP_REFRELE(sctp_prev);
761 sctp_sum_mib(sctps, &sctp_mib);
763 optp = (struct opthdr *)&mpctl->b_rptr[sizeof (struct T_optmgmt_ack)];
764 optp->level = MIB2_SCTP;
765 optp->name = 0;
766 (void) snmp_append_data(mpdata, (char *)&sctp_mib, sizeof (sctp_mib));
767 optp->len = msgdsize(mpdata);
768 qreply(q, mpctl);
770 /* table of connections... */
771 optp = (struct opthdr *)&mp_conn_ctl->b_rptr[
772 sizeof (struct T_optmgmt_ack)];
773 optp->level = MIB2_SCTP;
774 optp->name = MIB2_SCTP_CONN;
775 optp->len = msgdsize(mp_conn_data);
776 qreply(q, mp_conn_ctl);
778 /* assoc local address table */
779 optp = (struct opthdr *)&mp_local_ctl->b_rptr[
780 sizeof (struct T_optmgmt_ack)];
781 optp->level = MIB2_SCTP;
782 optp->name = MIB2_SCTP_CONN_LOCAL;
783 optp->len = msgdsize(mp_local_data);
784 qreply(q, mp_local_ctl);
786 /* assoc remote address table */
787 optp = (struct opthdr *)&mp_rem_ctl->b_rptr[
788 sizeof (struct T_optmgmt_ack)];
789 optp->level = MIB2_SCTP;
790 optp->name = MIB2_SCTP_CONN_REMOTE;
791 optp->len = msgdsize(mp_rem_data);
792 qreply(q, mp_rem_ctl);
794 return (mp_ret);
797 /* Translate SCTP state to MIB2 SCTP state. */
798 static int
799 sctp_snmp_state(sctp_t *sctp)
801 if (sctp == NULL)
802 return (0);
804 switch (sctp->sctp_state) {
805 case SCTPS_IDLE:
806 case SCTPS_BOUND:
807 return (MIB2_SCTP_closed);
808 case SCTPS_LISTEN:
809 return (MIB2_SCTP_listen);
810 case SCTPS_COOKIE_WAIT:
811 return (MIB2_SCTP_cookieWait);
812 case SCTPS_COOKIE_ECHOED:
813 return (MIB2_SCTP_cookieEchoed);
814 case SCTPS_ESTABLISHED:
815 return (MIB2_SCTP_established);
816 case SCTPS_SHUTDOWN_PENDING:
817 return (MIB2_SCTP_shutdownPending);
818 case SCTPS_SHUTDOWN_SENT:
819 return (MIB2_SCTP_shutdownSent);
820 case SCTPS_SHUTDOWN_RECEIVED:
821 return (MIB2_SCTP_shutdownReceived);
822 case SCTPS_SHUTDOWN_ACK_SENT:
823 return (MIB2_SCTP_shutdownAckSent);
824 default:
825 return (0);
830 * To sum up all MIB2 stats for a sctp_stack_t from all per CPU stats. The
831 * caller should initialize the target mib2_sctp_t properly as this function
832 * just adds up all the per CPU stats.
834 static void
835 sctp_sum_mib(sctp_stack_t *sctps, mib2_sctp_t *sctp_mib)
837 int i;
838 int cnt;
840 /* Static componets of mib2_sctp_t. */
841 SET_MIB(sctp_mib->sctpRtoAlgorithm, MIB2_SCTP_RTOALGO_VANJ);
842 SET_MIB(sctp_mib->sctpRtoMin, sctps->sctps_rto_ming);
843 SET_MIB(sctp_mib->sctpRtoMax, sctps->sctps_rto_maxg);
844 SET_MIB(sctp_mib->sctpRtoInitial, sctps->sctps_rto_initialg);
845 SET_MIB(sctp_mib->sctpMaxAssocs, -1);
846 SET_MIB(sctp_mib->sctpValCookieLife, sctps->sctps_cookie_life);
847 SET_MIB(sctp_mib->sctpMaxInitRetr, sctps->sctps_max_init_retr);
849 /* fixed length structure for IPv4 and IPv6 counters */
850 SET_MIB(sctp_mib->sctpEntrySize, sizeof (mib2_sctpConnEntry_t));
851 SET_MIB(sctp_mib->sctpLocalEntrySize,
852 sizeof (mib2_sctpConnLocalEntry_t));
853 SET_MIB(sctp_mib->sctpRemoteEntrySize,
854 sizeof (mib2_sctpConnRemoteEntry_t));
857 * sctps_sc_cnt may change in the middle of the loop. It is better
858 * to get its value first.
860 cnt = sctps->sctps_sc_cnt;
861 for (i = 0; i < cnt; i++)
862 sctp_add_mib(&sctps->sctps_sc[i]->sctp_sc_mib, sctp_mib);
865 static void
866 sctp_add_mib(mib2_sctp_t *from, mib2_sctp_t *to)
868 to->sctpActiveEstab += from->sctpActiveEstab;
869 to->sctpPassiveEstab += from->sctpPassiveEstab;
870 to->sctpAborted += from->sctpAborted;
871 to->sctpShutdowns += from->sctpShutdowns;
872 to->sctpOutOfBlue += from->sctpOutOfBlue;
873 to->sctpChecksumError += from->sctpChecksumError;
874 to->sctpOutCtrlChunks += from->sctpOutCtrlChunks;
875 to->sctpOutOrderChunks += from->sctpOutOrderChunks;
876 to->sctpOutUnorderChunks += from->sctpOutUnorderChunks;
877 to->sctpRetransChunks += from->sctpRetransChunks;
878 to->sctpOutAck += from->sctpOutAck;
879 to->sctpOutAckDelayed += from->sctpOutAckDelayed;
880 to->sctpOutWinUpdate += from->sctpOutWinUpdate;
881 to->sctpOutFastRetrans += from->sctpOutFastRetrans;
882 to->sctpOutWinProbe += from->sctpOutWinProbe;
883 to->sctpInCtrlChunks += from->sctpInCtrlChunks;
884 to->sctpInOrderChunks += from->sctpInOrderChunks;
885 to->sctpInUnorderChunks += from->sctpInUnorderChunks;
886 to->sctpInAck += from->sctpInAck;
887 to->sctpInDupAck += from->sctpInDupAck;
888 to->sctpInAckUnsent += from->sctpInAckUnsent;
889 to->sctpFragUsrMsgs += from->sctpFragUsrMsgs;
890 to->sctpReasmUsrMsgs += from->sctpReasmUsrMsgs;
891 to->sctpOutSCTPPkts += from->sctpOutSCTPPkts;
892 to->sctpInSCTPPkts += from->sctpInSCTPPkts;
893 to->sctpInInvalidCookie += from->sctpInInvalidCookie;
894 to->sctpTimRetrans += from->sctpTimRetrans;
895 to->sctpTimRetransDrop += from->sctpTimRetransDrop;
896 to->sctpTimHeartBeatProbe += from->sctpTimHeartBeatProbe;
897 to->sctpTimHeartBeatDrop += from->sctpTimHeartBeatDrop;
898 to->sctpListenDrop += from->sctpListenDrop;
899 to->sctpInClosed += from->sctpInClosed;