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 }