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]
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>
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
;
51 /* Translate TCP state to MIB2 TCP state. */
53 tcp_snmp_state(tcp_t
*tcp
)
58 switch (tcp
->tcp_state
) {
60 case TCPS_IDLE
: /* RFC1213 doesn't have analogue for IDLE & BOUND */
62 return (MIB2_TCP_closed
);
64 return (MIB2_TCP_listen
);
66 return (MIB2_TCP_synSent
);
68 return (MIB2_TCP_synReceived
);
69 case TCPS_ESTABLISHED
:
70 return (MIB2_TCP_established
);
72 return (MIB2_TCP_closeWait
);
74 return (MIB2_TCP_finWait1
);
76 return (MIB2_TCP_closing
);
78 return (MIB2_TCP_lastAck
);
80 return (MIB2_TCP_finWait2
);
82 return (MIB2_TCP_timeWait
);
89 * Return SNMP stuff in buffer in mpdata.
92 tcp_snmp_get(queue_t
*q
, mblk_t
*mpctl
, boolean_t legacy_req
)
95 mblk_t
*mp_conn_ctl
= NULL
;
97 mblk_t
*mp6_conn_ctl
= NULL
;
98 mblk_t
*mp6_conn_tail
;
100 mib2_tcpConnEntry_t tce
;
101 mib2_tcp6ConnEntry_t tce6
;
108 conn_t
*connp
= Q_TO_CONN(q
);
113 size_t tcp_mib_size
, tce_size
, tce6_size
;
116 * make a copy of the original message
118 mp2ctl
= copymsg(mpctl
);
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
);
131 ipst
= connp
->conn_netstack
->netstack_ip
;
132 tcps
= connp
->conn_netstack
->netstack_tcp
;
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
);
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);
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
];
168 ipcl_get_next_conn(connfp
, connp
, IPCL_TCPCONN
)) != NULL
) {
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
);
177 TCPS_UPDATE_MIB(tcps
, tcpHCOutSegs
, tcp
->tcp_obsegs
);
180 tce6
.tcp6ConnState
= tce
.tcpConnState
=
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
;
196 tce6
.tcp6ConnIfIndex
= connp
->conn_bound_if
;
198 /* Don't want just anybody seeing these... */
200 tce6
.tcp6ConnEntryInfo
.ce_snxt
=
202 tce6
.tcp6ConnEntryInfo
.ce_suna
=
204 tce6
.tcp6ConnEntryInfo
.ce_rnxt
=
206 tce6
.tcp6ConnEntryInfo
.ce_rack
=
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
:
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
;
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... */
260 tce
.tcpConnEntryInfo
.ce_snxt
=
262 tce
.tcpConnEntryInfo
.ce_suna
=
264 tce
.tcpConnEntryInfo
.ce_rnxt
=
266 tce
.tcpConnEntryInfo
.ce_rack
=
270 * Netstat, unfortunately, uses this to
271 * get send/receive queue sizes. How
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
=
290 tce
.tcpConnCreationProcess
=
291 (connp
->conn_cpid
< 0) ?
292 MIB2_UNKNOWN_PROCESS
:
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
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
;
320 (void) snmp_append_data(mpdata
, (char *)&tcp_mib
, tcp_mib_size
);
321 optp
->len
= msgdsize(mpdata
);
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
);
343 /* Return 0 if invalid set request, 1 otherwise, including non-tcp requests */
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
;
354 if (tce
->tcpConnState
!= MIB2_TCP_deleteTCB
)
356 /* TODO: delete entry defined by tce */
367 * TCP Kstats implementation
370 tcp_kstat_init(netstackid_t stackid
)
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
);
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
);
455 tcp_kstat_fini(netstackid_t stackid
, kstat_t
*ksp
)
458 ASSERT(stackid
== (netstackid_t
)(uintptr_t)ksp
->ks_private
);
459 kstat_delete_netstack(ksp
, stackid
);
464 tcp_kstat_update(kstat_t
*kp
, int rw
)
466 tcp_named_kstat_t
*tcpkp
;
471 netstackid_t stackid
= (netstackid_t
)(uintptr_t)kp
->ks_private
;
477 if (rw
== KSTAT_WRITE
)
480 ns
= netstack_find_by_stackid(stackid
);
483 tcps
= ns
->netstack_tcp
;
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
];
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
++;
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
;
572 * kstats related to squeues i.e. not per IP instance
575 tcp_g_kstat_init(tcp_g_stat_t
*tcp_g_statp
)
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
),
593 bcopy(&template, tcp_g_statp
, sizeof (template));
594 ksp
->ks_data
= (void *)tcp_g_statp
;
601 tcp_g_kstat_fini(kstat_t
*ksp
)
609 tcp_kstat2_init(netstackid_t stackid
)
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 },
665 ksp
= kstat_create_netstack(TCP_MOD_NAME
, stackid
, "tcpstat", "net",
666 KSTAT_TYPE_NAMED
, sizeof (template) / sizeof (kstat_named_t
), 0,
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
);
688 tcp_kstat2_fini(netstackid_t stackid
, kstat_t
*ksp
)
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.
700 tcp_kstat2_update(kstat_t
*kp
, int rw
)
702 netstackid_t stackid
= (netstackid_t
)(uintptr_t)kp
->ks_private
;
709 if (rw
== KSTAT_WRITE
)
712 ns
= netstack_find_by_stackid(stackid
);
715 tcps
= ns
->netstack_tcp
;
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
);
737 * To add stats from one mib2_tcp_t to another. Static fields are not added.
738 * The caller should set them up propertly.
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.
801 tcp_sum_mib(tcp_stack_t
*tcps
, mib2_tcp_t
*tcp_mib
)
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.
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;
874 * To add counters from the per CPU tcp_stat_counter_t to the stack
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
+=
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
+=
904 to
->tcp_zcopy_off
.value
.ui64
+=
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
+=
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
+=
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
;