/* * Return SNMP stuff in buffer in mpdata. */ mblk_t * tcp_snmp_get(queue_t *q, mblk_t *mpctl, boolean_t legacy_req) { mblk_t *mpdata; mblk_t *mp_conn_ctl = NULL; mblk_t *mp_conn_tail; mblk_t *mp_attr_ctl = NULL; mblk_t *mp_attr_tail; mblk_t *mp6_conn_ctl = NULL; mblk_t *mp6_conn_tail; mblk_t *mp6_attr_ctl = NULL; mblk_t *mp6_attr_tail; struct opthdr *optp; mib2_tcpConnEntry_t tce; mib2_tcp6ConnEntry_t tce6; mib2_transportMLPEntry_t mlp; connf_t *connfp; int i; boolean_t ispriv; zoneid_t zoneid; int v4_conn_idx; int v6_conn_idx; conn_t *connp = Q_TO_CONN(q); tcp_stack_t *tcps; ip_stack_t *ipst; mblk_t *mp2ctl; mib2_tcp_t tcp_mib; size_t tcp_mib_size, tce_size, tce6_size; /* * make a copy of the original message */ mp2ctl = copymsg(mpctl); if (mpctl == NULL || (mpdata = mpctl->b_cont) == NULL || (mp_conn_ctl = copymsg(mpctl)) == NULL || (mp_attr_ctl = copymsg(mpctl)) == NULL || (mp6_conn_ctl = copymsg(mpctl)) == NULL || (mp6_attr_ctl = copymsg(mpctl)) == NULL) { freemsg(mp_conn_ctl); freemsg(mp_attr_ctl); freemsg(mp6_conn_ctl); freemsg(mp6_attr_ctl); freemsg(mpctl); freemsg(mp2ctl); return (NULL); } ipst = connp->conn_netstack->netstack_ip; tcps = connp->conn_netstack->netstack_tcp; if (legacy_req) { tcp_mib_size = LEGACY_MIB_SIZE(&tcp_mib, mib2_tcp_t); tce_size = LEGACY_MIB_SIZE(&tce, mib2_tcpConnEntry_t); tce6_size = LEGACY_MIB_SIZE(&tce6, mib2_tcp6ConnEntry_t); } else { tcp_mib_size = sizeof (mib2_tcp_t); tce_size = sizeof (mib2_tcpConnEntry_t); tce6_size = sizeof (mib2_tcp6ConnEntry_t); } bzero(&tcp_mib, sizeof (tcp_mib)); /* build table of connections -- need count in fixed part */ SET_MIB(tcp_mib.tcpRtoAlgorithm, 4); /* vanj */ SET_MIB(tcp_mib.tcpRtoMin, tcps->tcps_rexmit_interval_min); SET_MIB(tcp_mib.tcpRtoMax, tcps->tcps_rexmit_interval_max); SET_MIB(tcp_mib.tcpMaxConn, -1); SET_MIB(tcp_mib.tcpCurrEstab, 0); ispriv = secpolicy_ip_config((Q_TO_CONN(q))->conn_cred, B_TRUE) == 0; zoneid = Q_TO_CONN(q)->conn_zoneid; v4_conn_idx = v6_conn_idx = 0; mp_conn_tail = mp_attr_tail = mp6_conn_tail = mp6_attr_tail = NULL; for (i = 0; i < CONN_G_HASH_SIZE; i++) { ipst = tcps->tcps_netstack->netstack_ip; connfp = &ipst->ips_ipcl_globalhash_fanout[i]; connp = NULL; while ((connp = ipcl_get_next_conn(connfp, connp, IPCL_TCPCONN)) != NULL) { tcp_t *tcp; boolean_t needattr; if (connp->conn_zoneid != zoneid) continue; /* not in this zone */ tcp = connp->conn_tcp; TCPS_UPDATE_MIB(tcps, tcpHCInSegs, tcp->tcp_ibsegs); tcp->tcp_ibsegs = 0; TCPS_UPDATE_MIB(tcps, tcpHCOutSegs, tcp->tcp_obsegs); tcp->tcp_obsegs = 0; tce6.tcp6ConnState = tce.tcpConnState = tcp_snmp_state(tcp); if (tce.tcpConnState == MIB2_TCP_established || tce.tcpConnState == MIB2_TCP_closeWait) BUMP_MIB(&tcp_mib, tcpCurrEstab); needattr = B_FALSE; bzero(&mlp, sizeof (mlp)); if (connp->conn_mlp_type != mlptSingle) { if (connp->conn_mlp_type == mlptShared || connp->conn_mlp_type == mlptBoth) mlp.tme_flags |= MIB2_TMEF_SHARED; if (connp->conn_mlp_type == mlptPrivate || connp->conn_mlp_type == mlptBoth) mlp.tme_flags |= MIB2_TMEF_PRIVATE; needattr = B_TRUE; } if (connp->conn_anon_mlp) { mlp.tme_flags |= MIB2_TMEF_ANONMLP; needattr = B_TRUE; } switch (connp->conn_mac_mode) { case CONN_MAC_DEFAULT: break; case CONN_MAC_AWARE: mlp.tme_flags |= MIB2_TMEF_MACEXEMPT; needattr = B_TRUE; break; case CONN_MAC_IMPLICIT: mlp.tme_flags |= MIB2_TMEF_MACIMPLICIT; needattr = B_TRUE; break; } if (connp->conn_ixa->ixa_tsl != NULL) { ts_label_t *tsl; tsl = connp->conn_ixa->ixa_tsl; mlp.tme_flags |= MIB2_TMEF_IS_LABELED; mlp.tme_doi = label2doi(tsl); mlp.tme_label = *label2bslabel(tsl); needattr = B_TRUE; } /* Create a message to report on IPv6 entries */ if (connp->conn_ipversion == IPV6_VERSION) { tce6.tcp6ConnLocalAddress = connp->conn_laddr_v6; tce6.tcp6ConnRemAddress = connp->conn_faddr_v6; tce6.tcp6ConnLocalPort = ntohs(connp->conn_lport); tce6.tcp6ConnRemPort = ntohs(connp->conn_fport); if (connp->conn_ixa->ixa_flags & IXAF_SCOPEID_SET) { tce6.tcp6ConnIfIndex = connp->conn_ixa->ixa_scopeid; } else { tce6.tcp6ConnIfIndex = connp->conn_bound_if; } /* Don't want just anybody seeing these... */ if (ispriv) { tce6.tcp6ConnEntryInfo.ce_snxt = tcp->tcp_snxt; tce6.tcp6ConnEntryInfo.ce_suna = tcp->tcp_suna; tce6.tcp6ConnEntryInfo.ce_rnxt = tcp->tcp_rnxt; tce6.tcp6ConnEntryInfo.ce_rack = tcp->tcp_rack; } else { /* * Netstat, unfortunately, uses this to * get send/receive queue sizes. How to fix? * Why not compute the difference only? */ tce6.tcp6ConnEntryInfo.ce_snxt = tcp->tcp_snxt - tcp->tcp_suna; tce6.tcp6ConnEntryInfo.ce_suna = 0; tce6.tcp6ConnEntryInfo.ce_rnxt = tcp->tcp_rnxt - tcp->tcp_rack; tce6.tcp6ConnEntryInfo.ce_rack = 0; } tce6.tcp6ConnEntryInfo.ce_swnd = tcp->tcp_swnd; tce6.tcp6ConnEntryInfo.ce_rwnd = tcp->tcp_rwnd; tce6.tcp6ConnEntryInfo.ce_rto = tcp->tcp_rto; tce6.tcp6ConnEntryInfo.ce_mss = tcp->tcp_mss; tce6.tcp6ConnEntryInfo.ce_state = tcp->tcp_state; tce6.tcp6ConnCreationProcess = (connp->conn_cpid < 0) ? MIB2_UNKNOWN_PROCESS : connp->conn_cpid; tce6.tcp6ConnCreationTime = connp->conn_open_time; (void) snmp_append_data2(mp6_conn_ctl->b_cont, &mp6_conn_tail, (char *)&tce6, tce6_size); mlp.tme_connidx = v6_conn_idx++; if (needattr) (void) snmp_append_data2(mp6_attr_ctl->b_cont, &mp6_attr_tail, (char *)&mlp, sizeof (mlp)); } /* * Create an IPv4 table entry for IPv4 entries and also * for IPv6 entries which are bound to in6addr_any * but don't have IPV6_V6ONLY set. * (i.e. anything an IPv4 peer could connect to) */ if (connp->conn_ipversion == IPV4_VERSION || (tcp->tcp_state <= TCPS_LISTEN && !connp->conn_ipv6_v6only && IN6_IS_ADDR_UNSPECIFIED(&connp->conn_laddr_v6))) { if (connp->conn_ipversion == IPV6_VERSION) { tce.tcpConnRemAddress = INADDR_ANY; tce.tcpConnLocalAddress = INADDR_ANY; } else { tce.tcpConnRemAddress = connp->conn_faddr_v4; tce.tcpConnLocalAddress = connp->conn_laddr_v4; } tce.tcpConnLocalPort = ntohs(connp->conn_lport); tce.tcpConnRemPort = ntohs(connp->conn_fport); /* Don't want just anybody seeing these... */ if (ispriv) { tce.tcpConnEntryInfo.ce_snxt = tcp->tcp_snxt; tce.tcpConnEntryInfo.ce_suna = tcp->tcp_suna; tce.tcpConnEntryInfo.ce_rnxt = tcp->tcp_rnxt; tce.tcpConnEntryInfo.ce_rack = tcp->tcp_rack; } else { /* * Netstat, unfortunately, uses this to * get send/receive queue sizes. How * to fix? * Why not compute the difference only? */ tce.tcpConnEntryInfo.ce_snxt = tcp->tcp_snxt - tcp->tcp_suna; tce.tcpConnEntryInfo.ce_suna = 0; tce.tcpConnEntryInfo.ce_rnxt = tcp->tcp_rnxt - tcp->tcp_rack; tce.tcpConnEntryInfo.ce_rack = 0; } tce.tcpConnEntryInfo.ce_swnd = tcp->tcp_swnd; tce.tcpConnEntryInfo.ce_rwnd = tcp->tcp_rwnd; tce.tcpConnEntryInfo.ce_rto = tcp->tcp_rto; tce.tcpConnEntryInfo.ce_mss = tcp->tcp_mss; tce.tcpConnEntryInfo.ce_state = tcp->tcp_state; tce.tcpConnCreationProcess = (connp->conn_cpid < 0) ? MIB2_UNKNOWN_PROCESS : connp->conn_cpid; tce.tcpConnCreationTime = connp->conn_open_time; (void) snmp_append_data2(mp_conn_ctl->b_cont, &mp_conn_tail, (char *)&tce, tce_size); mlp.tme_connidx = v4_conn_idx++; if (needattr) (void) snmp_append_data2( mp_attr_ctl->b_cont, &mp_attr_tail, (char *)&mlp, sizeof (mlp)); } } } tcp_sum_mib(tcps, &tcp_mib); /* Fixed length structure for IPv4 and IPv6 counters */ SET_MIB(tcp_mib.tcpConnTableSize, tce_size); SET_MIB(tcp_mib.tcp6ConnTableSize, tce6_size); /* * Synchronize 32- and 64-bit counters. Note that tcpInSegs and * tcpOutSegs are not updated anywhere in TCP. The new 64 bits * counters are used. Hence the old counters' values in tcp_sc_mib * are always 0. */ SYNC32_MIB(&tcp_mib, tcpInSegs, tcpHCInSegs); SYNC32_MIB(&tcp_mib, tcpOutSegs, tcpHCOutSegs); optp = (struct opthdr *)&mpctl->b_rptr[sizeof (struct T_optmgmt_ack)]; optp->level = MIB2_TCP; optp->name = 0; (void) snmp_append_data(mpdata, (char *)&tcp_mib, tcp_mib_size); optp->len = msgdsize(mpdata); qreply(q, mpctl); /* table of connections... */ optp = (struct opthdr *)&mp_conn_ctl->b_rptr[ sizeof (struct T_optmgmt_ack)]; optp->level = MIB2_TCP; optp->name = MIB2_TCP_CONN; optp->len = msgdsize(mp_conn_ctl->b_cont); qreply(q, mp_conn_ctl); /* table of MLP attributes... */ optp = (struct opthdr *)&mp_attr_ctl->b_rptr[ sizeof (struct T_optmgmt_ack)]; optp->level = MIB2_TCP; optp->name = EXPER_XPORT_MLP; optp->len = msgdsize(mp_attr_ctl->b_cont); if (optp->len == 0) freemsg(mp_attr_ctl); else qreply(q, mp_attr_ctl); /* table of IPv6 connections... */ optp = (struct opthdr *)&mp6_conn_ctl->b_rptr[ sizeof (struct T_optmgmt_ack)]; optp->level = MIB2_TCP6; optp->name = MIB2_TCP6_CONN; optp->len = msgdsize(mp6_conn_ctl->b_cont); qreply(q, mp6_conn_ctl); /* table of IPv6 MLP attributes... */ optp = (struct opthdr *)&mp6_attr_ctl->b_rptr[ sizeof (struct T_optmgmt_ack)]; optp->level = MIB2_TCP6; optp->name = EXPER_XPORT_MLP; optp->len = msgdsize(mp6_attr_ctl->b_cont); if (optp->len == 0) freemsg(mp6_attr_ctl); else qreply(q, mp6_attr_ctl); return (mp2ctl); }
static int sctp_kstat_update(kstat_t *kp, int rw) { sctp_named_kstat_t *sctpkp; sctp_t *sctp, *sctp_prev; zoneid_t zoneid; if (kp == NULL|| kp->ks_data == NULL) return (EIO); if (rw == KSTAT_WRITE) return (EACCES); zoneid = getzoneid(); /* * Get the number of current associations and gather their * individual set of statistics. */ SET_MIB(sctp_mib.sctpCurrEstab, 0); sctp = gsctp; sctp_prev = NULL; mutex_enter(&sctp_g_lock); while (sctp != NULL) { mutex_enter(&sctp->sctp_reflock); if (sctp->sctp_condemned) { mutex_exit(&sctp->sctp_reflock); sctp = list_next(&sctp_g_list, sctp); continue; } sctp->sctp_refcnt++; mutex_exit(&sctp->sctp_reflock); mutex_exit(&sctp_g_lock); if (sctp_prev != NULL) SCTP_REFRELE(sctp_prev); if (sctp->sctp_connp->conn_zoneid != zoneid) goto next_sctp; if (sctp->sctp_state == SCTPS_ESTABLISHED || sctp->sctp_state == SCTPS_SHUTDOWN_PENDING || sctp->sctp_state == SCTPS_SHUTDOWN_RECEIVED) { BUMP_MIB(&sctp_mib, sctpCurrEstab); } if (sctp->sctp_opkts) { UPDATE_MIB(&sctp_mib, sctpOutSCTPPkts, sctp->sctp_opkts); sctp->sctp_opkts = 0; } if (sctp->sctp_obchunks) { UPDATE_MIB(&sctp_mib, sctpOutCtrlChunks, sctp->sctp_obchunks); sctp->sctp_obchunks = 0; } if (sctp->sctp_odchunks) { UPDATE_MIB(&sctp_mib, sctpOutOrderChunks, sctp->sctp_odchunks); sctp->sctp_odchunks = 0; } if (sctp->sctp_oudchunks) { UPDATE_MIB(&sctp_mib, sctpOutUnorderChunks, sctp->sctp_oudchunks); sctp->sctp_oudchunks = 0; } if (sctp->sctp_rxtchunks) { UPDATE_MIB(&sctp_mib, sctpRetransChunks, sctp->sctp_rxtchunks); sctp->sctp_rxtchunks = 0; } if (sctp->sctp_ipkts) { UPDATE_MIB(&sctp_mib, sctpInSCTPPkts, sctp->sctp_ipkts); sctp->sctp_ipkts = 0; } if (sctp->sctp_ibchunks) { UPDATE_MIB(&sctp_mib, sctpInCtrlChunks, sctp->sctp_ibchunks); sctp->sctp_ibchunks = 0; } if (sctp->sctp_idchunks) { UPDATE_MIB(&sctp_mib, sctpInOrderChunks, sctp->sctp_idchunks); sctp->sctp_idchunks = 0; } if (sctp->sctp_iudchunks) { UPDATE_MIB(&sctp_mib, sctpInUnorderChunks, sctp->sctp_iudchunks); sctp->sctp_iudchunks = 0; } if (sctp->sctp_fragdmsgs) { UPDATE_MIB(&sctp_mib, sctpFragUsrMsgs, sctp->sctp_fragdmsgs); sctp->sctp_fragdmsgs = 0; } if (sctp->sctp_reassmsgs) { UPDATE_MIB(&sctp_mib, sctpReasmUsrMsgs, sctp->sctp_reassmsgs); sctp->sctp_reassmsgs = 0; } next_sctp: sctp_prev = sctp; mutex_enter(&sctp_g_lock); sctp = list_next(&sctp_g_list, sctp); } mutex_exit(&sctp_g_lock); if (sctp_prev != NULL) SCTP_REFRELE(sctp_prev); /* Copy data from the SCTP MIB */ sctpkp = (sctp_named_kstat_t *)kp->ks_data; /* These are from global ndd params. */ sctpkp->sctpRtoMin.value.ui32 = sctp_rto_ming; sctpkp->sctpRtoMax.value.ui32 = sctp_rto_maxg; sctpkp->sctpRtoInitial.value.ui32 = sctp_rto_initialg; sctpkp->sctpValCookieLife.value.ui32 = sctp_cookie_life; sctpkp->sctpMaxInitRetr.value.ui32 = sctp_max_init_retr; sctpkp->sctpCurrEstab.value.i32 = sctp_mib.sctpCurrEstab; sctpkp->sctpActiveEstab.value.i32 = sctp_mib.sctpActiveEstab; sctpkp->sctpPassiveEstab.value.i32 = sctp_mib.sctpPassiveEstab; sctpkp->sctpAborted.value.i32 = sctp_mib.sctpAborted; sctpkp->sctpShutdowns.value.i32 = sctp_mib.sctpShutdowns; sctpkp->sctpOutOfBlue.value.i32 = sctp_mib.sctpOutOfBlue; sctpkp->sctpChecksumError.value.i32 = sctp_mib.sctpChecksumError; sctpkp->sctpOutCtrlChunks.value.i64 = sctp_mib.sctpOutCtrlChunks; sctpkp->sctpOutOrderChunks.value.i64 = sctp_mib.sctpOutOrderChunks; sctpkp->sctpOutUnorderChunks.value.i64 = sctp_mib.sctpOutUnorderChunks; sctpkp->sctpRetransChunks.value.i64 = sctp_mib.sctpRetransChunks; sctpkp->sctpOutAck.value.i32 = sctp_mib.sctpOutAck; sctpkp->sctpOutAckDelayed.value.i32 = sctp_mib.sctpOutAckDelayed; sctpkp->sctpOutWinUpdate.value.i32 = sctp_mib.sctpOutWinUpdate; sctpkp->sctpOutFastRetrans.value.i32 = sctp_mib.sctpOutFastRetrans; sctpkp->sctpOutWinProbe.value.i32 = sctp_mib.sctpOutWinProbe; sctpkp->sctpInCtrlChunks.value.i64 = sctp_mib.sctpInCtrlChunks; sctpkp->sctpInOrderChunks.value.i64 = sctp_mib.sctpInOrderChunks; sctpkp->sctpInUnorderChunks.value.i64 = sctp_mib.sctpInUnorderChunks; sctpkp->sctpInAck.value.i32 = sctp_mib.sctpInAck; sctpkp->sctpInDupAck.value.i32 = sctp_mib.sctpInDupAck; sctpkp->sctpInAckUnsent.value.i32 = sctp_mib.sctpInAckUnsent; sctpkp->sctpFragUsrMsgs.value.i64 = sctp_mib.sctpFragUsrMsgs; sctpkp->sctpReasmUsrMsgs.value.i64 = sctp_mib.sctpReasmUsrMsgs; sctpkp->sctpOutSCTPPkts.value.i64 = sctp_mib.sctpOutSCTPPkts; sctpkp->sctpInSCTPPkts.value.i64 = sctp_mib.sctpInSCTPPkts; sctpkp->sctpInInvalidCookie.value.i32 = sctp_mib.sctpInInvalidCookie; sctpkp->sctpTimRetrans.value.i32 = sctp_mib.sctpTimRetrans; sctpkp->sctpTimRetransDrop.value.i32 = sctp_mib.sctpTimRetransDrop; sctpkp->sctpTimHeartBeatProbe.value.i32 = sctp_mib.sctpTimHeartBeatProbe; sctpkp->sctpTimHeartBeatDrop.value.i32 = sctp_mib.sctpTimHeartBeatDrop; sctpkp->sctpListenDrop.value.i32 = sctp_mib.sctpListenDrop; sctpkp->sctpInClosed.value.i32 = sctp_mib.sctpInClosed; return (0); }