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 *
udp_snmp_get(queue_t * q,mblk_t * mpctl,boolean_t legacy_req)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
udp_snmp_set(queue_t * q,t_scalar_t level,t_scalar_t name,uchar_t * ptr,int len)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
udp_kstat_fini(netstackid_t stackid,kstat_t * ksp)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
udp_add_mib(mib2_udp_t * from,mib2_udp_t * to)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 *
udp_kstat2_init(netstackid_t stackid)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
udp_kstat2_fini(netstackid_t stackid,kstat_t * ksp)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
udp_add_stats(udp_stat_counter_t * from,udp_stat_t * to)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
udp_clr_stats(udp_stat_t * stats)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
udp_kstat2_update(kstat_t * kp,int rw)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 *
udp_kstat_init(netstackid_t stackid)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
udp_sum_mib(udp_stack_t * us,mib2_udp_t * udp_mib)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
udp_kstat_update(kstat_t * kp,int rw)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