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