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