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