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 }