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