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