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 2010 Sun Microsystems, Inc. All rights reserved. 24 * Copyright 2012 David Hoeppner. All rights reserved. 25 */ 26 27 /* 28 * Functions related to MIB-II and kstat. 29 */ 30 31 #include <sys/types.h> 32 #include <sys/tihdr.h> 33 #include <sys/policy.h> 34 #include <sys/tsol/tnet.h> 35 36 #include <inet/common.h> 37 #include <inet/ip.h> 38 #include <inet/kstatcom.h> 39 #include <inet/snmpcom.h> 40 41 #include <sys/cmn_err.h> 42 43 #include "dccp_impl.h" 44 45 static int dccp_snmp_state(dccp_t *); 46 static int dccp_kstat_update(kstat_t *, int); 47 48 /* 49 * Translate DCCP state to MIB2 state. 50 */ 51 static int 52 dccp_snmp_state(dccp_t *dccp) 53 { 54 if (dccp == NULL) { 55 return (0); 56 } 57 58 switch(dccp->dccp_state) { 59 case DCCPS_CLOSED: 60 return (MIB2_DCCP_closed); 61 default: 62 return (0); 63 } 64 } 65 66 /* 67 * Get the MIB-II stats. 68 */ 69 mblk_t * 70 dccp_snmp_get(queue_t *q, mblk_t *mpctl, boolean_t legacy_req) 71 { 72 conn_t *connp = Q_TO_CONN(q); 73 connf_t *connfp; 74 ip_stack_t *ipst; 75 dccp_stack_t *dccps; 76 struct opthdr *optp; 77 mblk_t *mp2ctl; 78 mblk_t *mpdata; 79 mblk_t *mp_conn_ctl = NULL; 80 mblk_t *mp_conn_tail; 81 mblk_t *mp_attr_ctl = NULL; 82 mblk_t *mp_attr_tail; 83 mblk_t *mp6_conn_ctl = NULL; 84 mblk_t *mp6_conn_tail; 85 mblk_t *mp6_attr_ctl = NULL; 86 mblk_t *mp6_attr_tail; 87 size_t dccp_mib_size; 88 size_t dce_size; 89 size_t dce6_size; 90 zoneid_t zoneid; 91 int i; 92 mib2_dccp_t dccp_mib; 93 mib2_dccpConnEntry_t dce; 94 mib2_dccp6ConnEntry_t dce6; 95 96 /* 97 * Make a copy of the original message. 98 */ 99 mp2ctl = copymsg(mpctl); 100 101 cmn_err(CE_NOTE, "dccp_stats.c: dccp_snmp_get"); 102 103 if (mpctl == NULL || 104 (mpdata = mpctl->b_cont) == NULL || 105 (mp_conn_ctl = copymsg(mpctl)) == NULL || 106 (mp_attr_ctl = copymsg(mpctl)) == NULL) { 107 freemsg(mp_conn_ctl); 108 freemsg(mp_attr_ctl); 109 freemsg(mpctl); 110 freemsg(mp2ctl); 111 return (NULL); 112 } 113 114 ipst = connp->conn_netstack->netstack_ip; 115 dccps = connp->conn_netstack->netstack_dccp; 116 117 if (legacy_req) { 118 dccp_mib_size = LEGACY_MIB_SIZE(&dccp_mib, mib2_dccp_t); 119 dce_size = LEGACY_MIB_SIZE(&dce, mib2_dccpConnEntry_t); 120 dce6_size = LEGACY_MIB_SIZE(&dce6, mib2_dccp6ConnEntry_t); 121 } else { 122 dccp_mib_size = sizeof (mib2_dccp_t); 123 dce_size = sizeof (mib2_dccpConnEntry_t); 124 dce6_size = sizeof (mib2_dccp6ConnEntry_t); 125 } 126 127 bzero(&dccp_mib, sizeof (dccp_mib)); 128 zoneid = Q_TO_CONN(q)->conn_zoneid; 129 mp_conn_tail = mp_attr_tail = mp6_conn_tail = mp6_attr_tail = NULL; 130 131 for (i = 0; i < CONN_G_HASH_SIZE; i++) { 132 ipst = dccps->dccps_netstack->netstack_ip; 133 134 connfp = &ipst->ips_ipcl_globalhash_fanout[i]; 135 connp = NULL; 136 137 while ((connp = ipcl_get_next_conn(connfp, connp, 138 IPCL_DCCPCONN)) != NULL) { 139 dccp_t *dccp; 140 141 if (connp->conn_zoneid != zoneid) { 142 continue; 143 } 144 145 dccp = connp->conn_dccp; 146 147 dce.dccpConnState = dccp_snmp_state(dccp); 148 149 if (connp->conn_ipversion == IPV4_VERSION || 150 (dccp->dccp_state <= DCCPS_LISTEN)) { 151 152 if (connp->conn_ipversion == IPV6_VERSION) { 153 dce.dccpConnRemAddress = INADDR_ANY; 154 dce.dccpConnLocalAddress = INADDR_ANY; 155 } else { 156 dce.dccpConnRemAddress = 157 connp->conn_faddr_v4; 158 dce.dccpConnLocalAddress = 159 connp->conn_laddr_v4; 160 } 161 162 dce.dccpConnLocalPort = ntohs(connp->conn_lport); 163 dce.dccpConnRemPort = ntohs(connp->conn_fport); 164 /* 165 dce.dccpConnCreationProcess = (connp->conn_cpid < 0) ? 166 MIB2_UNKNOWN_PROCESS : connp->conn_cpid; 167 dce.dccpConnCreationTime = connp->conn_open_time; 168 */ 169 (void) snmp_append_data2(mp_conn_ctl->b_cont, 170 &mp_conn_tail, (char *)&dce, dce_size); 171 172 } 173 } 174 } 175 176 SET_MIB(dccp_mib.dccpConnTableSize, dce_size); 177 SET_MIB(dccp_mib.dccp6ConnTableSize, dce6_size); 178 179 optp = (struct opthdr *)&mpctl->b_rptr[sizeof (struct T_optmgmt_ack)]; 180 optp->level = MIB2_DCCP; 181 optp->name = 0; 182 (void) snmp_append_data(mpdata, (char *)&dccp_mib, dccp_mib_size); 183 optp->len = msgdsize(mpdata); 184 qreply(q, mpctl); 185 186 optp = (struct opthdr *)&mp_conn_ctl->b_rptr[ 187 sizeof (struct T_optmgmt_ack)]; 188 optp->level = MIB2_DCCP; 189 optp->name = MIB2_DCCP_CONN; 190 optp->len = msgdsize(mp_conn_ctl->b_cont); 191 qreply(q, mp_conn_ctl); 192 193 optp = (struct opthdr *)&mp_attr_ctl->b_rptr[ 194 sizeof (struct T_optmgmt_ack)]; 195 optp->level = MIB2_DCCP; 196 optp->name = EXPER_XPORT_MLP; 197 optp->len = msgdsize(mp_attr_ctl->b_cont); 198 if (optp->len == 0) { 199 freemsg(mp_attr_ctl); 200 } else { 201 qreply(q, mp_attr_ctl); 202 } 203 204 return (mp2ctl); 205 } 206 207 /* 208 * DCCP kernel statistics. 209 */ 210 void * 211 dccp_kstat_init(netstackid_t stackid) 212 { 213 kstat_t *ksp; 214 215 dccp_named_kstat_t template = { 216 { "activeOpens", KSTAT_DATA_UINT32, 0 }, 217 { "passiveOpens", KSTAT_DATA_UINT32, 0 }, 218 { "inSegs", KSTAT_DATA_UINT64, 0 }, 219 { "outSegs", KSTAT_DATA_UINT64, 0 }, 220 }; 221 222 ksp = kstat_create_netstack(DCCP_MOD_NAME, 0, DCCP_MOD_NAME, "mib2", 223 KSTAT_TYPE_NAMED, NUM_OF_FIELDS(dccp_named_kstat_t), 0, stackid); 224 if (ksp == NULL) { 225 return (NULL); 226 } 227 228 bcopy(&template, ksp->ks_data, sizeof (template)); 229 ksp->ks_update = dccp_kstat_update; 230 ksp->ks_private = (void *)(uintptr_t)stackid; 231 232 kstat_install(ksp); 233 234 return (ksp); 235 } 236 237 /* 238 * Destroy DCCP kernel statistics. 239 */ 240 void 241 dccp_kstat_fini(netstackid_t stackid, kstat_t *ksp) 242 { 243 244 if (ksp != NULL) { 245 ASSERT(stackid == (netstackid_t)(uintptr_t)ksp->ks_private); 246 kstat_delete_netstack(ksp, stackid); 247 } 248 } 249 250 /* 251 * Update DCCP kernel statistics. 252 */ 253 static int 254 dccp_kstat_update(kstat_t *ksp, int rw) 255 { 256 257 if (rw == KSTAT_WRITE) { 258 return (EACCES); 259 } 260 261 return (0); 262 }