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