xref: /illumos-gate/usr/src/uts/common/inet/udp/udp_stats.c (revision ab82c29b6e890d0f1241f9cd0cefda3430f46bd5)
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 	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
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
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
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 *
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
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
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
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
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 *
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
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
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