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 }