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