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 }