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