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