xref: /illumos-gate/usr/src/uts/common/inet/tcp/tcp_stats.c (revision 9b9d39d2a32ff806d2431dbcc50968ef1e6d46b2)
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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright (c) 2011, Joyent Inc. All rights reserved.
25  * Copyright (c) 2015, 2016 by Delphix. All rights reserved.
26  * Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
27  * Copyright 2024 Oxide Computer Company
28  */
29 
30 #include <sys/types.h>
31 #include <sys/tihdr.h>
32 #include <sys/policy.h>
33 #include <sys/tsol/tnet.h>
34 #include <sys/kstat.h>
35 #include <sys/stropts.h>
36 #include <sys/strsubr.h>
37 #include <sys/socket.h>
38 #include <sys/socketvar.h>
39 
40 #include <inet/common.h>
41 #include <inet/ip.h>
42 #include <inet/tcp.h>
43 #include <inet/tcp_impl.h>
44 #include <inet/tcp_stats.h>
45 #include <inet/kstatcom.h>
46 #include <inet/snmpcom.h>
47 
48 static int	tcp_kstat_update(kstat_t *, int);
49 static int	tcp_kstat2_update(kstat_t *, int);
50 static void	tcp_sum_mib(tcp_stack_t *, mib2_tcp_t *);
51 
52 static void	tcp_add_mib(mib2_tcp_t *, mib2_tcp_t *);
53 static void	tcp_add_stats(tcp_stat_counter_t *, tcp_stat_t *);
54 static void	tcp_clr_stats(tcp_stat_t *);
55 
56 tcp_g_stat_t	tcp_g_statistics;
57 kstat_t		*tcp_g_kstat;
58 
59 /* Translate TCP state to MIB2 TCP state. */
60 static int
61 tcp_snmp_state(tcp_t *tcp)
62 {
63 	if (tcp == NULL)
64 		return (0);
65 
66 	switch (tcp->tcp_state) {
67 	case TCPS_CLOSED:
68 	case TCPS_IDLE:	/* RFC1213 doesn't have analogue for IDLE & BOUND */
69 	case TCPS_BOUND:
70 		return (MIB2_TCP_closed);
71 	case TCPS_LISTEN:
72 		return (MIB2_TCP_listen);
73 	case TCPS_SYN_SENT:
74 		return (MIB2_TCP_synSent);
75 	case TCPS_SYN_RCVD:
76 		return (MIB2_TCP_synReceived);
77 	case TCPS_ESTABLISHED:
78 		return (MIB2_TCP_established);
79 	case TCPS_CLOSE_WAIT:
80 		return (MIB2_TCP_closeWait);
81 	case TCPS_FIN_WAIT_1:
82 		return (MIB2_TCP_finWait1);
83 	case TCPS_CLOSING:
84 		return (MIB2_TCP_closing);
85 	case TCPS_LAST_ACK:
86 		return (MIB2_TCP_lastAck);
87 	case TCPS_FIN_WAIT_2:
88 		return (MIB2_TCP_finWait2);
89 	case TCPS_TIME_WAIT:
90 		return (MIB2_TCP_timeWait);
91 	default:
92 		return (0);
93 	}
94 }
95 
96 static void
97 tcp_set_conninfo(tcp_t *tcp, struct tcpConnEntryInfo_s *tcei, boolean_t ispriv)
98 {
99 	/* Don't want just anybody seeing these... */
100 	if (ispriv) {
101 		tcei->ce_snxt = tcp->tcp_snxt;
102 		tcei->ce_suna = tcp->tcp_suna;
103 		tcei->ce_rnxt = tcp->tcp_rnxt;
104 		tcei->ce_rack = tcp->tcp_rack;
105 	} else {
106 		/*
107 		 * Netstat, unfortunately, uses this to get send/receive queue
108 		 * sizes.  How to fix? Why not compute the difference only?
109 		 */
110 		tcei->ce_snxt = tcp->tcp_snxt - tcp->tcp_suna;
111 		tcei->ce_suna = 0;
112 		tcei->ce_rnxt = tcp->tcp_rnxt - tcp->tcp_rack;
113 		tcei->ce_rack = 0;
114 	}
115 
116 	tcei->ce_in_data_inorder_bytes = tcp->tcp_cs.tcp_in_data_inorder_bytes;
117 	tcei->ce_in_data_inorder_segs = tcp->tcp_cs.tcp_in_data_inorder_segs;
118 	tcei->ce_in_data_unorder_bytes = tcp->tcp_cs.tcp_in_data_unorder_bytes;
119 	tcei->ce_in_data_unorder_segs = tcp->tcp_cs.tcp_in_data_unorder_segs;
120 	tcei->ce_in_zwnd_probes = tcp->tcp_cs.tcp_in_zwnd_probes;
121 
122 	tcei->ce_out_data_bytes = tcp->tcp_cs.tcp_out_data_bytes;
123 	tcei->ce_out_data_segs = tcp->tcp_cs.tcp_out_data_segs;
124 	tcei->ce_out_retrans_bytes = tcp->tcp_cs.tcp_out_retrans_bytes;
125 	tcei->ce_out_retrans_segs = tcp->tcp_cs.tcp_out_retrans_segs;
126 	tcei->ce_out_zwnd_probes = tcp->tcp_cs.tcp_out_zwnd_probes;
127 
128 	tcei->ce_unsent = tcp->tcp_unsent;
129 	tcei->ce_swnd = tcp->tcp_swnd;
130 	tcei->ce_cwnd = tcp->tcp_cwnd;
131 	tcei->ce_rwnd = tcp->tcp_rwnd;
132 	tcei->ce_rto =  tcp->tcp_rto;
133 	tcei->ce_mss =  tcp->tcp_mss;
134 	tcei->ce_state = tcp->tcp_state;
135 	tcei->ce_rtt_sa = NSEC2USEC(tcp->tcp_rtt_sa >> 3);
136 	tcei->ce_rtt_sum = NSEC2USEC(tcp->tcp_rtt_sum);
137 	tcei->ce_rtt_cnt = tcp->tcp_rtt_cnt;
138 }
139 
140 /*
141  * Return SNMP stuff in buffer in mpdata.
142  */
143 mblk_t *
144 tcp_snmp_get(queue_t *q, mblk_t *mpctl, boolean_t legacy_req)
145 {
146 	mblk_t			*mpdata;
147 	mblk_t			*mp_conn_ctl = NULL;
148 	mblk_t			*mp_conn_tail;
149 	mblk_t			*mp_attr_ctl = NULL;
150 	mblk_t			*mp_attr_tail;
151 	mblk_t			*mp_info_ctl = NULL;
152 	mblk_t			*mp_info_tail;
153 	mblk_t			*mp6_conn_ctl = NULL;
154 	mblk_t			*mp6_conn_tail;
155 	mblk_t			*mp6_attr_ctl = NULL;
156 	mblk_t			*mp6_attr_tail;
157 	mblk_t			*mp6_info_ctl = NULL;
158 	mblk_t			*mp6_info_tail;
159 	struct opthdr		*optp;
160 	mib2_tcpConnEntry_t	tce;
161 	mib2_tcp6ConnEntry_t	tce6;
162 	mib2_transportMLPEntry_t mlp;
163 	mib2_socketInfoEntry_t	*sie, psie;
164 	connf_t			*connfp;
165 	int			i;
166 	boolean_t		ispriv;
167 	zoneid_t		zoneid;
168 	int			v4_conn_idx;
169 	int			v6_conn_idx;
170 	conn_t			*connp = Q_TO_CONN(q);
171 	tcp_stack_t		*tcps;
172 	ip_stack_t		*ipst;
173 	mblk_t			*mp2ctl;
174 	mib2_tcp_t		tcp_mib;
175 	size_t			tcp_mib_size, tce_size, tce6_size;
176 
177 	/*
178 	 * make a copy of the original message
179 	 */
180 	mp2ctl = copymsg(mpctl);
181 
182 	if (mpctl == NULL ||
183 	    (mpdata = mpctl->b_cont) == NULL ||
184 	    (mp_conn_ctl = copymsg(mpctl)) == NULL ||
185 	    (mp_attr_ctl = copymsg(mpctl)) == NULL ||
186 	    (mp_info_ctl = copymsg(mpctl)) == NULL ||
187 	    (mp6_conn_ctl = copymsg(mpctl)) == NULL ||
188 	    (mp6_attr_ctl = copymsg(mpctl)) == NULL ||
189 	    (mp6_info_ctl = copymsg(mpctl)) == NULL) {
190 		freemsg(mp_conn_ctl);
191 		freemsg(mp_attr_ctl);
192 		freemsg(mp_info_ctl);
193 		freemsg(mp6_conn_ctl);
194 		freemsg(mp6_attr_ctl);
195 		freemsg(mp6_info_ctl);
196 		freemsg(mpctl);
197 		freemsg(mp2ctl);
198 		return (NULL);
199 	}
200 
201 	ipst = connp->conn_netstack->netstack_ip;
202 	tcps = connp->conn_netstack->netstack_tcp;
203 
204 	if (legacy_req) {
205 		tcp_mib_size = LEGACY_MIB_SIZE(&tcp_mib, mib2_tcp_t);
206 		tce_size = LEGACY_MIB_SIZE(&tce, mib2_tcpConnEntry_t);
207 		tce6_size = LEGACY_MIB_SIZE(&tce6, mib2_tcp6ConnEntry_t);
208 	} else {
209 		tcp_mib_size = sizeof (mib2_tcp_t);
210 		tce_size = sizeof (mib2_tcpConnEntry_t);
211 		tce6_size = sizeof (mib2_tcp6ConnEntry_t);
212 	}
213 
214 	bzero(&tcp_mib, sizeof (tcp_mib));
215 
216 	/* build table of connections -- need count in fixed part */
217 	SET_MIB(tcp_mib.tcpRtoAlgorithm, 4);   /* vanj */
218 	SET_MIB(tcp_mib.tcpRtoMin, tcps->tcps_rexmit_interval_min);
219 	SET_MIB(tcp_mib.tcpRtoMax, tcps->tcps_rexmit_interval_max);
220 	SET_MIB(tcp_mib.tcpMaxConn, -1);
221 	SET_MIB(tcp_mib.tcpCurrEstab, 0);
222 
223 	ispriv =
224 	    secpolicy_ip_config((Q_TO_CONN(q))->conn_cred, B_TRUE) == 0;
225 	zoneid = Q_TO_CONN(q)->conn_zoneid;
226 
227 	v4_conn_idx = v6_conn_idx = 0;
228 	mp_conn_tail = mp_attr_tail = mp6_conn_tail = mp6_attr_tail = NULL;
229 	mp_info_tail = mp6_info_tail = NULL;
230 
231 	for (i = 0; i < CONN_G_HASH_SIZE; i++) {
232 		ipst = tcps->tcps_netstack->netstack_ip;
233 
234 		connfp = &ipst->ips_ipcl_globalhash_fanout[i];
235 
236 		connp = NULL;
237 
238 		while ((connp =
239 		    ipcl_get_next_conn(connfp, connp, IPCL_TCPCONN)) != NULL) {
240 			tcp_t *tcp;
241 			boolean_t needattr;
242 
243 			if (connp->conn_zoneid != zoneid)
244 				continue;	/* not in this zone */
245 
246 			tcp = connp->conn_tcp;
247 			tce6.tcp6ConnState = tce.tcpConnState =
248 			    tcp_snmp_state(tcp);
249 			if (tce.tcpConnState == MIB2_TCP_established ||
250 			    tce.tcpConnState == MIB2_TCP_closeWait)
251 				BUMP_MIB(&tcp_mib, tcpCurrEstab);
252 
253 			needattr = B_FALSE;
254 			bzero(&mlp, sizeof (mlp));
255 			if (connp->conn_mlp_type != mlptSingle) {
256 				if (connp->conn_mlp_type == mlptShared ||
257 				    connp->conn_mlp_type == mlptBoth)
258 					mlp.tme_flags |= MIB2_TMEF_SHARED;
259 				if (connp->conn_mlp_type == mlptPrivate ||
260 				    connp->conn_mlp_type == mlptBoth)
261 					mlp.tme_flags |= MIB2_TMEF_PRIVATE;
262 				needattr = B_TRUE;
263 			}
264 			if (connp->conn_anon_mlp) {
265 				mlp.tme_flags |= MIB2_TMEF_ANONMLP;
266 				needattr = B_TRUE;
267 			}
268 			switch (connp->conn_mac_mode) {
269 			case CONN_MAC_DEFAULT:
270 				break;
271 			case CONN_MAC_AWARE:
272 				mlp.tme_flags |= MIB2_TMEF_MACEXEMPT;
273 				needattr = B_TRUE;
274 				break;
275 			case CONN_MAC_IMPLICIT:
276 				mlp.tme_flags |= MIB2_TMEF_MACIMPLICIT;
277 				needattr = B_TRUE;
278 				break;
279 			}
280 			if (connp->conn_ixa->ixa_tsl != NULL) {
281 				ts_label_t *tsl;
282 
283 				tsl = connp->conn_ixa->ixa_tsl;
284 				mlp.tme_flags |= MIB2_TMEF_IS_LABELED;
285 				mlp.tme_doi = label2doi(tsl);
286 				mlp.tme_label = *label2bslabel(tsl);
287 				needattr = B_TRUE;
288 			}
289 
290 			/* Create a message to report on IPv6 entries */
291 			if (connp->conn_ipversion == IPV6_VERSION) {
292 				tce6.tcp6ConnLocalAddress =
293 				    connp->conn_laddr_v6;
294 				tce6.tcp6ConnRemAddress =
295 				    connp->conn_faddr_v6;
296 				tce6.tcp6ConnLocalPort =
297 				    ntohs(connp->conn_lport);
298 				tce6.tcp6ConnRemPort =
299 				    ntohs(connp->conn_fport);
300 				if (connp->conn_ixa->ixa_flags &
301 				    IXAF_SCOPEID_SET) {
302 					tce6.tcp6ConnIfIndex =
303 					    connp->conn_ixa->ixa_scopeid;
304 				} else {
305 					tce6.tcp6ConnIfIndex =
306 					    connp->conn_bound_if;
307 				}
308 
309 				tcp_set_conninfo(tcp, &tce6.tcp6ConnEntryInfo,
310 				    ispriv);
311 
312 				tce6.tcp6ConnCreationProcess =
313 				    (connp->conn_cpid < 0) ?
314 				    MIB2_UNKNOWN_PROCESS : connp->conn_cpid;
315 				tce6.tcp6ConnCreationTime =
316 				    connp->conn_open_time;
317 
318 				(void) snmp_append_data2(mp6_conn_ctl->b_cont,
319 				    &mp6_conn_tail, (char *)&tce6, tce6_size);
320 
321 				if (needattr) {
322 					mlp.tme_connidx = v6_conn_idx;
323 					(void) snmp_append_data2(
324 					    mp6_attr_ctl->b_cont,
325 					    &mp6_attr_tail,
326 					    (char *)&mlp, sizeof (mlp));
327 				}
328 
329 				if ((sie = conn_get_socket_info(connp,
330 				    &psie)) != NULL) {
331 					sie->sie_connidx = v6_conn_idx;
332 					(void) snmp_append_data2(
333 					    mp6_info_ctl->b_cont,
334 					    &mp6_info_tail,
335 					    (char *)sie, sizeof (*sie));
336 				}
337 
338 				v6_conn_idx++;
339 			}
340 
341 			/*
342 			 * Create an IPv4 table entry for IPv4 entries and also
343 			 * for IPv6 entries which are bound to in6addr_any
344 			 * but don't have IPV6_V6ONLY set.
345 			 * (i.e. anything an IPv4 peer could connect to)
346 			 */
347 			if (connp->conn_ipversion == IPV4_VERSION ||
348 			    (tcp->tcp_state <= TCPS_LISTEN &&
349 			    !connp->conn_ipv6_v6only &&
350 			    IN6_IS_ADDR_UNSPECIFIED(&connp->conn_laddr_v6))) {
351 				if (connp->conn_ipversion == IPV6_VERSION) {
352 					tce.tcpConnRemAddress = INADDR_ANY;
353 					tce.tcpConnLocalAddress = INADDR_ANY;
354 				} else {
355 					tce.tcpConnRemAddress =
356 					    connp->conn_faddr_v4;
357 					tce.tcpConnLocalAddress =
358 					    connp->conn_laddr_v4;
359 				}
360 				tce.tcpConnLocalPort = ntohs(connp->conn_lport);
361 				tce.tcpConnRemPort = ntohs(connp->conn_fport);
362 
363 				tcp_set_conninfo(tcp, &tce.tcpConnEntryInfo,
364 				    ispriv);
365 
366 				tce.tcpConnCreationProcess =
367 				    (connp->conn_cpid < 0) ?
368 				    MIB2_UNKNOWN_PROCESS :
369 				    connp->conn_cpid;
370 				tce.tcpConnCreationTime = connp->conn_open_time;
371 
372 				(void) snmp_append_data2(mp_conn_ctl->b_cont,
373 				    &mp_conn_tail, (char *)&tce, tce_size);
374 
375 				if (needattr) {
376 					mlp.tme_connidx = v4_conn_idx;
377 					(void) snmp_append_data2(
378 					    mp_attr_ctl->b_cont,
379 					    &mp_attr_tail, (char *)&mlp,
380 					    sizeof (mlp));
381 				}
382 
383 				if ((sie = conn_get_socket_info(connp, &psie))
384 				    != NULL) {
385 					sie->sie_connidx = v4_conn_idx;
386 					if (connp->conn_ipversion ==
387 					    IPV6_VERSION)
388 						sie->sie_flags |=
389 						    MIB2_SOCKINFO_IPV6;
390 					(void) snmp_append_data2(
391 					    mp_info_ctl->b_cont, &mp_info_tail,
392 					    (char *)sie, sizeof (*sie));
393 				}
394 
395 				v4_conn_idx++;
396 			}
397 		}
398 	}
399 
400 	tcp_sum_mib(tcps, &tcp_mib);
401 
402 	/* Fixed length structure for IPv4 and IPv6 counters */
403 	SET_MIB(tcp_mib.tcpConnTableSize, tce_size);
404 	SET_MIB(tcp_mib.tcp6ConnTableSize, tce6_size);
405 
406 	/*
407 	 * Synchronize 32- and 64-bit counters.  Note that tcpInSegs and
408 	 * tcpOutSegs are not updated anywhere in TCP.  The new 64 bits
409 	 * counters are used.  Hence the old counters' values in tcp_sc_mib
410 	 * are always 0.
411 	 */
412 	SYNC32_MIB(&tcp_mib, tcpInSegs, tcpHCInSegs);
413 	SYNC32_MIB(&tcp_mib, tcpOutSegs, tcpHCOutSegs);
414 
415 	optp = (struct opthdr *)&mpctl->b_rptr[sizeof (struct T_optmgmt_ack)];
416 	optp->level = MIB2_TCP;
417 	optp->name = 0;
418 	(void) snmp_append_data(mpdata, (char *)&tcp_mib, tcp_mib_size);
419 	optp->len = msgdsize(mpdata);
420 	qreply(q, mpctl);
421 
422 	/* table of connections... */
423 	optp = (struct opthdr *)&mp_conn_ctl->b_rptr[
424 	    sizeof (struct T_optmgmt_ack)];
425 	optp->level = MIB2_TCP;
426 	optp->name = MIB2_TCP_CONN;
427 	optp->len = msgdsize(mp_conn_ctl->b_cont);
428 	qreply(q, mp_conn_ctl);
429 
430 	/* table of MLP attributes... */
431 	optp = (struct opthdr *)&mp_attr_ctl->b_rptr[
432 	    sizeof (struct T_optmgmt_ack)];
433 	optp->level = MIB2_TCP;
434 	optp->name = EXPER_XPORT_MLP;
435 	optp->len = msgdsize(mp_attr_ctl->b_cont);
436 	if (optp->len == 0)
437 		freemsg(mp_attr_ctl);
438 	else
439 		qreply(q, mp_attr_ctl);
440 
441 	/* table of socket info... */
442 	optp = (struct opthdr *)&mp_info_ctl->b_rptr[
443 	    sizeof (struct T_optmgmt_ack)];
444 	optp->level = MIB2_TCP;
445 	optp->name = EXPER_SOCK_INFO;
446 	optp->len = msgdsize(mp_info_ctl->b_cont);
447 	if (optp->len == 0)
448 		freemsg(mp_info_ctl);
449 	else
450 		qreply(q, mp_info_ctl);
451 
452 	/* table of IPv6 connections... */
453 	optp = (struct opthdr *)&mp6_conn_ctl->b_rptr[
454 	    sizeof (struct T_optmgmt_ack)];
455 	optp->level = MIB2_TCP6;
456 	optp->name = MIB2_TCP6_CONN;
457 	optp->len = msgdsize(mp6_conn_ctl->b_cont);
458 	qreply(q, mp6_conn_ctl);
459 
460 	/* table of IPv6 MLP attributes... */
461 	optp = (struct opthdr *)&mp6_attr_ctl->b_rptr[
462 	    sizeof (struct T_optmgmt_ack)];
463 	optp->level = MIB2_TCP6;
464 	optp->name = EXPER_XPORT_MLP;
465 	optp->len = msgdsize(mp6_attr_ctl->b_cont);
466 	if (optp->len == 0)
467 		freemsg(mp6_attr_ctl);
468 	else
469 		qreply(q, mp6_attr_ctl);
470 
471 	/* table of IPv6 socket info.. */
472 	optp = (struct opthdr *)&mp6_info_ctl->b_rptr[
473 	    sizeof (struct T_optmgmt_ack)];
474 	optp->level = MIB2_TCP6;
475 	optp->name = EXPER_SOCK_INFO;
476 	optp->len = msgdsize(mp6_info_ctl->b_cont);
477 	if (optp->len == 0)
478 		freemsg(mp6_info_ctl);
479 	else
480 		qreply(q, mp6_info_ctl);
481 
482 	return (mp2ctl);
483 }
484 
485 /* Return 0 if invalid set request, 1 otherwise, including non-tcp requests  */
486 /* ARGSUSED */
487 int
488 tcp_snmp_set(queue_t *q, int level, int name, uchar_t *ptr, int len)
489 {
490 	mib2_tcpConnEntry_t	*tce = (mib2_tcpConnEntry_t *)ptr;
491 
492 	switch (level) {
493 	case MIB2_TCP:
494 		switch (name) {
495 		case 13:
496 			if (tce->tcpConnState != MIB2_TCP_deleteTCB)
497 				return (0);
498 			/* TODO: delete entry defined by tce */
499 			return (1);
500 		default:
501 			return (0);
502 		}
503 	default:
504 		return (1);
505 	}
506 }
507 
508 /*
509  * TCP Kstats implementation
510  */
511 void *
512 tcp_kstat_init(netstackid_t stackid)
513 {
514 	kstat_t	*ksp;
515 
516 	tcp_named_kstat_t template = {
517 		{ "rtoAlgorithm",	KSTAT_DATA_INT32, 0 },
518 		{ "rtoMin",		KSTAT_DATA_INT32, 0 },
519 		{ "rtoMax",		KSTAT_DATA_INT32, 0 },
520 		{ "maxConn",		KSTAT_DATA_INT32, 0 },
521 		{ "activeOpens",	KSTAT_DATA_UINT32, 0 },
522 		{ "passiveOpens",	KSTAT_DATA_UINT32, 0 },
523 		{ "attemptFails",	KSTAT_DATA_UINT32, 0 },
524 		{ "estabResets",	KSTAT_DATA_UINT32, 0 },
525 		{ "currEstab",		KSTAT_DATA_UINT32, 0 },
526 		{ "inSegs",		KSTAT_DATA_UINT64, 0 },
527 		{ "outSegs",		KSTAT_DATA_UINT64, 0 },
528 		{ "retransSegs",	KSTAT_DATA_UINT32, 0 },
529 		{ "connTableSize",	KSTAT_DATA_INT32, 0 },
530 		{ "outRsts",		KSTAT_DATA_UINT32, 0 },
531 		{ "outDataSegs",	KSTAT_DATA_UINT32, 0 },
532 		{ "outDataBytes",	KSTAT_DATA_UINT32, 0 },
533 		{ "retransBytes",	KSTAT_DATA_UINT32, 0 },
534 		{ "outAck",		KSTAT_DATA_UINT32, 0 },
535 		{ "outAckDelayed",	KSTAT_DATA_UINT32, 0 },
536 		{ "outUrg",		KSTAT_DATA_UINT32, 0 },
537 		{ "outWinUpdate",	KSTAT_DATA_UINT32, 0 },
538 		{ "outWinProbe",	KSTAT_DATA_UINT32, 0 },
539 		{ "outControl",		KSTAT_DATA_UINT32, 0 },
540 		{ "outFastRetrans",	KSTAT_DATA_UINT32, 0 },
541 		{ "inAckSegs",		KSTAT_DATA_UINT32, 0 },
542 		{ "inAckBytes",		KSTAT_DATA_UINT32, 0 },
543 		{ "inDupAck",		KSTAT_DATA_UINT32, 0 },
544 		{ "inAckUnsent",	KSTAT_DATA_UINT32, 0 },
545 		{ "inDataInorderSegs",	KSTAT_DATA_UINT32, 0 },
546 		{ "inDataInorderBytes",	KSTAT_DATA_UINT32, 0 },
547 		{ "inDataUnorderSegs",	KSTAT_DATA_UINT32, 0 },
548 		{ "inDataUnorderBytes",	KSTAT_DATA_UINT32, 0 },
549 		{ "inDataDupSegs",	KSTAT_DATA_UINT32, 0 },
550 		{ "inDataDupBytes",	KSTAT_DATA_UINT32, 0 },
551 		{ "inDataPartDupSegs",	KSTAT_DATA_UINT32, 0 },
552 		{ "inDataPartDupBytes",	KSTAT_DATA_UINT32, 0 },
553 		{ "inDataPastWinSegs",	KSTAT_DATA_UINT32, 0 },
554 		{ "inDataPastWinBytes",	KSTAT_DATA_UINT32, 0 },
555 		{ "inWinProbe",		KSTAT_DATA_UINT32, 0 },
556 		{ "inWinUpdate",	KSTAT_DATA_UINT32, 0 },
557 		{ "inClosed",		KSTAT_DATA_UINT32, 0 },
558 		{ "rttUpdate",		KSTAT_DATA_UINT32, 0 },
559 		{ "rttNoUpdate",	KSTAT_DATA_UINT32, 0 },
560 		{ "timRetrans",		KSTAT_DATA_UINT32, 0 },
561 		{ "timRetransDrop",	KSTAT_DATA_UINT32, 0 },
562 		{ "timKeepalive",	KSTAT_DATA_UINT32, 0 },
563 		{ "timKeepaliveProbe",	KSTAT_DATA_UINT32, 0 },
564 		{ "timKeepaliveDrop",	KSTAT_DATA_UINT32, 0 },
565 		{ "listenDrop",		KSTAT_DATA_UINT32, 0 },
566 		{ "listenDropQ0",	KSTAT_DATA_UINT32, 0 },
567 		{ "halfOpenDrop",	KSTAT_DATA_UINT32, 0 },
568 		{ "outSackRetransSegs",	KSTAT_DATA_UINT32, 0 },
569 		{ "connTableSize6",	KSTAT_DATA_INT32, 0 }
570 	};
571 
572 	ksp = kstat_create_netstack(TCP_MOD_NAME, stackid, TCP_MOD_NAME, "mib2",
573 	    KSTAT_TYPE_NAMED, NUM_OF_FIELDS(tcp_named_kstat_t), 0, stackid);
574 
575 	if (ksp == NULL)
576 		return (NULL);
577 
578 	template.rtoAlgorithm.value.ui32 = 4;
579 	template.maxConn.value.i32 = -1;
580 
581 	bcopy(&template, ksp->ks_data, sizeof (template));
582 	ksp->ks_update = tcp_kstat_update;
583 	ksp->ks_private = (void *)(uintptr_t)stackid;
584 
585 	/*
586 	 * If this is an exclusive netstack for a local zone, the global zone
587 	 * should still be able to read the kstat.
588 	 */
589 	if (stackid != GLOBAL_NETSTACKID)
590 		kstat_zone_add(ksp, GLOBAL_ZONEID);
591 
592 	kstat_install(ksp);
593 	return (ksp);
594 }
595 
596 void
597 tcp_kstat_fini(netstackid_t stackid, kstat_t *ksp)
598 {
599 	if (ksp != NULL) {
600 		ASSERT(stackid == (netstackid_t)(uintptr_t)ksp->ks_private);
601 		kstat_delete_netstack(ksp, stackid);
602 	}
603 }
604 
605 static int
606 tcp_kstat_update(kstat_t *kp, int rw)
607 {
608 	tcp_named_kstat_t *tcpkp;
609 	tcp_t		*tcp;
610 	connf_t		*connfp;
611 	conn_t		*connp;
612 	int		i;
613 	netstackid_t	stackid = (netstackid_t)(uintptr_t)kp->ks_private;
614 	netstack_t	*ns;
615 	tcp_stack_t	*tcps;
616 	ip_stack_t	*ipst;
617 	mib2_tcp_t	tcp_mib;
618 
619 	if (rw == KSTAT_WRITE)
620 		return (EACCES);
621 
622 	ns = netstack_find_by_stackid(stackid);
623 	if (ns == NULL)
624 		return (-1);
625 	tcps = ns->netstack_tcp;
626 	if (tcps == NULL) {
627 		netstack_rele(ns);
628 		return (-1);
629 	}
630 
631 	tcpkp = (tcp_named_kstat_t *)kp->ks_data;
632 
633 	tcpkp->currEstab.value.ui32 = 0;
634 	tcpkp->rtoMin.value.ui32 = tcps->tcps_rexmit_interval_min;
635 	tcpkp->rtoMax.value.ui32 = tcps->tcps_rexmit_interval_max;
636 
637 	ipst = ns->netstack_ip;
638 
639 	for (i = 0; i < CONN_G_HASH_SIZE; i++) {
640 		connfp = &ipst->ips_ipcl_globalhash_fanout[i];
641 		connp = NULL;
642 		while ((connp =
643 		    ipcl_get_next_conn(connfp, connp, IPCL_TCPCONN)) != NULL) {
644 			tcp = connp->conn_tcp;
645 			switch (tcp_snmp_state(tcp)) {
646 			case MIB2_TCP_established:
647 			case MIB2_TCP_closeWait:
648 				tcpkp->currEstab.value.ui32++;
649 				break;
650 			}
651 		}
652 	}
653 	bzero(&tcp_mib, sizeof (tcp_mib));
654 	tcp_sum_mib(tcps, &tcp_mib);
655 
656 	/* Fixed length structure for IPv4 and IPv6 counters */
657 	SET_MIB(tcp_mib.tcpConnTableSize, sizeof (mib2_tcpConnEntry_t));
658 	SET_MIB(tcp_mib.tcp6ConnTableSize, sizeof (mib2_tcp6ConnEntry_t));
659 
660 	tcpkp->activeOpens.value.ui32 = tcp_mib.tcpActiveOpens;
661 	tcpkp->passiveOpens.value.ui32 = tcp_mib.tcpPassiveOpens;
662 	tcpkp->attemptFails.value.ui32 = tcp_mib.tcpAttemptFails;
663 	tcpkp->estabResets.value.ui32 = tcp_mib.tcpEstabResets;
664 	tcpkp->inSegs.value.ui64 = tcp_mib.tcpHCInSegs;
665 	tcpkp->outSegs.value.ui64 = tcp_mib.tcpHCOutSegs;
666 	tcpkp->retransSegs.value.ui32 =	tcp_mib.tcpRetransSegs;
667 	tcpkp->connTableSize.value.i32 = tcp_mib.tcpConnTableSize;
668 	tcpkp->outRsts.value.ui32 = tcp_mib.tcpOutRsts;
669 	tcpkp->outDataSegs.value.ui32 = tcp_mib.tcpOutDataSegs;
670 	tcpkp->outDataBytes.value.ui32 = tcp_mib.tcpOutDataBytes;
671 	tcpkp->retransBytes.value.ui32 = tcp_mib.tcpRetransBytes;
672 	tcpkp->outAck.value.ui32 = tcp_mib.tcpOutAck;
673 	tcpkp->outAckDelayed.value.ui32 = tcp_mib.tcpOutAckDelayed;
674 	tcpkp->outUrg.value.ui32 = tcp_mib.tcpOutUrg;
675 	tcpkp->outWinUpdate.value.ui32 = tcp_mib.tcpOutWinUpdate;
676 	tcpkp->outWinProbe.value.ui32 = tcp_mib.tcpOutWinProbe;
677 	tcpkp->outControl.value.ui32 = tcp_mib.tcpOutControl;
678 	tcpkp->outFastRetrans.value.ui32 = tcp_mib.tcpOutFastRetrans;
679 	tcpkp->inAckSegs.value.ui32 = tcp_mib.tcpInAckSegs;
680 	tcpkp->inAckBytes.value.ui32 = tcp_mib.tcpInAckBytes;
681 	tcpkp->inDupAck.value.ui32 = tcp_mib.tcpInDupAck;
682 	tcpkp->inAckUnsent.value.ui32 = tcp_mib.tcpInAckUnsent;
683 	tcpkp->inDataInorderSegs.value.ui32 = tcp_mib.tcpInDataInorderSegs;
684 	tcpkp->inDataInorderBytes.value.ui32 = tcp_mib.tcpInDataInorderBytes;
685 	tcpkp->inDataUnorderSegs.value.ui32 = tcp_mib.tcpInDataUnorderSegs;
686 	tcpkp->inDataUnorderBytes.value.ui32 = tcp_mib.tcpInDataUnorderBytes;
687 	tcpkp->inDataDupSegs.value.ui32 = tcp_mib.tcpInDataDupSegs;
688 	tcpkp->inDataDupBytes.value.ui32 = tcp_mib.tcpInDataDupBytes;
689 	tcpkp->inDataPartDupSegs.value.ui32 = tcp_mib.tcpInDataPartDupSegs;
690 	tcpkp->inDataPartDupBytes.value.ui32 = tcp_mib.tcpInDataPartDupBytes;
691 	tcpkp->inDataPastWinSegs.value.ui32 = tcp_mib.tcpInDataPastWinSegs;
692 	tcpkp->inDataPastWinBytes.value.ui32 = tcp_mib.tcpInDataPastWinBytes;
693 	tcpkp->inWinProbe.value.ui32 = tcp_mib.tcpInWinProbe;
694 	tcpkp->inWinUpdate.value.ui32 = tcp_mib.tcpInWinUpdate;
695 	tcpkp->inClosed.value.ui32 = tcp_mib.tcpInClosed;
696 	tcpkp->rttNoUpdate.value.ui32 = tcp_mib.tcpRttNoUpdate;
697 	tcpkp->rttUpdate.value.ui32 = tcp_mib.tcpRttUpdate;
698 	tcpkp->timRetrans.value.ui32 = tcp_mib.tcpTimRetrans;
699 	tcpkp->timRetransDrop.value.ui32 = tcp_mib.tcpTimRetransDrop;
700 	tcpkp->timKeepalive.value.ui32 = tcp_mib.tcpTimKeepalive;
701 	tcpkp->timKeepaliveProbe.value.ui32 = tcp_mib.tcpTimKeepaliveProbe;
702 	tcpkp->timKeepaliveDrop.value.ui32 = tcp_mib.tcpTimKeepaliveDrop;
703 	tcpkp->listenDrop.value.ui32 = tcp_mib.tcpListenDrop;
704 	tcpkp->listenDropQ0.value.ui32 = tcp_mib.tcpListenDropQ0;
705 	tcpkp->halfOpenDrop.value.ui32 = tcp_mib.tcpHalfOpenDrop;
706 	tcpkp->outSackRetransSegs.value.ui32 = tcp_mib.tcpOutSackRetransSegs;
707 	tcpkp->connTableSize6.value.i32 = tcp_mib.tcp6ConnTableSize;
708 
709 	netstack_rele(ns);
710 	return (0);
711 }
712 
713 /*
714  * kstats related to squeues i.e. not per IP instance
715  */
716 void *
717 tcp_g_kstat_init(tcp_g_stat_t *tcp_g_statp)
718 {
719 	kstat_t *ksp;
720 
721 	tcp_g_stat_t template = {
722 		{ "tcp_timermp_alloced",	KSTAT_DATA_UINT64 },
723 		{ "tcp_timermp_allocfail",	KSTAT_DATA_UINT64 },
724 		{ "tcp_timermp_allocdblfail",	KSTAT_DATA_UINT64 },
725 		{ "tcp_freelist_cleanup",	KSTAT_DATA_UINT64 },
726 	};
727 
728 	ksp = kstat_create(TCP_MOD_NAME, 0, "tcpstat_g", "net",
729 	    KSTAT_TYPE_NAMED, sizeof (template) / sizeof (kstat_named_t),
730 	    KSTAT_FLAG_VIRTUAL);
731 
732 	if (ksp == NULL)
733 		return (NULL);
734 
735 	bcopy(&template, tcp_g_statp, sizeof (template));
736 	ksp->ks_data = (void *)tcp_g_statp;
737 
738 	kstat_install(ksp);
739 	return (ksp);
740 }
741 
742 void
743 tcp_g_kstat_fini(kstat_t *ksp)
744 {
745 	if (ksp != NULL) {
746 		kstat_delete(ksp);
747 	}
748 }
749 
750 void *
751 tcp_kstat2_init(netstackid_t stackid)
752 {
753 	kstat_t *ksp;
754 
755 	tcp_stat_t template = {
756 		{ "tcp_time_wait_syn_success",	KSTAT_DATA_UINT64, 0 },
757 		{ "tcp_clean_death_nondetached",	KSTAT_DATA_UINT64, 0 },
758 		{ "tcp_eager_blowoff_q",	KSTAT_DATA_UINT64, 0 },
759 		{ "tcp_eager_blowoff_q0",	KSTAT_DATA_UINT64, 0 },
760 		{ "tcp_no_listener",		KSTAT_DATA_UINT64, 0 },
761 		{ "tcp_listendrop",		KSTAT_DATA_UINT64, 0 },
762 		{ "tcp_listendropq0",		KSTAT_DATA_UINT64, 0 },
763 		{ "tcp_wsrv_called",		KSTAT_DATA_UINT64, 0 },
764 		{ "tcp_flwctl_on",		KSTAT_DATA_UINT64, 0 },
765 		{ "tcp_timer_fire_early",	KSTAT_DATA_UINT64, 0 },
766 		{ "tcp_timer_fire_miss",	KSTAT_DATA_UINT64, 0 },
767 		{ "tcp_zcopy_on",		KSTAT_DATA_UINT64, 0 },
768 		{ "tcp_zcopy_off",		KSTAT_DATA_UINT64, 0 },
769 		{ "tcp_zcopy_backoff",		KSTAT_DATA_UINT64, 0 },
770 		{ "tcp_fusion_flowctl",		KSTAT_DATA_UINT64, 0 },
771 		{ "tcp_fusion_backenabled",	KSTAT_DATA_UINT64, 0 },
772 		{ "tcp_fusion_urg",		KSTAT_DATA_UINT64, 0 },
773 		{ "tcp_fusion_putnext",		KSTAT_DATA_UINT64, 0 },
774 		{ "tcp_fusion_unfusable",	KSTAT_DATA_UINT64, 0 },
775 		{ "tcp_fusion_aborted",		KSTAT_DATA_UINT64, 0 },
776 		{ "tcp_fusion_unqualified",	KSTAT_DATA_UINT64, 0 },
777 		{ "tcp_fusion_rrw_busy",	KSTAT_DATA_UINT64, 0 },
778 		{ "tcp_fusion_rrw_msgcnt",	KSTAT_DATA_UINT64, 0 },
779 		{ "tcp_fusion_rrw_plugged",	KSTAT_DATA_UINT64, 0 },
780 		{ "tcp_in_ack_unsent_drop",	KSTAT_DATA_UINT64, 0 },
781 		{ "tcp_sock_fallback",		KSTAT_DATA_UINT64, 0 },
782 		{ "tcp_lso_enabled",		KSTAT_DATA_UINT64, 0 },
783 		{ "tcp_lso_disabled",		KSTAT_DATA_UINT64, 0 },
784 		{ "tcp_lso_times",		KSTAT_DATA_UINT64, 0 },
785 		{ "tcp_lso_pkt_out",		KSTAT_DATA_UINT64, 0 },
786 		{ "tcp_listen_cnt_drop",	KSTAT_DATA_UINT64, 0 },
787 		{ "tcp_listen_mem_drop",	KSTAT_DATA_UINT64, 0 },
788 		{ "tcp_zwin_mem_drop",		KSTAT_DATA_UINT64, 0 },
789 		{ "tcp_zwin_ack_syn",		KSTAT_DATA_UINT64, 0 },
790 		{ "tcp_rst_unsent",		KSTAT_DATA_UINT64, 0 },
791 		{ "tcp_reclaim_cnt",		KSTAT_DATA_UINT64, 0 },
792 		{ "tcp_reass_timeout",		KSTAT_DATA_UINT64, 0 },
793 		{ "tcp_sig_no_option",		KSTAT_DATA_UINT64, 0 },
794 		{ "tcp_sig_no_space",		KSTAT_DATA_UINT64, 0 },
795 		{ "tcp_sig_match_failed",	KSTAT_DATA_UINT64, 0 },
796 		{ "tcp_sig_verify_failed",	KSTAT_DATA_UINT64, 0 },
797 		{ "tcp_sig_degraded",		KSTAT_DATA_UINT64, 0 },
798 #ifdef TCP_DEBUG_COUNTER
799 		{ "tcp_time_wait",		KSTAT_DATA_UINT64, 0 },
800 		{ "tcp_rput_time_wait",		KSTAT_DATA_UINT64, 0 },
801 		{ "tcp_detach_time_wait",	KSTAT_DATA_UINT64, 0 },
802 		{ "tcp_timeout_calls",		KSTAT_DATA_UINT64, 0 },
803 		{ "tcp_timeout_cached_alloc",	KSTAT_DATA_UINT64, 0 },
804 		{ "tcp_timeout_cancel_reqs",	KSTAT_DATA_UINT64, 0 },
805 		{ "tcp_timeout_canceled",	KSTAT_DATA_UINT64, 0 },
806 		{ "tcp_timermp_freed",		KSTAT_DATA_UINT64, 0 },
807 		{ "tcp_push_timer_cnt",		KSTAT_DATA_UINT64, 0 },
808 		{ "tcp_ack_timer_cnt",		KSTAT_DATA_UINT64, 0 },
809 #endif
810 	};
811 
812 	ksp = kstat_create_netstack(TCP_MOD_NAME, stackid, "tcpstat", "net",
813 	    KSTAT_TYPE_NAMED, sizeof (template) / sizeof (kstat_named_t), 0,
814 	    stackid);
815 
816 	if (ksp == NULL)
817 		return (NULL);
818 
819 	bcopy(&template, ksp->ks_data, sizeof (template));
820 	ksp->ks_private = (void *)(uintptr_t)stackid;
821 	ksp->ks_update = tcp_kstat2_update;
822 
823 	/*
824 	 * If this is an exclusive netstack for a local zone, the global zone
825 	 * should still be able to read the kstat.
826 	 */
827 	if (stackid != GLOBAL_NETSTACKID)
828 		kstat_zone_add(ksp, GLOBAL_ZONEID);
829 
830 	kstat_install(ksp);
831 	return (ksp);
832 }
833 
834 void
835 tcp_kstat2_fini(netstackid_t stackid, kstat_t *ksp)
836 {
837 	if (ksp != NULL) {
838 		ASSERT(stackid == (netstackid_t)(uintptr_t)ksp->ks_private);
839 		kstat_delete_netstack(ksp, stackid);
840 	}
841 }
842 
843 /*
844  * Sum up all per CPU tcp_stat_t kstat counters.
845  */
846 static int
847 tcp_kstat2_update(kstat_t *kp, int rw)
848 {
849 	netstackid_t	stackid = (netstackid_t)(uintptr_t)kp->ks_private;
850 	netstack_t	*ns;
851 	tcp_stack_t	*tcps;
852 	tcp_stat_t	*stats;
853 	int		i;
854 	int		cnt;
855 
856 	if (rw == KSTAT_WRITE)
857 		return (EACCES);
858 
859 	ns = netstack_find_by_stackid(stackid);
860 	if (ns == NULL)
861 		return (-1);
862 	tcps = ns->netstack_tcp;
863 	if (tcps == NULL) {
864 		netstack_rele(ns);
865 		return (-1);
866 	}
867 
868 	stats = (tcp_stat_t *)kp->ks_data;
869 	tcp_clr_stats(stats);
870 
871 	/*
872 	 * tcps_sc_cnt may change in the middle of the loop.  It is better
873 	 * to get its value first.
874 	 */
875 	cnt = tcps->tcps_sc_cnt;
876 	for (i = 0; i < cnt; i++)
877 		tcp_add_stats(&tcps->tcps_sc[i]->tcp_sc_stats, stats);
878 
879 	netstack_rele(ns);
880 	return (0);
881 }
882 
883 /*
884  * To add stats from one mib2_tcp_t to another.  Static fields are not added.
885  * The caller should set them up propertly.
886  */
887 static void
888 tcp_add_mib(mib2_tcp_t *from, mib2_tcp_t *to)
889 {
890 	to->tcpActiveOpens += from->tcpActiveOpens;
891 	to->tcpPassiveOpens += from->tcpPassiveOpens;
892 	to->tcpAttemptFails += from->tcpAttemptFails;
893 	to->tcpEstabResets += from->tcpEstabResets;
894 	to->tcpInSegs += from->tcpInSegs;
895 	to->tcpOutSegs += from->tcpOutSegs;
896 	to->tcpRetransSegs += from->tcpRetransSegs;
897 	to->tcpOutRsts += from->tcpOutRsts;
898 
899 	to->tcpOutDataSegs += from->tcpOutDataSegs;
900 	to->tcpOutDataBytes += from->tcpOutDataBytes;
901 	to->tcpRetransBytes += from->tcpRetransBytes;
902 	to->tcpOutAck += from->tcpOutAck;
903 	to->tcpOutAckDelayed += from->tcpOutAckDelayed;
904 	to->tcpOutUrg += from->tcpOutUrg;
905 	to->tcpOutWinUpdate += from->tcpOutWinUpdate;
906 	to->tcpOutWinProbe += from->tcpOutWinProbe;
907 	to->tcpOutControl += from->tcpOutControl;
908 	to->tcpOutFastRetrans += from->tcpOutFastRetrans;
909 
910 	to->tcpInAckBytes += from->tcpInAckBytes;
911 	to->tcpInDupAck += from->tcpInDupAck;
912 	to->tcpInAckUnsent += from->tcpInAckUnsent;
913 	to->tcpInDataInorderSegs += from->tcpInDataInorderSegs;
914 	to->tcpInDataInorderBytes += from->tcpInDataInorderBytes;
915 	to->tcpInDataUnorderSegs += from->tcpInDataUnorderSegs;
916 	to->tcpInDataUnorderBytes += from->tcpInDataUnorderBytes;
917 	to->tcpInDataDupSegs += from->tcpInDataDupSegs;
918 	to->tcpInDataDupBytes += from->tcpInDataDupBytes;
919 	to->tcpInDataPartDupSegs += from->tcpInDataPartDupSegs;
920 	to->tcpInDataPartDupBytes += from->tcpInDataPartDupBytes;
921 	to->tcpInDataPastWinSegs += from->tcpInDataPastWinSegs;
922 	to->tcpInDataPastWinBytes += from->tcpInDataPastWinBytes;
923 	to->tcpInWinProbe += from->tcpInWinProbe;
924 	to->tcpInWinUpdate += from->tcpInWinUpdate;
925 	to->tcpInClosed += from->tcpInClosed;
926 
927 	to->tcpRttNoUpdate += from->tcpRttNoUpdate;
928 	to->tcpRttUpdate += from->tcpRttUpdate;
929 	to->tcpTimRetrans += from->tcpTimRetrans;
930 	to->tcpTimRetransDrop += from->tcpTimRetransDrop;
931 	to->tcpTimKeepalive += from->tcpTimKeepalive;
932 	to->tcpTimKeepaliveProbe += from->tcpTimKeepaliveProbe;
933 	to->tcpTimKeepaliveDrop += from->tcpTimKeepaliveDrop;
934 	to->tcpListenDrop += from->tcpListenDrop;
935 	to->tcpListenDropQ0 += from->tcpListenDropQ0;
936 	to->tcpHalfOpenDrop += from->tcpHalfOpenDrop;
937 	to->tcpOutSackRetransSegs += from->tcpOutSackRetransSegs;
938 	to->tcpHCInSegs += from->tcpHCInSegs;
939 	to->tcpHCOutSegs += from->tcpHCOutSegs;
940 }
941 
942 /*
943  * To sum up all MIB2 stats for a tcp_stack_t from all per CPU stats.  The
944  * caller should initialize the target mib2_tcp_t properly as this function
945  * just adds up all the per CPU stats.
946  */
947 static void
948 tcp_sum_mib(tcp_stack_t *tcps, mib2_tcp_t *tcp_mib)
949 {
950 	int i;
951 	int cnt;
952 
953 	/*
954 	 * tcps_sc_cnt may change in the middle of the loop.  It is better
955 	 * to get its value first.
956 	 */
957 	cnt = tcps->tcps_sc_cnt;
958 	for (i = 0; i < cnt; i++)
959 		tcp_add_mib(&tcps->tcps_sc[i]->tcp_sc_mib, tcp_mib);
960 }
961 
962 /*
963  * To set all tcp_stat_t counters to 0.
964  */
965 static void
966 tcp_clr_stats(tcp_stat_t *stats)
967 {
968 	stats->tcp_time_wait_syn_success.value.ui64 = 0;
969 	stats->tcp_clean_death_nondetached.value.ui64 = 0;
970 	stats->tcp_eager_blowoff_q.value.ui64 = 0;
971 	stats->tcp_eager_blowoff_q0.value.ui64 = 0;
972 	stats->tcp_no_listener.value.ui64 = 0;
973 	stats->tcp_listendrop.value.ui64 = 0;
974 	stats->tcp_listendropq0.value.ui64 = 0;
975 	stats->tcp_wsrv_called.value.ui64 = 0;
976 	stats->tcp_flwctl_on.value.ui64 = 0;
977 	stats->tcp_timer_fire_early.value.ui64 = 0;
978 	stats->tcp_timer_fire_miss.value.ui64 = 0;
979 	stats->tcp_zcopy_on.value.ui64 = 0;
980 	stats->tcp_zcopy_off.value.ui64 = 0;
981 	stats->tcp_zcopy_backoff.value.ui64 = 0;
982 	stats->tcp_fusion_flowctl.value.ui64 = 0;
983 	stats->tcp_fusion_backenabled.value.ui64 = 0;
984 	stats->tcp_fusion_urg.value.ui64 = 0;
985 	stats->tcp_fusion_putnext.value.ui64 = 0;
986 	stats->tcp_fusion_unfusable.value.ui64 = 0;
987 	stats->tcp_fusion_aborted.value.ui64 = 0;
988 	stats->tcp_fusion_unqualified.value.ui64 = 0;
989 	stats->tcp_fusion_rrw_busy.value.ui64 = 0;
990 	stats->tcp_fusion_rrw_msgcnt.value.ui64 = 0;
991 	stats->tcp_fusion_rrw_plugged.value.ui64 = 0;
992 	stats->tcp_in_ack_unsent_drop.value.ui64 = 0;
993 	stats->tcp_sock_fallback.value.ui64 = 0;
994 	stats->tcp_lso_enabled.value.ui64 = 0;
995 	stats->tcp_lso_disabled.value.ui64 = 0;
996 	stats->tcp_lso_times.value.ui64 = 0;
997 	stats->tcp_lso_pkt_out.value.ui64 = 0;
998 	stats->tcp_listen_cnt_drop.value.ui64 = 0;
999 	stats->tcp_listen_mem_drop.value.ui64 = 0;
1000 	stats->tcp_zwin_mem_drop.value.ui64 = 0;
1001 	stats->tcp_zwin_ack_syn.value.ui64 = 0;
1002 	stats->tcp_rst_unsent.value.ui64 = 0;
1003 	stats->tcp_reclaim_cnt.value.ui64 = 0;
1004 	stats->tcp_reass_timeout.value.ui64 = 0;
1005 	stats->tcp_sig_no_option.value.ui64 = 0;
1006 	stats->tcp_sig_no_space.value.ui64 = 0;
1007 	stats->tcp_sig_match_failed.value.ui64 = 0;
1008 	stats->tcp_sig_verify_failed.value.ui64 = 0;
1009 	stats->tcp_sig_degraded.value.ui64 = 0;
1010 
1011 #ifdef TCP_DEBUG_COUNTER
1012 	stats->tcp_time_wait.value.ui64 = 0;
1013 	stats->tcp_rput_time_wait.value.ui64 = 0;
1014 	stats->tcp_detach_time_wait.value.ui64 = 0;
1015 	stats->tcp_timeout_calls.value.ui64 = 0;
1016 	stats->tcp_timeout_cached_alloc.value.ui64 = 0;
1017 	stats->tcp_timeout_cancel_reqs.value.ui64 = 0;
1018 	stats->tcp_timeout_canceled.value.ui64 = 0;
1019 	stats->tcp_timermp_freed.value.ui64 = 0;
1020 	stats->tcp_push_timer_cnt.value.ui64 = 0;
1021 	stats->tcp_ack_timer_cnt.value.ui64 = 0;
1022 #endif
1023 }
1024 
1025 /*
1026  * To add counters from the per CPU tcp_stat_counter_t to the stack
1027  * tcp_stat_t.
1028  */
1029 static void
1030 tcp_add_stats(tcp_stat_counter_t *from, tcp_stat_t *to)
1031 {
1032 	to->tcp_time_wait_syn_success.value.ui64 +=
1033 	    from->tcp_time_wait_syn_success;
1034 	to->tcp_clean_death_nondetached.value.ui64 +=
1035 	    from->tcp_clean_death_nondetached;
1036 	to->tcp_eager_blowoff_q.value.ui64 +=
1037 	    from->tcp_eager_blowoff_q;
1038 	to->tcp_eager_blowoff_q0.value.ui64 +=
1039 	    from->tcp_eager_blowoff_q0;
1040 	to->tcp_no_listener.value.ui64 +=
1041 	    from->tcp_no_listener;
1042 	to->tcp_listendrop.value.ui64 +=
1043 	    from->tcp_listendrop;
1044 	to->tcp_listendropq0.value.ui64 +=
1045 	    from->tcp_listendropq0;
1046 	to->tcp_wsrv_called.value.ui64 +=
1047 	    from->tcp_wsrv_called;
1048 	to->tcp_flwctl_on.value.ui64 +=
1049 	    from->tcp_flwctl_on;
1050 	to->tcp_timer_fire_early.value.ui64 +=
1051 	    from->tcp_timer_fire_early;
1052 	to->tcp_timer_fire_miss.value.ui64 +=
1053 	    from->tcp_timer_fire_miss;
1054 	to->tcp_zcopy_on.value.ui64 +=
1055 	    from->tcp_zcopy_on;
1056 	to->tcp_zcopy_off.value.ui64 +=
1057 	    from->tcp_zcopy_off;
1058 	to->tcp_zcopy_backoff.value.ui64 +=
1059 	    from->tcp_zcopy_backoff;
1060 	to->tcp_fusion_flowctl.value.ui64 +=
1061 	    from->tcp_fusion_flowctl;
1062 	to->tcp_fusion_backenabled.value.ui64 +=
1063 	    from->tcp_fusion_backenabled;
1064 	to->tcp_fusion_urg.value.ui64 +=
1065 	    from->tcp_fusion_urg;
1066 	to->tcp_fusion_putnext.value.ui64 +=
1067 	    from->tcp_fusion_putnext;
1068 	to->tcp_fusion_unfusable.value.ui64 +=
1069 	    from->tcp_fusion_unfusable;
1070 	to->tcp_fusion_aborted.value.ui64 +=
1071 	    from->tcp_fusion_aborted;
1072 	to->tcp_fusion_unqualified.value.ui64 +=
1073 	    from->tcp_fusion_unqualified;
1074 	to->tcp_fusion_rrw_busy.value.ui64 +=
1075 	    from->tcp_fusion_rrw_busy;
1076 	to->tcp_fusion_rrw_msgcnt.value.ui64 +=
1077 	    from->tcp_fusion_rrw_msgcnt;
1078 	to->tcp_fusion_rrw_plugged.value.ui64 +=
1079 	    from->tcp_fusion_rrw_plugged;
1080 	to->tcp_in_ack_unsent_drop.value.ui64 +=
1081 	    from->tcp_in_ack_unsent_drop;
1082 	to->tcp_sock_fallback.value.ui64 +=
1083 	    from->tcp_sock_fallback;
1084 	to->tcp_lso_enabled.value.ui64 +=
1085 	    from->tcp_lso_enabled;
1086 	to->tcp_lso_disabled.value.ui64 +=
1087 	    from->tcp_lso_disabled;
1088 	to->tcp_lso_times.value.ui64 +=
1089 	    from->tcp_lso_times;
1090 	to->tcp_lso_pkt_out.value.ui64 +=
1091 	    from->tcp_lso_pkt_out;
1092 	to->tcp_listen_cnt_drop.value.ui64 +=
1093 	    from->tcp_listen_cnt_drop;
1094 	to->tcp_listen_mem_drop.value.ui64 +=
1095 	    from->tcp_listen_mem_drop;
1096 	to->tcp_zwin_mem_drop.value.ui64 +=
1097 	    from->tcp_zwin_mem_drop;
1098 	to->tcp_zwin_ack_syn.value.ui64 +=
1099 	    from->tcp_zwin_ack_syn;
1100 	to->tcp_rst_unsent.value.ui64 +=
1101 	    from->tcp_rst_unsent;
1102 	to->tcp_reclaim_cnt.value.ui64 +=
1103 	    from->tcp_reclaim_cnt;
1104 	to->tcp_reass_timeout.value.ui64 +=
1105 	    from->tcp_reass_timeout;
1106 	to->tcp_sig_no_option.value.ui64 +=
1107 	    from->tcp_sig_no_option;
1108 	to->tcp_sig_no_space.value.ui64 +=
1109 	    from->tcp_sig_no_space;
1110 	to->tcp_sig_match_failed.value.ui64 +=
1111 	    from->tcp_sig_match_failed;
1112 	to->tcp_sig_verify_failed.value.ui64 +=
1113 	    from->tcp_sig_verify_failed;
1114 	to->tcp_sig_degraded.value.ui64 +=
1115 	    from->tcp_sig_degraded;
1116 
1117 #ifdef TCP_DEBUG_COUNTER
1118 	to->tcp_time_wait.value.ui64 +=
1119 	    from->tcp_time_wait;
1120 	to->tcp_rput_time_wait.value.ui64 +=
1121 	    from->tcp_rput_time_wait;
1122 	to->tcp_detach_time_wait.value.ui64 +=
1123 	    from->tcp_detach_time_wait;
1124 	to->tcp_timeout_calls.value.ui64 +=
1125 	    from->tcp_timeout_calls;
1126 	to->tcp_timeout_cached_alloc.value.ui64 +=
1127 	    from->tcp_timeout_cached_alloc;
1128 	to->tcp_timeout_cancel_reqs.value.ui64 +=
1129 	    from->tcp_timeout_cancel_reqs;
1130 	to->tcp_timeout_canceled.value.ui64 +=
1131 	    from->tcp_timeout_canceled;
1132 	to->tcp_timermp_freed.value.ui64 +=
1133 	    from->tcp_timermp_freed;
1134 	to->tcp_push_timer_cnt.value.ui64 +=
1135 	    from->tcp_push_timer_cnt;
1136 	to->tcp_ack_timer_cnt.value.ui64 +=
1137 	    from->tcp_ack_timer_cnt;
1138 #endif
1139 }
1140