Merge commit '7e934d3acc051b7ee3ef0d11571fd1225800a607'
[unleashed.git] / kernel / net / tcp / tcp_stats.c
blob063e94bdc9c266acaab39dd75fbdcfb2d94c4bc5
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) 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2011, Joyent Inc. All rights reserved.
27 #include <sys/types.h>
28 #include <sys/tihdr.h>
29 #include <sys/policy.h>
30 #include <sys/kstat.h>
32 #include <inet/common.h>
33 #include <inet/ip.h>
34 #include <inet/tcp.h>
35 #include <inet/tcp_impl.h>
36 #include <inet/tcp_stats.h>
37 #include <inet/kstatcom.h>
38 #include <inet/snmpcom.h>
40 static int tcp_kstat_update(kstat_t *, int);
41 static int tcp_kstat2_update(kstat_t *, int);
42 static void tcp_sum_mib(tcp_stack_t *, mib2_tcp_t *);
44 static void tcp_add_mib(mib2_tcp_t *, mib2_tcp_t *);
45 static void tcp_add_stats(tcp_stat_counter_t *, tcp_stat_t *);
46 static void tcp_clr_stats(tcp_stat_t *);
48 tcp_g_stat_t tcp_g_statistics;
49 kstat_t *tcp_g_kstat;
51 /* Translate TCP state to MIB2 TCP state. */
52 static int
53 tcp_snmp_state(tcp_t *tcp)
55 if (tcp == NULL)
56 return (0);
58 switch (tcp->tcp_state) {
59 case TCPS_CLOSED:
60 case TCPS_IDLE: /* RFC1213 doesn't have analogue for IDLE & BOUND */
61 case TCPS_BOUND:
62 return (MIB2_TCP_closed);
63 case TCPS_LISTEN:
64 return (MIB2_TCP_listen);
65 case TCPS_SYN_SENT:
66 return (MIB2_TCP_synSent);
67 case TCPS_SYN_RCVD:
68 return (MIB2_TCP_synReceived);
69 case TCPS_ESTABLISHED:
70 return (MIB2_TCP_established);
71 case TCPS_CLOSE_WAIT:
72 return (MIB2_TCP_closeWait);
73 case TCPS_FIN_WAIT_1:
74 return (MIB2_TCP_finWait1);
75 case TCPS_CLOSING:
76 return (MIB2_TCP_closing);
77 case TCPS_LAST_ACK:
78 return (MIB2_TCP_lastAck);
79 case TCPS_FIN_WAIT_2:
80 return (MIB2_TCP_finWait2);
81 case TCPS_TIME_WAIT:
82 return (MIB2_TCP_timeWait);
83 default:
84 return (0);
89 * Return SNMP stuff in buffer in mpdata.
91 mblk_t *
92 tcp_snmp_get(queue_t *q, mblk_t *mpctl, boolean_t legacy_req)
94 mblk_t *mpdata;
95 mblk_t *mp_conn_ctl = NULL;
96 mblk_t *mp_conn_tail;
97 mblk_t *mp6_conn_ctl = NULL;
98 mblk_t *mp6_conn_tail;
99 struct opthdr *optp;
100 mib2_tcpConnEntry_t tce;
101 mib2_tcp6ConnEntry_t tce6;
102 connf_t *connfp;
103 int i;
104 boolean_t ispriv;
105 zoneid_t zoneid;
106 int v4_conn_idx;
107 int v6_conn_idx;
108 conn_t *connp = Q_TO_CONN(q);
109 tcp_stack_t *tcps;
110 ip_stack_t *ipst;
111 mblk_t *mp2ctl;
112 mib2_tcp_t tcp_mib;
113 size_t tcp_mib_size, tce_size, tce6_size;
116 * make a copy of the original message
118 mp2ctl = copymsg(mpctl);
120 if (mpctl == NULL ||
121 (mpdata = mpctl->b_cont) == NULL ||
122 (mp_conn_ctl = copymsg(mpctl)) == NULL ||
123 (mp6_conn_ctl = copymsg(mpctl)) == NULL) {
124 freemsg(mp_conn_ctl);
125 freemsg(mp6_conn_ctl);
126 freemsg(mpctl);
127 freemsg(mp2ctl);
128 return (NULL);
131 ipst = connp->conn_netstack->netstack_ip;
132 tcps = connp->conn_netstack->netstack_tcp;
134 if (legacy_req) {
135 tcp_mib_size = LEGACY_MIB_SIZE(&tcp_mib, mib2_tcp_t);
136 tce_size = LEGACY_MIB_SIZE(&tce, mib2_tcpConnEntry_t);
137 tce6_size = LEGACY_MIB_SIZE(&tce6, mib2_tcp6ConnEntry_t);
138 } else {
139 tcp_mib_size = sizeof (mib2_tcp_t);
140 tce_size = sizeof (mib2_tcpConnEntry_t);
141 tce6_size = sizeof (mib2_tcp6ConnEntry_t);
144 bzero(&tcp_mib, sizeof (tcp_mib));
146 /* build table of connections -- need count in fixed part */
147 SET_MIB(tcp_mib.tcpRtoAlgorithm, 4); /* vanj */
148 SET_MIB(tcp_mib.tcpRtoMin, tcps->tcps_rexmit_interval_min);
149 SET_MIB(tcp_mib.tcpRtoMax, tcps->tcps_rexmit_interval_max);
150 SET_MIB(tcp_mib.tcpMaxConn, -1);
151 SET_MIB(tcp_mib.tcpCurrEstab, 0);
153 ispriv =
154 secpolicy_ip_config((Q_TO_CONN(q))->conn_cred, B_TRUE) == 0;
155 zoneid = Q_TO_CONN(q)->conn_zoneid;
157 v4_conn_idx = v6_conn_idx = 0;
158 mp_conn_tail = mp6_conn_tail = NULL;
160 for (i = 0; i < CONN_G_HASH_SIZE; i++) {
161 ipst = tcps->tcps_netstack->netstack_ip;
163 connfp = &ipst->ips_ipcl_globalhash_fanout[i];
165 connp = NULL;
167 while ((connp =
168 ipcl_get_next_conn(connfp, connp, IPCL_TCPCONN)) != NULL) {
169 tcp_t *tcp;
171 if (connp->conn_zoneid != zoneid)
172 continue; /* not in this zone */
174 tcp = connp->conn_tcp;
175 TCPS_UPDATE_MIB(tcps, tcpHCInSegs, tcp->tcp_ibsegs);
176 tcp->tcp_ibsegs = 0;
177 TCPS_UPDATE_MIB(tcps, tcpHCOutSegs, tcp->tcp_obsegs);
178 tcp->tcp_obsegs = 0;
180 tce6.tcp6ConnState = tce.tcpConnState =
181 tcp_snmp_state(tcp);
182 if (tce.tcpConnState == MIB2_TCP_established ||
183 tce.tcpConnState == MIB2_TCP_closeWait)
184 BUMP_MIB(&tcp_mib, tcpCurrEstab);
186 /* Create a message to report on IPv6 entries */
187 if (connp->conn_ipversion == IPV6_VERSION) {
188 tce6.tcp6ConnLocalAddress = connp->conn_laddr_v6;
189 tce6.tcp6ConnRemAddress = connp->conn_faddr_v6;
190 tce6.tcp6ConnLocalPort = ntohs(connp->conn_lport);
191 tce6.tcp6ConnRemPort = ntohs(connp->conn_fport);
192 if (connp->conn_ixa->ixa_flags & IXAF_SCOPEID_SET) {
193 tce6.tcp6ConnIfIndex =
194 connp->conn_ixa->ixa_scopeid;
195 } else {
196 tce6.tcp6ConnIfIndex = connp->conn_bound_if;
198 /* Don't want just anybody seeing these... */
199 if (ispriv) {
200 tce6.tcp6ConnEntryInfo.ce_snxt =
201 tcp->tcp_snxt;
202 tce6.tcp6ConnEntryInfo.ce_suna =
203 tcp->tcp_suna;
204 tce6.tcp6ConnEntryInfo.ce_rnxt =
205 tcp->tcp_rnxt;
206 tce6.tcp6ConnEntryInfo.ce_rack =
207 tcp->tcp_rack;
208 } else {
210 * Netstat, unfortunately, uses this to
211 * get send/receive queue sizes. How to fix?
212 * Why not compute the difference only?
214 tce6.tcp6ConnEntryInfo.ce_snxt =
215 tcp->tcp_snxt - tcp->tcp_suna;
216 tce6.tcp6ConnEntryInfo.ce_suna = 0;
217 tce6.tcp6ConnEntryInfo.ce_rnxt =
218 tcp->tcp_rnxt - tcp->tcp_rack;
219 tce6.tcp6ConnEntryInfo.ce_rack = 0;
222 tce6.tcp6ConnEntryInfo.ce_swnd = tcp->tcp_swnd;
223 tce6.tcp6ConnEntryInfo.ce_rwnd = tcp->tcp_rwnd;
224 tce6.tcp6ConnEntryInfo.ce_rto = tcp->tcp_rto;
225 tce6.tcp6ConnEntryInfo.ce_mss = tcp->tcp_mss;
226 tce6.tcp6ConnEntryInfo.ce_state = tcp->tcp_state;
228 tce6.tcp6ConnCreationProcess =
229 (connp->conn_cpid < 0) ? MIB2_UNKNOWN_PROCESS :
230 connp->conn_cpid;
231 tce6.tcp6ConnCreationTime = connp->conn_open_time;
233 (void) snmp_append_data2(mp6_conn_ctl->b_cont,
234 &mp6_conn_tail, (char *)&tce6, tce6_size);
238 * Create an IPv4 table entry for IPv4 entries and also
239 * for IPv6 entries which are bound to in6addr_any
240 * but don't have IPV6_V6ONLY set.
241 * (i.e. anything an IPv4 peer could connect to)
243 if (connp->conn_ipversion == IPV4_VERSION ||
244 (tcp->tcp_state <= TCPS_LISTEN &&
245 !connp->conn_ipv6_v6only &&
246 IN6_IS_ADDR_UNSPECIFIED(&connp->conn_laddr_v6))) {
247 if (connp->conn_ipversion == IPV6_VERSION) {
248 tce.tcpConnRemAddress = INADDR_ANY;
249 tce.tcpConnLocalAddress = INADDR_ANY;
250 } else {
251 tce.tcpConnRemAddress =
252 connp->conn_faddr_v4;
253 tce.tcpConnLocalAddress =
254 connp->conn_laddr_v4;
256 tce.tcpConnLocalPort = ntohs(connp->conn_lport);
257 tce.tcpConnRemPort = ntohs(connp->conn_fport);
258 /* Don't want just anybody seeing these... */
259 if (ispriv) {
260 tce.tcpConnEntryInfo.ce_snxt =
261 tcp->tcp_snxt;
262 tce.tcpConnEntryInfo.ce_suna =
263 tcp->tcp_suna;
264 tce.tcpConnEntryInfo.ce_rnxt =
265 tcp->tcp_rnxt;
266 tce.tcpConnEntryInfo.ce_rack =
267 tcp->tcp_rack;
268 } else {
270 * Netstat, unfortunately, uses this to
271 * get send/receive queue sizes. How
272 * to fix?
273 * Why not compute the difference only?
275 tce.tcpConnEntryInfo.ce_snxt =
276 tcp->tcp_snxt - tcp->tcp_suna;
277 tce.tcpConnEntryInfo.ce_suna = 0;
278 tce.tcpConnEntryInfo.ce_rnxt =
279 tcp->tcp_rnxt - tcp->tcp_rack;
280 tce.tcpConnEntryInfo.ce_rack = 0;
283 tce.tcpConnEntryInfo.ce_swnd = tcp->tcp_swnd;
284 tce.tcpConnEntryInfo.ce_rwnd = tcp->tcp_rwnd;
285 tce.tcpConnEntryInfo.ce_rto = tcp->tcp_rto;
286 tce.tcpConnEntryInfo.ce_mss = tcp->tcp_mss;
287 tce.tcpConnEntryInfo.ce_state =
288 tcp->tcp_state;
290 tce.tcpConnCreationProcess =
291 (connp->conn_cpid < 0) ?
292 MIB2_UNKNOWN_PROCESS :
293 connp->conn_cpid;
294 tce.tcpConnCreationTime = connp->conn_open_time;
296 (void) snmp_append_data2(mp_conn_ctl->b_cont,
297 &mp_conn_tail, (char *)&tce, tce_size);
302 tcp_sum_mib(tcps, &tcp_mib);
304 /* Fixed length structure for IPv4 and IPv6 counters */
305 SET_MIB(tcp_mib.tcpConnTableSize, tce_size);
306 SET_MIB(tcp_mib.tcp6ConnTableSize, tce6_size);
309 * Synchronize 32- and 64-bit counters. Note that tcpInSegs and
310 * tcpOutSegs are not updated anywhere in TCP. The new 64 bits
311 * counters are used. Hence the old counters' values in tcp_sc_mib
312 * are always 0.
314 SYNC32_MIB(&tcp_mib, tcpInSegs, tcpHCInSegs);
315 SYNC32_MIB(&tcp_mib, tcpOutSegs, tcpHCOutSegs);
317 optp = (struct opthdr *)&mpctl->b_rptr[sizeof (struct T_optmgmt_ack)];
318 optp->level = MIB2_TCP;
319 optp->name = 0;
320 (void) snmp_append_data(mpdata, (char *)&tcp_mib, tcp_mib_size);
321 optp->len = msgdsize(mpdata);
322 qreply(q, mpctl);
324 /* table of connections... */
325 optp = (struct opthdr *)&mp_conn_ctl->b_rptr[
326 sizeof (struct T_optmgmt_ack)];
327 optp->level = MIB2_TCP;
328 optp->name = MIB2_TCP_CONN;
329 optp->len = msgdsize(mp_conn_ctl->b_cont);
330 qreply(q, mp_conn_ctl);
332 /* table of IPv6 connections... */
333 optp = (struct opthdr *)&mp6_conn_ctl->b_rptr[
334 sizeof (struct T_optmgmt_ack)];
335 optp->level = MIB2_TCP6;
336 optp->name = MIB2_TCP6_CONN;
337 optp->len = msgdsize(mp6_conn_ctl->b_cont);
338 qreply(q, mp6_conn_ctl);
340 return (mp2ctl);
343 /* Return 0 if invalid set request, 1 otherwise, including non-tcp requests */
344 /* ARGSUSED */
346 tcp_snmp_set(queue_t *q, int level, int name, uchar_t *ptr, int len)
348 mib2_tcpConnEntry_t *tce = (mib2_tcpConnEntry_t *)ptr;
350 switch (level) {
351 case MIB2_TCP:
352 switch (name) {
353 case 13:
354 if (tce->tcpConnState != MIB2_TCP_deleteTCB)
355 return (0);
356 /* TODO: delete entry defined by tce */
357 return (1);
358 default:
359 return (0);
361 default:
362 return (1);
367 * TCP Kstats implementation
369 void *
370 tcp_kstat_init(netstackid_t stackid)
372 kstat_t *ksp;
374 tcp_named_kstat_t template = {
375 { "rtoAlgorithm", KSTAT_DATA_INT32, 0 },
376 { "rtoMin", KSTAT_DATA_INT32, 0 },
377 { "rtoMax", KSTAT_DATA_INT32, 0 },
378 { "maxConn", KSTAT_DATA_INT32, 0 },
379 { "activeOpens", KSTAT_DATA_UINT32, 0 },
380 { "passiveOpens", KSTAT_DATA_UINT32, 0 },
381 { "attemptFails", KSTAT_DATA_UINT32, 0 },
382 { "estabResets", KSTAT_DATA_UINT32, 0 },
383 { "currEstab", KSTAT_DATA_UINT32, 0 },
384 { "inSegs", KSTAT_DATA_UINT64, 0 },
385 { "outSegs", KSTAT_DATA_UINT64, 0 },
386 { "retransSegs", KSTAT_DATA_UINT32, 0 },
387 { "connTableSize", KSTAT_DATA_INT32, 0 },
388 { "outRsts", KSTAT_DATA_UINT32, 0 },
389 { "outDataSegs", KSTAT_DATA_UINT32, 0 },
390 { "outDataBytes", KSTAT_DATA_UINT32, 0 },
391 { "retransBytes", KSTAT_DATA_UINT32, 0 },
392 { "outAck", KSTAT_DATA_UINT32, 0 },
393 { "outAckDelayed", KSTAT_DATA_UINT32, 0 },
394 { "outUrg", KSTAT_DATA_UINT32, 0 },
395 { "outWinUpdate", KSTAT_DATA_UINT32, 0 },
396 { "outWinProbe", KSTAT_DATA_UINT32, 0 },
397 { "outControl", KSTAT_DATA_UINT32, 0 },
398 { "outFastRetrans", KSTAT_DATA_UINT32, 0 },
399 { "inAckSegs", KSTAT_DATA_UINT32, 0 },
400 { "inAckBytes", KSTAT_DATA_UINT32, 0 },
401 { "inDupAck", KSTAT_DATA_UINT32, 0 },
402 { "inAckUnsent", KSTAT_DATA_UINT32, 0 },
403 { "inDataInorderSegs", KSTAT_DATA_UINT32, 0 },
404 { "inDataInorderBytes", KSTAT_DATA_UINT32, 0 },
405 { "inDataUnorderSegs", KSTAT_DATA_UINT32, 0 },
406 { "inDataUnorderBytes", KSTAT_DATA_UINT32, 0 },
407 { "inDataDupSegs", KSTAT_DATA_UINT32, 0 },
408 { "inDataDupBytes", KSTAT_DATA_UINT32, 0 },
409 { "inDataPartDupSegs", KSTAT_DATA_UINT32, 0 },
410 { "inDataPartDupBytes", KSTAT_DATA_UINT32, 0 },
411 { "inDataPastWinSegs", KSTAT_DATA_UINT32, 0 },
412 { "inDataPastWinBytes", KSTAT_DATA_UINT32, 0 },
413 { "inWinProbe", KSTAT_DATA_UINT32, 0 },
414 { "inWinUpdate", KSTAT_DATA_UINT32, 0 },
415 { "inClosed", KSTAT_DATA_UINT32, 0 },
416 { "rttUpdate", KSTAT_DATA_UINT32, 0 },
417 { "rttNoUpdate", KSTAT_DATA_UINT32, 0 },
418 { "timRetrans", KSTAT_DATA_UINT32, 0 },
419 { "timRetransDrop", KSTAT_DATA_UINT32, 0 },
420 { "timKeepalive", KSTAT_DATA_UINT32, 0 },
421 { "timKeepaliveProbe", KSTAT_DATA_UINT32, 0 },
422 { "timKeepaliveDrop", KSTAT_DATA_UINT32, 0 },
423 { "listenDrop", KSTAT_DATA_UINT32, 0 },
424 { "listenDropQ0", KSTAT_DATA_UINT32, 0 },
425 { "halfOpenDrop", KSTAT_DATA_UINT32, 0 },
426 { "outSackRetransSegs", KSTAT_DATA_UINT32, 0 },
427 { "connTableSize6", KSTAT_DATA_INT32, 0 }
430 ksp = kstat_create_netstack(TCP_MOD_NAME, stackid, TCP_MOD_NAME, "mib2",
431 KSTAT_TYPE_NAMED, NUM_OF_FIELDS(tcp_named_kstat_t), 0, stackid);
433 if (ksp == NULL)
434 return (NULL);
436 template.rtoAlgorithm.value.ui32 = 4;
437 template.maxConn.value.i32 = -1;
439 bcopy(&template, ksp->ks_data, sizeof (template));
440 ksp->ks_update = tcp_kstat_update;
441 ksp->ks_private = (void *)(uintptr_t)stackid;
444 * If this is an exclusive netstack for a local zone, the global zone
445 * should still be able to read the kstat.
447 if (stackid != GLOBAL_NETSTACKID)
448 kstat_zone_add(ksp, GLOBAL_ZONEID);
450 kstat_install(ksp);
451 return (ksp);
454 void
455 tcp_kstat_fini(netstackid_t stackid, kstat_t *ksp)
457 if (ksp != NULL) {
458 ASSERT(stackid == (netstackid_t)(uintptr_t)ksp->ks_private);
459 kstat_delete_netstack(ksp, stackid);
463 static int
464 tcp_kstat_update(kstat_t *kp, int rw)
466 tcp_named_kstat_t *tcpkp;
467 tcp_t *tcp;
468 connf_t *connfp;
469 conn_t *connp;
470 int i;
471 netstackid_t stackid = (netstackid_t)(uintptr_t)kp->ks_private;
472 netstack_t *ns;
473 tcp_stack_t *tcps;
474 ip_stack_t *ipst;
475 mib2_tcp_t tcp_mib;
477 if (rw == KSTAT_WRITE)
478 return (EACCES);
480 ns = netstack_find_by_stackid(stackid);
481 if (ns == NULL)
482 return (-1);
483 tcps = ns->netstack_tcp;
484 if (tcps == NULL) {
485 netstack_rele(ns);
486 return (-1);
489 tcpkp = (tcp_named_kstat_t *)kp->ks_data;
491 tcpkp->currEstab.value.ui32 = 0;
492 tcpkp->rtoMin.value.ui32 = tcps->tcps_rexmit_interval_min;
493 tcpkp->rtoMax.value.ui32 = tcps->tcps_rexmit_interval_max;
495 ipst = ns->netstack_ip;
497 for (i = 0; i < CONN_G_HASH_SIZE; i++) {
498 connfp = &ipst->ips_ipcl_globalhash_fanout[i];
499 connp = NULL;
500 while ((connp =
501 ipcl_get_next_conn(connfp, connp, IPCL_TCPCONN)) != NULL) {
502 tcp = connp->conn_tcp;
503 switch (tcp_snmp_state(tcp)) {
504 case MIB2_TCP_established:
505 case MIB2_TCP_closeWait:
506 tcpkp->currEstab.value.ui32++;
507 break;
511 bzero(&tcp_mib, sizeof (tcp_mib));
512 tcp_sum_mib(tcps, &tcp_mib);
514 /* Fixed length structure for IPv4 and IPv6 counters */
515 SET_MIB(tcp_mib.tcpConnTableSize, sizeof (mib2_tcpConnEntry_t));
516 SET_MIB(tcp_mib.tcp6ConnTableSize, sizeof (mib2_tcp6ConnEntry_t));
518 tcpkp->activeOpens.value.ui32 = tcp_mib.tcpActiveOpens;
519 tcpkp->passiveOpens.value.ui32 = tcp_mib.tcpPassiveOpens;
520 tcpkp->attemptFails.value.ui32 = tcp_mib.tcpAttemptFails;
521 tcpkp->estabResets.value.ui32 = tcp_mib.tcpEstabResets;
522 tcpkp->inSegs.value.ui64 = tcp_mib.tcpHCInSegs;
523 tcpkp->outSegs.value.ui64 = tcp_mib.tcpHCOutSegs;
524 tcpkp->retransSegs.value.ui32 = tcp_mib.tcpRetransSegs;
525 tcpkp->connTableSize.value.i32 = tcp_mib.tcpConnTableSize;
526 tcpkp->outRsts.value.ui32 = tcp_mib.tcpOutRsts;
527 tcpkp->outDataSegs.value.ui32 = tcp_mib.tcpOutDataSegs;
528 tcpkp->outDataBytes.value.ui32 = tcp_mib.tcpOutDataBytes;
529 tcpkp->retransBytes.value.ui32 = tcp_mib.tcpRetransBytes;
530 tcpkp->outAck.value.ui32 = tcp_mib.tcpOutAck;
531 tcpkp->outAckDelayed.value.ui32 = tcp_mib.tcpOutAckDelayed;
532 tcpkp->outUrg.value.ui32 = tcp_mib.tcpOutUrg;
533 tcpkp->outWinUpdate.value.ui32 = tcp_mib.tcpOutWinUpdate;
534 tcpkp->outWinProbe.value.ui32 = tcp_mib.tcpOutWinProbe;
535 tcpkp->outControl.value.ui32 = tcp_mib.tcpOutControl;
536 tcpkp->outFastRetrans.value.ui32 = tcp_mib.tcpOutFastRetrans;
537 tcpkp->inAckSegs.value.ui32 = tcp_mib.tcpInAckSegs;
538 tcpkp->inAckBytes.value.ui32 = tcp_mib.tcpInAckBytes;
539 tcpkp->inDupAck.value.ui32 = tcp_mib.tcpInDupAck;
540 tcpkp->inAckUnsent.value.ui32 = tcp_mib.tcpInAckUnsent;
541 tcpkp->inDataInorderSegs.value.ui32 = tcp_mib.tcpInDataInorderSegs;
542 tcpkp->inDataInorderBytes.value.ui32 = tcp_mib.tcpInDataInorderBytes;
543 tcpkp->inDataUnorderSegs.value.ui32 = tcp_mib.tcpInDataUnorderSegs;
544 tcpkp->inDataUnorderBytes.value.ui32 = tcp_mib.tcpInDataUnorderBytes;
545 tcpkp->inDataDupSegs.value.ui32 = tcp_mib.tcpInDataDupSegs;
546 tcpkp->inDataDupBytes.value.ui32 = tcp_mib.tcpInDataDupBytes;
547 tcpkp->inDataPartDupSegs.value.ui32 = tcp_mib.tcpInDataPartDupSegs;
548 tcpkp->inDataPartDupBytes.value.ui32 = tcp_mib.tcpInDataPartDupBytes;
549 tcpkp->inDataPastWinSegs.value.ui32 = tcp_mib.tcpInDataPastWinSegs;
550 tcpkp->inDataPastWinBytes.value.ui32 = tcp_mib.tcpInDataPastWinBytes;
551 tcpkp->inWinProbe.value.ui32 = tcp_mib.tcpInWinProbe;
552 tcpkp->inWinUpdate.value.ui32 = tcp_mib.tcpInWinUpdate;
553 tcpkp->inClosed.value.ui32 = tcp_mib.tcpInClosed;
554 tcpkp->rttNoUpdate.value.ui32 = tcp_mib.tcpRttNoUpdate;
555 tcpkp->rttUpdate.value.ui32 = tcp_mib.tcpRttUpdate;
556 tcpkp->timRetrans.value.ui32 = tcp_mib.tcpTimRetrans;
557 tcpkp->timRetransDrop.value.ui32 = tcp_mib.tcpTimRetransDrop;
558 tcpkp->timKeepalive.value.ui32 = tcp_mib.tcpTimKeepalive;
559 tcpkp->timKeepaliveProbe.value.ui32 = tcp_mib.tcpTimKeepaliveProbe;
560 tcpkp->timKeepaliveDrop.value.ui32 = tcp_mib.tcpTimKeepaliveDrop;
561 tcpkp->listenDrop.value.ui32 = tcp_mib.tcpListenDrop;
562 tcpkp->listenDropQ0.value.ui32 = tcp_mib.tcpListenDropQ0;
563 tcpkp->halfOpenDrop.value.ui32 = tcp_mib.tcpHalfOpenDrop;
564 tcpkp->outSackRetransSegs.value.ui32 = tcp_mib.tcpOutSackRetransSegs;
565 tcpkp->connTableSize6.value.i32 = tcp_mib.tcp6ConnTableSize;
567 netstack_rele(ns);
568 return (0);
572 * kstats related to squeues i.e. not per IP instance
574 void *
575 tcp_g_kstat_init(tcp_g_stat_t *tcp_g_statp)
577 kstat_t *ksp;
579 tcp_g_stat_t template = {
580 { "tcp_timermp_alloced", KSTAT_DATA_UINT64 },
581 { "tcp_timermp_allocfail", KSTAT_DATA_UINT64 },
582 { "tcp_timermp_allocdblfail", KSTAT_DATA_UINT64 },
583 { "tcp_freelist_cleanup", KSTAT_DATA_UINT64 },
586 ksp = kstat_create(TCP_MOD_NAME, 0, "tcpstat_g", "net",
587 KSTAT_TYPE_NAMED, sizeof (template) / sizeof (kstat_named_t),
588 KSTAT_FLAG_VIRTUAL);
590 if (ksp == NULL)
591 return (NULL);
593 bcopy(&template, tcp_g_statp, sizeof (template));
594 ksp->ks_data = (void *)tcp_g_statp;
596 kstat_install(ksp);
597 return (ksp);
600 void
601 tcp_g_kstat_fini(kstat_t *ksp)
603 if (ksp != NULL) {
604 kstat_delete(ksp);
608 void *
609 tcp_kstat2_init(netstackid_t stackid)
611 kstat_t *ksp;
613 tcp_stat_t template = {
614 { "tcp_time_wait_syn_success", KSTAT_DATA_UINT64, 0 },
615 { "tcp_clean_death_nondetached", KSTAT_DATA_UINT64, 0 },
616 { "tcp_eager_blowoff_q", KSTAT_DATA_UINT64, 0 },
617 { "tcp_eager_blowoff_q0", KSTAT_DATA_UINT64, 0 },
618 { "tcp_no_listener", KSTAT_DATA_UINT64, 0 },
619 { "tcp_listendrop", KSTAT_DATA_UINT64, 0 },
620 { "tcp_listendropq0", KSTAT_DATA_UINT64, 0 },
621 { "tcp_wsrv_called", KSTAT_DATA_UINT64, 0 },
622 { "tcp_flwctl_on", KSTAT_DATA_UINT64, 0 },
623 { "tcp_timer_fire_early", KSTAT_DATA_UINT64, 0 },
624 { "tcp_timer_fire_miss", KSTAT_DATA_UINT64, 0 },
625 { "tcp_zcopy_on", KSTAT_DATA_UINT64, 0 },
626 { "tcp_zcopy_off", KSTAT_DATA_UINT64, 0 },
627 { "tcp_zcopy_backoff", KSTAT_DATA_UINT64, 0 },
628 { "tcp_fusion_flowctl", KSTAT_DATA_UINT64, 0 },
629 { "tcp_fusion_backenabled", KSTAT_DATA_UINT64, 0 },
630 { "tcp_fusion_urg", KSTAT_DATA_UINT64, 0 },
631 { "tcp_fusion_putnext", KSTAT_DATA_UINT64, 0 },
632 { "tcp_fusion_unfusable", KSTAT_DATA_UINT64, 0 },
633 { "tcp_fusion_aborted", KSTAT_DATA_UINT64, 0 },
634 { "tcp_fusion_unqualified", KSTAT_DATA_UINT64, 0 },
635 { "tcp_fusion_rrw_busy", KSTAT_DATA_UINT64, 0 },
636 { "tcp_fusion_rrw_msgcnt", KSTAT_DATA_UINT64, 0 },
637 { "tcp_fusion_rrw_plugged", KSTAT_DATA_UINT64, 0 },
638 { "tcp_in_ack_unsent_drop", KSTAT_DATA_UINT64, 0 },
639 { "tcp_sock_fallback", KSTAT_DATA_UINT64, 0 },
640 { "tcp_lso_enabled", KSTAT_DATA_UINT64, 0 },
641 { "tcp_lso_disabled", KSTAT_DATA_UINT64, 0 },
642 { "tcp_lso_times", KSTAT_DATA_UINT64, 0 },
643 { "tcp_lso_pkt_out", KSTAT_DATA_UINT64, 0 },
644 { "tcp_listen_cnt_drop", KSTAT_DATA_UINT64, 0 },
645 { "tcp_listen_mem_drop", KSTAT_DATA_UINT64, 0 },
646 { "tcp_zwin_mem_drop", KSTAT_DATA_UINT64, 0 },
647 { "tcp_zwin_ack_syn", KSTAT_DATA_UINT64, 0 },
648 { "tcp_rst_unsent", KSTAT_DATA_UINT64, 0 },
649 { "tcp_reclaim_cnt", KSTAT_DATA_UINT64, 0 },
650 { "tcp_reass_timeout", KSTAT_DATA_UINT64, 0 },
651 #ifdef TCP_DEBUG_COUNTER
652 { "tcp_time_wait", KSTAT_DATA_UINT64, 0 },
653 { "tcp_rput_time_wait", KSTAT_DATA_UINT64, 0 },
654 { "tcp_detach_time_wait", KSTAT_DATA_UINT64, 0 },
655 { "tcp_timeout_calls", KSTAT_DATA_UINT64, 0 },
656 { "tcp_timeout_cached_alloc", KSTAT_DATA_UINT64, 0 },
657 { "tcp_timeout_cancel_reqs", KSTAT_DATA_UINT64, 0 },
658 { "tcp_timeout_canceled", KSTAT_DATA_UINT64, 0 },
659 { "tcp_timermp_freed", KSTAT_DATA_UINT64, 0 },
660 { "tcp_push_timer_cnt", KSTAT_DATA_UINT64, 0 },
661 { "tcp_ack_timer_cnt", KSTAT_DATA_UINT64, 0 },
662 #endif
665 ksp = kstat_create_netstack(TCP_MOD_NAME, stackid, "tcpstat", "net",
666 KSTAT_TYPE_NAMED, sizeof (template) / sizeof (kstat_named_t), 0,
667 stackid);
669 if (ksp == NULL)
670 return (NULL);
672 bcopy(&template, ksp->ks_data, sizeof (template));
673 ksp->ks_private = (void *)(uintptr_t)stackid;
674 ksp->ks_update = tcp_kstat2_update;
677 * If this is an exclusive netstack for a local zone, the global zone
678 * should still be able to read the kstat.
680 if (stackid != GLOBAL_NETSTACKID)
681 kstat_zone_add(ksp, GLOBAL_ZONEID);
683 kstat_install(ksp);
684 return (ksp);
687 void
688 tcp_kstat2_fini(netstackid_t stackid, kstat_t *ksp)
690 if (ksp != NULL) {
691 ASSERT(stackid == (netstackid_t)(uintptr_t)ksp->ks_private);
692 kstat_delete_netstack(ksp, stackid);
697 * Sum up all per CPU tcp_stat_t kstat counters.
699 static int
700 tcp_kstat2_update(kstat_t *kp, int rw)
702 netstackid_t stackid = (netstackid_t)(uintptr_t)kp->ks_private;
703 netstack_t *ns;
704 tcp_stack_t *tcps;
705 tcp_stat_t *stats;
706 int i;
707 int cnt;
709 if (rw == KSTAT_WRITE)
710 return (EACCES);
712 ns = netstack_find_by_stackid(stackid);
713 if (ns == NULL)
714 return (-1);
715 tcps = ns->netstack_tcp;
716 if (tcps == NULL) {
717 netstack_rele(ns);
718 return (-1);
721 stats = (tcp_stat_t *)kp->ks_data;
722 tcp_clr_stats(stats);
725 * tcps_sc_cnt may change in the middle of the loop. It is better
726 * to get its value first.
728 cnt = tcps->tcps_sc_cnt;
729 for (i = 0; i < cnt; i++)
730 tcp_add_stats(&tcps->tcps_sc[i]->tcp_sc_stats, stats);
732 netstack_rele(ns);
733 return (0);
737 * To add stats from one mib2_tcp_t to another. Static fields are not added.
738 * The caller should set them up propertly.
740 static void
741 tcp_add_mib(mib2_tcp_t *from, mib2_tcp_t *to)
743 to->tcpActiveOpens += from->tcpActiveOpens;
744 to->tcpPassiveOpens += from->tcpPassiveOpens;
745 to->tcpAttemptFails += from->tcpAttemptFails;
746 to->tcpEstabResets += from->tcpEstabResets;
747 to->tcpInSegs += from->tcpInSegs;
748 to->tcpOutSegs += from->tcpOutSegs;
749 to->tcpRetransSegs += from->tcpRetransSegs;
750 to->tcpOutRsts += from->tcpOutRsts;
752 to->tcpOutDataSegs += from->tcpOutDataSegs;
753 to->tcpOutDataBytes += from->tcpOutDataBytes;
754 to->tcpRetransBytes += from->tcpRetransBytes;
755 to->tcpOutAck += from->tcpOutAck;
756 to->tcpOutAckDelayed += from->tcpOutAckDelayed;
757 to->tcpOutUrg += from->tcpOutUrg;
758 to->tcpOutWinUpdate += from->tcpOutWinUpdate;
759 to->tcpOutWinProbe += from->tcpOutWinProbe;
760 to->tcpOutControl += from->tcpOutControl;
761 to->tcpOutFastRetrans += from->tcpOutFastRetrans;
763 to->tcpInAckBytes += from->tcpInAckBytes;
764 to->tcpInDupAck += from->tcpInDupAck;
765 to->tcpInAckUnsent += from->tcpInAckUnsent;
766 to->tcpInDataInorderSegs += from->tcpInDataInorderSegs;
767 to->tcpInDataInorderBytes += from->tcpInDataInorderBytes;
768 to->tcpInDataUnorderSegs += from->tcpInDataUnorderSegs;
769 to->tcpInDataUnorderBytes += from->tcpInDataUnorderBytes;
770 to->tcpInDataDupSegs += from->tcpInDataDupSegs;
771 to->tcpInDataDupBytes += from->tcpInDataDupBytes;
772 to->tcpInDataPartDupSegs += from->tcpInDataPartDupSegs;
773 to->tcpInDataPartDupBytes += from->tcpInDataPartDupBytes;
774 to->tcpInDataPastWinSegs += from->tcpInDataPastWinSegs;
775 to->tcpInDataPastWinBytes += from->tcpInDataPastWinBytes;
776 to->tcpInWinProbe += from->tcpInWinProbe;
777 to->tcpInWinUpdate += from->tcpInWinUpdate;
778 to->tcpInClosed += from->tcpInClosed;
780 to->tcpRttNoUpdate += from->tcpRttNoUpdate;
781 to->tcpRttUpdate += from->tcpRttUpdate;
782 to->tcpTimRetrans += from->tcpTimRetrans;
783 to->tcpTimRetransDrop += from->tcpTimRetransDrop;
784 to->tcpTimKeepalive += from->tcpTimKeepalive;
785 to->tcpTimKeepaliveProbe += from->tcpTimKeepaliveProbe;
786 to->tcpTimKeepaliveDrop += from->tcpTimKeepaliveDrop;
787 to->tcpListenDrop += from->tcpListenDrop;
788 to->tcpListenDropQ0 += from->tcpListenDropQ0;
789 to->tcpHalfOpenDrop += from->tcpHalfOpenDrop;
790 to->tcpOutSackRetransSegs += from->tcpOutSackRetransSegs;
791 to->tcpHCInSegs += from->tcpHCInSegs;
792 to->tcpHCOutSegs += from->tcpHCOutSegs;
796 * To sum up all MIB2 stats for a tcp_stack_t from all per CPU stats. The
797 * caller should initialize the target mib2_tcp_t properly as this function
798 * just adds up all the per CPU stats.
800 static void
801 tcp_sum_mib(tcp_stack_t *tcps, mib2_tcp_t *tcp_mib)
803 int i;
804 int cnt;
807 * tcps_sc_cnt may change in the middle of the loop. It is better
808 * to get its value first.
810 cnt = tcps->tcps_sc_cnt;
811 for (i = 0; i < cnt; i++)
812 tcp_add_mib(&tcps->tcps_sc[i]->tcp_sc_mib, tcp_mib);
816 * To set all tcp_stat_t counters to 0.
818 static void
819 tcp_clr_stats(tcp_stat_t *stats)
821 stats->tcp_time_wait_syn_success.value.ui64 = 0;
822 stats->tcp_clean_death_nondetached.value.ui64 = 0;
823 stats->tcp_eager_blowoff_q.value.ui64 = 0;
824 stats->tcp_eager_blowoff_q0.value.ui64 = 0;
825 stats->tcp_no_listener.value.ui64 = 0;
826 stats->tcp_listendrop.value.ui64 = 0;
827 stats->tcp_listendropq0.value.ui64 = 0;
828 stats->tcp_wsrv_called.value.ui64 = 0;
829 stats->tcp_flwctl_on.value.ui64 = 0;
830 stats->tcp_timer_fire_early.value.ui64 = 0;
831 stats->tcp_timer_fire_miss.value.ui64 = 0;
832 stats->tcp_zcopy_on.value.ui64 = 0;
833 stats->tcp_zcopy_off.value.ui64 = 0;
834 stats->tcp_zcopy_backoff.value.ui64 = 0;
835 stats->tcp_fusion_flowctl.value.ui64 = 0;
836 stats->tcp_fusion_backenabled.value.ui64 = 0;
837 stats->tcp_fusion_urg.value.ui64 = 0;
838 stats->tcp_fusion_putnext.value.ui64 = 0;
839 stats->tcp_fusion_unfusable.value.ui64 = 0;
840 stats->tcp_fusion_aborted.value.ui64 = 0;
841 stats->tcp_fusion_unqualified.value.ui64 = 0;
842 stats->tcp_fusion_rrw_busy.value.ui64 = 0;
843 stats->tcp_fusion_rrw_msgcnt.value.ui64 = 0;
844 stats->tcp_fusion_rrw_plugged.value.ui64 = 0;
845 stats->tcp_in_ack_unsent_drop.value.ui64 = 0;
846 stats->tcp_sock_fallback.value.ui64 = 0;
847 stats->tcp_lso_enabled.value.ui64 = 0;
848 stats->tcp_lso_disabled.value.ui64 = 0;
849 stats->tcp_lso_times.value.ui64 = 0;
850 stats->tcp_lso_pkt_out.value.ui64 = 0;
851 stats->tcp_listen_cnt_drop.value.ui64 = 0;
852 stats->tcp_listen_mem_drop.value.ui64 = 0;
853 stats->tcp_zwin_mem_drop.value.ui64 = 0;
854 stats->tcp_zwin_ack_syn.value.ui64 = 0;
855 stats->tcp_rst_unsent.value.ui64 = 0;
856 stats->tcp_reclaim_cnt.value.ui64 = 0;
857 stats->tcp_reass_timeout.value.ui64 = 0;
859 #ifdef TCP_DEBUG_COUNTER
860 stats->tcp_time_wait.value.ui64 = 0;
861 stats->tcp_rput_time_wait.value.ui64 = 0;
862 stats->tcp_detach_time_wait.value.ui64 = 0;
863 stats->tcp_timeout_calls.value.ui64 = 0;
864 stats->tcp_timeout_cached_alloc.value.ui64 = 0;
865 stats->tcp_timeout_cancel_reqs.value.ui64 = 0;
866 stats->tcp_timeout_canceled.value.ui64 = 0;
867 stats->tcp_timermp_freed.value.ui64 = 0;
868 stats->tcp_push_timer_cnt.value.ui64 = 0;
869 stats->tcp_ack_timer_cnt.value.ui64 = 0;
870 #endif
874 * To add counters from the per CPU tcp_stat_counter_t to the stack
875 * tcp_stat_t.
877 static void
878 tcp_add_stats(tcp_stat_counter_t *from, tcp_stat_t *to)
880 to->tcp_time_wait_syn_success.value.ui64 +=
881 from->tcp_time_wait_syn_success;
882 to->tcp_clean_death_nondetached.value.ui64 +=
883 from->tcp_clean_death_nondetached;
884 to->tcp_eager_blowoff_q.value.ui64 +=
885 from->tcp_eager_blowoff_q;
886 to->tcp_eager_blowoff_q0.value.ui64 +=
887 from->tcp_eager_blowoff_q0;
888 to->tcp_no_listener.value.ui64 +=
889 from->tcp_no_listener;
890 to->tcp_listendrop.value.ui64 +=
891 from->tcp_listendrop;
892 to->tcp_listendropq0.value.ui64 +=
893 from->tcp_listendropq0;
894 to->tcp_wsrv_called.value.ui64 +=
895 from->tcp_wsrv_called;
896 to->tcp_flwctl_on.value.ui64 +=
897 from->tcp_flwctl_on;
898 to->tcp_timer_fire_early.value.ui64 +=
899 from->tcp_timer_fire_early;
900 to->tcp_timer_fire_miss.value.ui64 +=
901 from->tcp_timer_fire_miss;
902 to->tcp_zcopy_on.value.ui64 +=
903 from->tcp_zcopy_on;
904 to->tcp_zcopy_off.value.ui64 +=
905 from->tcp_zcopy_off;
906 to->tcp_zcopy_backoff.value.ui64 +=
907 from->tcp_zcopy_backoff;
908 to->tcp_fusion_flowctl.value.ui64 +=
909 from->tcp_fusion_flowctl;
910 to->tcp_fusion_backenabled.value.ui64 +=
911 from->tcp_fusion_backenabled;
912 to->tcp_fusion_urg.value.ui64 +=
913 from->tcp_fusion_urg;
914 to->tcp_fusion_putnext.value.ui64 +=
915 from->tcp_fusion_putnext;
916 to->tcp_fusion_unfusable.value.ui64 +=
917 from->tcp_fusion_unfusable;
918 to->tcp_fusion_aborted.value.ui64 +=
919 from->tcp_fusion_aborted;
920 to->tcp_fusion_unqualified.value.ui64 +=
921 from->tcp_fusion_unqualified;
922 to->tcp_fusion_rrw_busy.value.ui64 +=
923 from->tcp_fusion_rrw_busy;
924 to->tcp_fusion_rrw_msgcnt.value.ui64 +=
925 from->tcp_fusion_rrw_msgcnt;
926 to->tcp_fusion_rrw_plugged.value.ui64 +=
927 from->tcp_fusion_rrw_plugged;
928 to->tcp_in_ack_unsent_drop.value.ui64 +=
929 from->tcp_in_ack_unsent_drop;
930 to->tcp_sock_fallback.value.ui64 +=
931 from->tcp_sock_fallback;
932 to->tcp_lso_enabled.value.ui64 +=
933 from->tcp_lso_enabled;
934 to->tcp_lso_disabled.value.ui64 +=
935 from->tcp_lso_disabled;
936 to->tcp_lso_times.value.ui64 +=
937 from->tcp_lso_times;
938 to->tcp_lso_pkt_out.value.ui64 +=
939 from->tcp_lso_pkt_out;
940 to->tcp_listen_cnt_drop.value.ui64 +=
941 from->tcp_listen_cnt_drop;
942 to->tcp_listen_mem_drop.value.ui64 +=
943 from->tcp_listen_mem_drop;
944 to->tcp_zwin_mem_drop.value.ui64 +=
945 from->tcp_zwin_mem_drop;
946 to->tcp_zwin_ack_syn.value.ui64 +=
947 from->tcp_zwin_ack_syn;
948 to->tcp_rst_unsent.value.ui64 +=
949 from->tcp_rst_unsent;
950 to->tcp_reclaim_cnt.value.ui64 +=
951 from->tcp_reclaim_cnt;
952 to->tcp_reass_timeout.value.ui64 +=
953 from->tcp_reass_timeout;
955 #ifdef TCP_DEBUG_COUNTER
956 to->tcp_time_wait.value.ui64 +=
957 from->tcp_time_wait;
958 to->tcp_rput_time_wait.value.ui64 +=
959 from->tcp_rput_time_wait;
960 to->tcp_detach_time_wait.value.ui64 +=
961 from->tcp_detach_time_wait;
962 to->tcp_timeout_calls.value.ui64 +=
963 from->tcp_timeout_calls;
964 to->tcp_timeout_cached_alloc.value.ui64 +=
965 from->tcp_timeout_cached_alloc;
966 to->tcp_timeout_cancel_reqs.value.ui64 +=
967 from->tcp_timeout_cancel_reqs;
968 to->tcp_timeout_canceled.value.ui64 +=
969 from->tcp_timeout_canceled;
970 to->tcp_timermp_freed.value.ui64 +=
971 from->tcp_timermp_freed;
972 to->tcp_push_timer_cnt.value.ui64 +=
973 from->tcp_push_timer_cnt;
974 to->tcp_ack_timer_cnt.value.ui64 +=
975 from->tcp_ack_timer_cnt;
976 #endif