XXXX adding PID information to netstat output
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/kstatcom.h> 33 #include <inet/snmpcom.h> 34 #include <inet/mib2.h> 35 #include <inet/optcom.h> 36 #include <inet/snmpcom.h> 37 #include <inet/kstatcom.h> 38 #include <inet/udp_impl.h> 39 40 static int udp_kstat_update(kstat_t *, int); 41 static int udp_kstat2_update(kstat_t *, int); 42 static void udp_sum_mib(udp_stack_t *, mib2_udp_t *); 43 static void udp_clr_stats(udp_stat_t *); 44 static void udp_add_stats(udp_stat_counter_t *, udp_stat_t *); 45 static void udp_add_mib(mib2_udp_t *, mib2_udp_t *); 46 /* 47 * return SNMP stuff in buffer in mpdata. We don't hold any lock and report 48 * information that can be changing beneath us. 49 */ 50 mblk_t * 51 udp_snmp_get(queue_t *q, mblk_t *mpctl, boolean_t legacy_req) 52 { 53 mblk_t *mpdata; 54 mblk_t *mp_conn_ctl; 55 mblk_t *mp_attr_ctl; 56 mblk_t *mp_pidnode_ctl; 57 mblk_t *mp6_conn_ctl; 58 mblk_t *mp6_attr_ctl; 59 mblk_t *mp6_pidnode_ctl; 60 mblk_t *mp_conn_tail; 61 mblk_t *mp_attr_tail; 62 mblk_t *mp_pidnode_tail; 63 mblk_t *mp6_conn_tail; 64 mblk_t *mp6_attr_tail; 65 mblk_t *mp6_pidnode_tail; 66 struct opthdr *optp; 67 mib2_udpEntry_t ude; 68 mib2_udp6Entry_t ude6; 69 mib2_transportMLPEntry_t mlp; 70 int state; 71 zoneid_t zoneid; 72 int i; 73 connf_t *connfp; 74 conn_t *connp = Q_TO_CONN(q); 75 int v4_conn_idx; 76 int v6_conn_idx; 77 boolean_t needattr; 78 udp_t *udp; 79 ip_stack_t *ipst = connp->conn_netstack->netstack_ip; 80 udp_stack_t *us = connp->conn_netstack->netstack_udp; 81 mblk_t *mp2ctl; 82 mib2_udp_t udp_mib; 83 size_t udp_mib_size, ude_size, ude6_size; 84 85 conn_pid_node_list_hdr_t *cph; 86 87 88 /* 89 * make a copy of the original message 90 */ 91 mp2ctl = copymsg(mpctl); 92 93 mp_conn_ctl = mp_attr_ctl = mp6_conn_ctl = NULL; 94 if (mpctl == NULL || 95 (mpdata = mpctl->b_cont) == NULL || 96 (mp_conn_ctl = copymsg(mpctl)) == NULL || 97 (mp_attr_ctl = copymsg(mpctl)) == NULL || 98 (mp_pidnode_ctl = copymsg(mpctl)) == NULL || 99 (mp6_conn_ctl = copymsg(mpctl)) == NULL || 100 (mp6_attr_ctl = copymsg(mpctl)) == NULL || 101 (mp6_pidnode_ctl = copymsg(mpctl)) == NULL) { 102 freemsg(mp_conn_ctl); 103 freemsg(mp_attr_ctl); 104 freemsg(mp_pidnode_ctl); 105 freemsg(mp6_conn_ctl); 106 freemsg(mp6_attr_ctl); 107 freemsg(mp6_pidnode_ctl); 108 freemsg(mpctl); 109 freemsg(mp2ctl); 110 return (0); 111 } 112 113 zoneid = connp->conn_zoneid; 114 115 if (legacy_req) { 116 udp_mib_size = LEGACY_MIB_SIZE(&udp_mib, mib2_udp_t); 117 ude_size = LEGACY_MIB_SIZE(&ude, mib2_udpEntry_t); 118 ude6_size = LEGACY_MIB_SIZE(&ude6, mib2_udp6Entry_t); 119 } else { 120 udp_mib_size = sizeof (mib2_udp_t); 121 ude_size = sizeof (mib2_udpEntry_t); 122 ude6_size = sizeof (mib2_udp6Entry_t); 123 } 124 125 bzero(&udp_mib, sizeof (udp_mib)); 126 /* fixed length structure for IPv4 and IPv6 counters */ 127 SET_MIB(udp_mib.udpEntrySize, ude_size); 128 SET_MIB(udp_mib.udp6EntrySize, ude6_size); 129 130 udp_sum_mib(us, &udp_mib); 131 132 /* 133 * Synchronize 32- and 64-bit counters. Note that udpInDatagrams and 134 * udpOutDatagrams are not updated anywhere in UDP. The new 64 bits 135 * counters are used. Hence the old counters' values in us_sc_mib 136 * are always 0. 137 */ 138 SYNC32_MIB(&udp_mib, udpInDatagrams, udpHCInDatagrams); 139 SYNC32_MIB(&udp_mib, udpOutDatagrams, udpHCOutDatagrams); 140 141 optp = (struct opthdr *)&mpctl->b_rptr[sizeof (struct T_optmgmt_ack)]; 142 optp->level = MIB2_UDP; 143 optp->name = 0; 144 (void) snmp_append_data(mpdata, (char *)&udp_mib, udp_mib_size); 145 optp->len = msgdsize(mpdata); 146 qreply(q, mpctl); 147 148 mp_conn_tail = mp_attr_tail = mp6_conn_tail = mp6_attr_tail = NULL; 149 mp_pidnode_tail = mp6_pidnode_tail = NULL; 150 v4_conn_idx = v6_conn_idx = 0; 151 152 for (i = 0; i < CONN_G_HASH_SIZE; i++) { 153 connfp = &ipst->ips_ipcl_globalhash_fanout[i]; 154 connp = NULL; 155 156 while ((connp = ipcl_get_next_conn(connfp, connp, 157 IPCL_UDPCONN))) { 158 udp = connp->conn_udp; 159 if (zoneid != connp->conn_zoneid) 160 continue; 161 162 /* 163 * Note that the port numbers are sent in 164 * host byte order 165 */ 166 167 if (udp->udp_state == TS_UNBND) 168 state = MIB2_UDP_unbound; 169 else if (udp->udp_state == TS_IDLE) 170 state = MIB2_UDP_idle; 171 else if (udp->udp_state == TS_DATA_XFER) 172 state = MIB2_UDP_connected; 173 else 174 state = MIB2_UDP_unknown; 175 176 needattr = B_FALSE; 177 bzero(&mlp, sizeof (mlp)); 178 if (connp->conn_mlp_type != mlptSingle) { 179 if (connp->conn_mlp_type == mlptShared || 180 connp->conn_mlp_type == mlptBoth) 181 mlp.tme_flags |= MIB2_TMEF_SHARED; 182 if (connp->conn_mlp_type == mlptPrivate || 183 connp->conn_mlp_type == mlptBoth) 184 mlp.tme_flags |= MIB2_TMEF_PRIVATE; 185 needattr = B_TRUE; 186 } 187 if (connp->conn_anon_mlp) { 188 mlp.tme_flags |= MIB2_TMEF_ANONMLP; 189 needattr = B_TRUE; 190 } 191 switch (connp->conn_mac_mode) { 192 case CONN_MAC_DEFAULT: 193 break; 194 case CONN_MAC_AWARE: 195 mlp.tme_flags |= MIB2_TMEF_MACEXEMPT; 196 needattr = B_TRUE; 197 break; 198 case CONN_MAC_IMPLICIT: 199 mlp.tme_flags |= MIB2_TMEF_MACIMPLICIT; 200 needattr = B_TRUE; 201 break; 202 } 203 mutex_enter(&connp->conn_lock); 204 if (udp->udp_state == TS_DATA_XFER && 205 connp->conn_ixa->ixa_tsl != NULL) { 206 ts_label_t *tsl; 207 208 tsl = connp->conn_ixa->ixa_tsl; 209 mlp.tme_flags |= MIB2_TMEF_IS_LABELED; 210 mlp.tme_doi = label2doi(tsl); 211 mlp.tme_label = *label2bslabel(tsl); 212 needattr = B_TRUE; 213 } 214 mutex_exit(&connp->conn_lock); 215 216 /* 217 * Create an IPv4 table entry for IPv4 entries and also 218 * any IPv6 entries which are bound to in6addr_any 219 * (i.e. anything a IPv4 peer could connect/send to). 220 */ 221 if (connp->conn_ipversion == IPV4_VERSION || 222 (udp->udp_state <= TS_IDLE && 223 IN6_IS_ADDR_UNSPECIFIED(&connp->conn_laddr_v6))) { 224 ude.udpEntryInfo.ue_state = state; 225 /* 226 * If in6addr_any this will set it to 227 * INADDR_ANY 228 */ 229 ude.udpLocalAddress = connp->conn_laddr_v4; 230 ude.udpLocalPort = ntohs(connp->conn_lport); 231 if (udp->udp_state == TS_DATA_XFER) { 232 /* 233 * Can potentially get here for 234 * v6 socket if another process 235 * (say, ping) has just done a 236 * sendto(), changing the state 237 * from the TS_IDLE above to 238 * TS_DATA_XFER by the time we hit 239 * this part of the code. 240 */ 241 ude.udpEntryInfo.ue_RemoteAddress = 242 connp->conn_faddr_v4; 243 ude.udpEntryInfo.ue_RemotePort = 244 ntohs(connp->conn_fport); 245 } else { 246 ude.udpEntryInfo.ue_RemoteAddress = 0; 247 ude.udpEntryInfo.ue_RemotePort = 0; 248 } 249 250 /* 251 * We make the assumption that all udp_t 252 * structs will be created within an address 253 * region no larger than 32-bits. 254 */ 255 ude.udpInstance = (uint32_t)(uintptr_t)udp; 256 ude.udpCreationProcess = 257 (connp->conn_cpid < 0) ? 258 MIB2_UNKNOWN_PROCESS : 259 connp->conn_cpid; 260 ude.udpCreationTime = connp->conn_open_time; 261 262 (void) snmp_append_data2(mp_conn_ctl->b_cont, 263 &mp_conn_tail, (char *)&ude, ude_size); 264 /* my data */ 265 (void) snmp_append_data2(mp_pidnode_ctl->b_cont, 266 &mp_pidnode_tail, (char *)&ude, ude_size); 267 268 cph = conn_get_pid_list(connp); 269 (void) snmp_append_data2(mp_pidnode_ctl->b_cont, 270 &mp_pidnode_tail, (char *)cph, 271 cph->cph_tot_size); 272 273 kmem_free(cph, cph->cph_tot_size); 274 /* end of my data */ 275 276 mlp.tme_connidx = v4_conn_idx++; 277 if (needattr) 278 (void) snmp_append_data2( 279 mp_attr_ctl->b_cont, &mp_attr_tail, 280 (char *)&mlp, sizeof (mlp)); 281 } 282 if (connp->conn_ipversion == IPV6_VERSION) { 283 ude6.udp6EntryInfo.ue_state = state; 284 ude6.udp6LocalAddress = connp->conn_laddr_v6; 285 ude6.udp6LocalPort = ntohs(connp->conn_lport); 286 mutex_enter(&connp->conn_lock); 287 if (connp->conn_ixa->ixa_flags & 288 IXAF_SCOPEID_SET) { 289 ude6.udp6IfIndex = 290 connp->conn_ixa->ixa_scopeid; 291 } else { 292 ude6.udp6IfIndex = connp->conn_bound_if; 293 } 294 mutex_exit(&connp->conn_lock); 295 if (udp->udp_state == TS_DATA_XFER) { 296 ude6.udp6EntryInfo.ue_RemoteAddress = 297 connp->conn_faddr_v6; 298 ude6.udp6EntryInfo.ue_RemotePort = 299 ntohs(connp->conn_fport); 300 } else { 301 ude6.udp6EntryInfo.ue_RemoteAddress = 302 sin6_null.sin6_addr; 303 ude6.udp6EntryInfo.ue_RemotePort = 0; 304 } 305 /* 306 * We make the assumption that all udp_t 307 * structs will be created within an address 308 * region no larger than 32-bits. 309 */ 310 ude6.udp6Instance = (uint32_t)(uintptr_t)udp; 311 ude6.udp6CreationProcess = 312 (connp->conn_cpid < 0) ? 313 MIB2_UNKNOWN_PROCESS : 314 connp->conn_cpid; 315 ude6.udp6CreationTime = connp->conn_open_time; 316 317 (void) snmp_append_data2(mp6_conn_ctl->b_cont, 318 &mp6_conn_tail, (char *)&ude6, ude6_size); 319 /* my dat */ 320 (void) snmp_append_data2( 321 mp6_pidnode_ctl->b_cont, &mp6_pidnode_tail, 322 (char *)&ude6, ude6_size); 323 324 cph = conn_get_pid_list(connp); 325 (void) snmp_append_data2( 326 mp6_pidnode_ctl->b_cont, &mp6_pidnode_tail, 327 (char *)cph, cph->cph_tot_size); 328 329 kmem_free(cph, cph->cph_tot_size); 330 /* end of my data */ 331 mlp.tme_connidx = v6_conn_idx++; 332 if (needattr) 333 (void) snmp_append_data2( 334 mp6_attr_ctl->b_cont, 335 &mp6_attr_tail, (char *)&mlp, 336 sizeof (mlp)); 337 } 338 } 339 } 340 341 /* IPv4 UDP endpoints */ 342 optp = (struct opthdr *)&mp_conn_ctl->b_rptr[ 343 sizeof (struct T_optmgmt_ack)]; 344 optp->level = MIB2_UDP; 345 optp->name = MIB2_UDP_ENTRY; 346 optp->len = msgdsize(mp_conn_ctl->b_cont); 347 qreply(q, mp_conn_ctl); 348 349 /* table of MLP attributes... */ 350 optp = (struct opthdr *)&mp_attr_ctl->b_rptr[ 351 sizeof (struct T_optmgmt_ack)]; 352 optp->level = MIB2_UDP; 353 optp->name = EXPER_XPORT_MLP; 354 optp->len = msgdsize(mp_attr_ctl->b_cont); 355 if (optp->len == 0) 356 freemsg(mp_attr_ctl); 357 else 358 qreply(q, mp_attr_ctl); 359 360 /* table of EXPER_XPORT_PROC_INFO ipv4 */ 361 optp = (struct opthdr *)&mp_pidnode_ctl->b_rptr[ 362 sizeof (struct T_optmgmt_ack)]; 363 optp->level = MIB2_UDP; 364 optp->name = EXPER_XPORT_PROC_INFO; 365 optp->len = msgdsize(mp_pidnode_ctl->b_cont); 366 if (optp->len == 0) 367 freemsg(mp_pidnode_ctl); 368 else 369 qreply(q, mp_pidnode_ctl); 370 371 /* IPv6 UDP endpoints */ 372 optp = (struct opthdr *)&mp6_conn_ctl->b_rptr[ 373 sizeof (struct T_optmgmt_ack)]; 374 optp->level = MIB2_UDP6; 375 optp->name = MIB2_UDP6_ENTRY; 376 optp->len = msgdsize(mp6_conn_ctl->b_cont); 377 qreply(q, mp6_conn_ctl); 378 379 /* table of MLP attributes... */ 380 optp = (struct opthdr *)&mp6_attr_ctl->b_rptr[ 381 sizeof (struct T_optmgmt_ack)]; 382 optp->level = MIB2_UDP6; 383 optp->name = EXPER_XPORT_MLP; 384 optp->len = msgdsize(mp6_attr_ctl->b_cont); 385 if (optp->len == 0) 386 freemsg(mp6_attr_ctl); 387 else 388 qreply(q, mp6_attr_ctl); 389 390 /* table of EXPER_XPORT_PROC_INFO ipv6 */ 391 optp = (struct opthdr *)&mp6_pidnode_ctl->b_rptr[ 392 sizeof (struct T_optmgmt_ack)]; 393 optp->level = MIB2_UDP6; 394 optp->name = EXPER_XPORT_PROC_INFO; 395 optp->len = msgdsize(mp6_pidnode_ctl->b_cont); 396 if (optp->len == 0) 397 freemsg(mp6_pidnode_ctl); 398 else 399 qreply(q, mp6_pidnode_ctl); 400 401 return (mp2ctl); 402 } 403 404 /* 405 * Return 0 if invalid set request, 1 otherwise, including non-udp requests. 406 * NOTE: Per MIB-II, UDP has no writable data. 407 * TODO: If this ever actually tries to set anything, it needs to be 408 * to do the appropriate locking. 409 */ 410 /* ARGSUSED */ 411 int 412 udp_snmp_set(queue_t *q, t_scalar_t level, t_scalar_t name, 413 uchar_t *ptr, int len) 414 { 415 switch (level) { 416 case MIB2_UDP: 417 return (0); 418 default: 419 return (1); 420 } 421 } 422 423 void 424 udp_kstat_fini(netstackid_t stackid, kstat_t *ksp) 425 { 426 if (ksp != NULL) { 427 ASSERT(stackid == (netstackid_t)(uintptr_t)ksp->ks_private); 428 kstat_delete_netstack(ksp, stackid); 429 } 430 } 431 432 /* 433 * To add stats from one mib2_udp_t to another. Static fields are not added. 434 * The caller should set them up propertly. 435 */ 436 static void 437 udp_add_mib(mib2_udp_t *from, mib2_udp_t *to) 438 { 439 to->udpHCInDatagrams += from->udpHCInDatagrams; 440 to->udpInErrors += from->udpInErrors; 441 to->udpHCOutDatagrams += from->udpHCOutDatagrams; 442 to->udpOutErrors += from->udpOutErrors; 443 } 444 445 446 void * 447 udp_kstat2_init(netstackid_t stackid) 448 { 449 kstat_t *ksp; 450 451 udp_stat_t template = { 452 { "udp_sock_fallback", KSTAT_DATA_UINT64 }, 453 { "udp_out_opt", KSTAT_DATA_UINT64 }, 454 { "udp_out_err_notconn", KSTAT_DATA_UINT64 }, 455 { "udp_out_err_output", KSTAT_DATA_UINT64 }, 456 { "udp_out_err_tudr", KSTAT_DATA_UINT64 }, 457 #ifdef DEBUG 458 { "udp_data_conn", KSTAT_DATA_UINT64 }, 459 { "udp_data_notconn", KSTAT_DATA_UINT64 }, 460 { "udp_out_lastdst", KSTAT_DATA_UINT64 }, 461 { "udp_out_diffdst", KSTAT_DATA_UINT64 }, 462 { "udp_out_ipv6", KSTAT_DATA_UINT64 }, 463 { "udp_out_mapped", KSTAT_DATA_UINT64 }, 464 { "udp_out_ipv4", KSTAT_DATA_UINT64 }, 465 #endif 466 }; 467 468 ksp = kstat_create_netstack(UDP_MOD_NAME, 0, "udpstat", "net", 469 KSTAT_TYPE_NAMED, sizeof (template) / sizeof (kstat_named_t), 470 0, stackid); 471 472 if (ksp == NULL) 473 return (NULL); 474 475 bcopy(&template, ksp->ks_data, sizeof (template)); 476 ksp->ks_update = udp_kstat2_update; 477 ksp->ks_private = (void *)(uintptr_t)stackid; 478 479 kstat_install(ksp); 480 return (ksp); 481 } 482 483 void 484 udp_kstat2_fini(netstackid_t stackid, kstat_t *ksp) 485 { 486 if (ksp != NULL) { 487 ASSERT(stackid == (netstackid_t)(uintptr_t)ksp->ks_private); 488 kstat_delete_netstack(ksp, stackid); 489 } 490 } 491 492 /* 493 * To copy counters from the per CPU udpp_stat_counter_t to the stack 494 * udp_stat_t. 495 */ 496 static void 497 udp_add_stats(udp_stat_counter_t *from, udp_stat_t *to) 498 { 499 to->udp_sock_fallback.value.ui64 += from->udp_sock_fallback; 500 to->udp_out_opt.value.ui64 += from->udp_out_opt; 501 to->udp_out_err_notconn.value.ui64 += from->udp_out_err_notconn; 502 to->udp_out_err_output.value.ui64 += from->udp_out_err_output; 503 to->udp_out_err_tudr.value.ui64 += from->udp_out_err_tudr; 504 #ifdef DEBUG 505 to->udp_data_conn.value.ui64 += from->udp_data_conn; 506 to->udp_data_notconn.value.ui64 += from->udp_data_notconn; 507 to->udp_out_lastdst.value.ui64 += from->udp_out_lastdst; 508 to->udp_out_diffdst.value.ui64 += from->udp_out_diffdst; 509 to->udp_out_ipv6.value.ui64 += from->udp_out_ipv6; 510 to->udp_out_mapped.value.ui64 += from->udp_out_mapped; 511 to->udp_out_ipv4.value.ui64 += from->udp_out_ipv4; 512 #endif 513 } 514 515 /* 516 * To set all udp_stat_t counters to 0. 517 */ 518 static void 519 udp_clr_stats(udp_stat_t *stats) 520 { 521 stats->udp_sock_fallback.value.ui64 = 0; 522 stats->udp_out_opt.value.ui64 = 0; 523 stats->udp_out_err_notconn.value.ui64 = 0; 524 stats->udp_out_err_output.value.ui64 = 0; 525 stats->udp_out_err_tudr.value.ui64 = 0; 526 #ifdef DEBUG 527 stats->udp_data_conn.value.ui64 = 0; 528 stats->udp_data_notconn.value.ui64 = 0; 529 stats->udp_out_lastdst.value.ui64 = 0; 530 stats->udp_out_diffdst.value.ui64 = 0; 531 stats->udp_out_ipv6.value.ui64 = 0; 532 stats->udp_out_mapped.value.ui64 = 0; 533 stats->udp_out_ipv4.value.ui64 = 0; 534 #endif 535 } 536 537 int 538 udp_kstat2_update(kstat_t *kp, int rw) 539 { 540 udp_stat_t *stats; 541 netstackid_t stackid = (netstackid_t)(uintptr_t)kp->ks_private; 542 netstack_t *ns; 543 udp_stack_t *us; 544 int i; 545 int cnt; 546 547 if (rw == KSTAT_WRITE) 548 return (EACCES); 549 550 ns = netstack_find_by_stackid(stackid); 551 if (ns == NULL) 552 return (-1); 553 us = ns->netstack_udp; 554 if (us == NULL) { 555 netstack_rele(ns); 556 return (-1); 557 } 558 stats = (udp_stat_t *)kp->ks_data; 559 udp_clr_stats(stats); 560 561 cnt = us->us_sc_cnt; 562 for (i = 0; i < cnt; i++) 563 udp_add_stats(&us->us_sc[i]->udp_sc_stats, stats); 564 565 netstack_rele(ns); 566 return (0); 567 } 568 569 void * 570 udp_kstat_init(netstackid_t stackid) 571 { 572 kstat_t *ksp; 573 574 udp_named_kstat_t template = { 575 { "inDatagrams", KSTAT_DATA_UINT64, 0 }, 576 { "inErrors", KSTAT_DATA_UINT32, 0 }, 577 { "outDatagrams", KSTAT_DATA_UINT64, 0 }, 578 { "entrySize", KSTAT_DATA_INT32, 0 }, 579 { "entry6Size", KSTAT_DATA_INT32, 0 }, 580 { "outErrors", KSTAT_DATA_UINT32, 0 }, 581 }; 582 583 ksp = kstat_create_netstack(UDP_MOD_NAME, 0, UDP_MOD_NAME, "mib2", 584 KSTAT_TYPE_NAMED, NUM_OF_FIELDS(udp_named_kstat_t), 0, stackid); 585 586 if (ksp == NULL) 587 return (NULL); 588 589 template.entrySize.value.ui32 = sizeof (mib2_udpEntry_t); 590 template.entry6Size.value.ui32 = sizeof (mib2_udp6Entry_t); 591 592 bcopy(&template, ksp->ks_data, sizeof (template)); 593 ksp->ks_update = udp_kstat_update; 594 ksp->ks_private = (void *)(uintptr_t)stackid; 595 596 kstat_install(ksp); 597 return (ksp); 598 } 599 600 /* 601 * To sum up all MIB2 stats for a udp_stack_t from all per CPU stats. The 602 * caller should initialize the target mib2_udp_t properly as this function 603 * just adds up all the per CPU stats. 604 */ 605 static void 606 udp_sum_mib(udp_stack_t *us, mib2_udp_t *udp_mib) 607 { 608 int i; 609 int cnt; 610 611 cnt = us->us_sc_cnt; 612 for (i = 0; i < cnt; i++) 613 udp_add_mib(&us->us_sc[i]->udp_sc_mib, udp_mib); 614 } 615 616 static int 617 udp_kstat_update(kstat_t *kp, int rw) 618 { 619 udp_named_kstat_t *udpkp; 620 netstackid_t stackid = (netstackid_t)(uintptr_t)kp->ks_private; 621 netstack_t *ns; 622 udp_stack_t *us; 623 mib2_udp_t udp_mib; 624 625 if (rw == KSTAT_WRITE) 626 return (EACCES); 627 628 ns = netstack_find_by_stackid(stackid); 629 if (ns == NULL) 630 return (-1); 631 us = ns->netstack_udp; 632 if (us == NULL) { 633 netstack_rele(ns); 634 return (-1); 635 } 636 udpkp = (udp_named_kstat_t *)kp->ks_data; 637 638 bzero(&udp_mib, sizeof (udp_mib)); 639 udp_sum_mib(us, &udp_mib); 640 641 udpkp->inDatagrams.value.ui64 = udp_mib.udpHCInDatagrams; 642 udpkp->inErrors.value.ui32 = udp_mib.udpInErrors; 643 udpkp->outDatagrams.value.ui64 = udp_mib.udpHCOutDatagrams; 644 udpkp->outErrors.value.ui32 = udp_mib.udpOutErrors; 645 netstack_rele(ns); 646 return (0); 647 } --- EOF ---