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