docs/how-to-build.md: use proper markup for directory names
[unleashed/tickless.git] / kernel / net / udp / udp_stats.c
blob54f9361776af5055a39e028a337c992f5b428b7a
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <sys/types.h>
27 #include <sys/tihdr.h>
28 #include <sys/policy.h>
30 #include <inet/common.h>
31 #include <inet/kstatcom.h>
32 #include <inet/snmpcom.h>
33 #include <inet/mib2.h>
34 #include <inet/optcom.h>
35 #include <inet/snmpcom.h>
36 #include <inet/kstatcom.h>
37 #include <inet/udp_impl.h>
39 static int udp_kstat_update(kstat_t *, int);
40 static int udp_kstat2_update(kstat_t *, int);
41 static void udp_sum_mib(udp_stack_t *, mib2_udp_t *);
42 static void udp_clr_stats(udp_stat_t *);
43 static void udp_add_stats(udp_stat_counter_t *, udp_stat_t *);
44 static void udp_add_mib(mib2_udp_t *, mib2_udp_t *);
46 * return SNMP stuff in buffer in mpdata. We don't hold any lock and report
47 * information that can be changing beneath us.
49 mblk_t *
50 udp_snmp_get(queue_t *q, mblk_t *mpctl, boolean_t legacy_req)
52 mblk_t *mpdata;
53 mblk_t *mp_conn_ctl;
54 mblk_t *mp6_conn_ctl;
55 mblk_t *mp_conn_tail;
56 mblk_t *mp6_conn_tail;
57 struct opthdr *optp;
58 mib2_udpEntry_t ude;
59 mib2_udp6Entry_t ude6;
60 int state;
61 zoneid_t zoneid;
62 int i;
63 connf_t *connfp;
64 conn_t *connp = Q_TO_CONN(q);
65 int v4_conn_idx;
66 int v6_conn_idx;
67 udp_t *udp;
68 ip_stack_t *ipst = connp->conn_netstack->netstack_ip;
69 udp_stack_t *us = connp->conn_netstack->netstack_udp;
70 mblk_t *mp2ctl;
71 mib2_udp_t udp_mib;
72 size_t udp_mib_size, ude_size, ude6_size;
76 * make a copy of the original message
78 mp2ctl = copymsg(mpctl);
80 mp_conn_ctl = mp6_conn_ctl = NULL;
81 if (mpctl == NULL ||
82 (mpdata = mpctl->b_cont) == NULL ||
83 (mp_conn_ctl = copymsg(mpctl)) == NULL ||
84 (mp6_conn_ctl = copymsg(mpctl)) == NULL) {
85 freemsg(mp_conn_ctl);
86 freemsg(mp6_conn_ctl);
87 freemsg(mpctl);
88 freemsg(mp2ctl);
89 return (0);
92 zoneid = connp->conn_zoneid;
94 if (legacy_req) {
95 udp_mib_size = LEGACY_MIB_SIZE(&udp_mib, mib2_udp_t);
96 ude_size = LEGACY_MIB_SIZE(&ude, mib2_udpEntry_t);
97 ude6_size = LEGACY_MIB_SIZE(&ude6, mib2_udp6Entry_t);
98 } else {
99 udp_mib_size = sizeof (mib2_udp_t);
100 ude_size = sizeof (mib2_udpEntry_t);
101 ude6_size = sizeof (mib2_udp6Entry_t);
104 bzero(&udp_mib, sizeof (udp_mib));
105 /* fixed length structure for IPv4 and IPv6 counters */
106 SET_MIB(udp_mib.udpEntrySize, ude_size);
107 SET_MIB(udp_mib.udp6EntrySize, ude6_size);
109 udp_sum_mib(us, &udp_mib);
112 * Synchronize 32- and 64-bit counters. Note that udpInDatagrams and
113 * udpOutDatagrams are not updated anywhere in UDP. The new 64 bits
114 * counters are used. Hence the old counters' values in us_sc_mib
115 * are always 0.
117 SYNC32_MIB(&udp_mib, udpInDatagrams, udpHCInDatagrams);
118 SYNC32_MIB(&udp_mib, udpOutDatagrams, udpHCOutDatagrams);
120 optp = (struct opthdr *)&mpctl->b_rptr[sizeof (struct T_optmgmt_ack)];
121 optp->level = MIB2_UDP;
122 optp->name = 0;
123 (void) snmp_append_data(mpdata, (char *)&udp_mib, udp_mib_size);
124 optp->len = msgdsize(mpdata);
125 qreply(q, mpctl);
127 mp_conn_tail = mp6_conn_tail = NULL;
128 v4_conn_idx = v6_conn_idx = 0;
130 for (i = 0; i < CONN_G_HASH_SIZE; i++) {
131 connfp = &ipst->ips_ipcl_globalhash_fanout[i];
132 connp = NULL;
134 while ((connp = ipcl_get_next_conn(connfp, connp,
135 IPCL_UDPCONN))) {
136 udp = connp->conn_udp;
137 if (zoneid != connp->conn_zoneid)
138 continue;
141 * Note that the port numbers are sent in
142 * host byte order
145 if (udp->udp_state == TS_UNBND)
146 state = MIB2_UDP_unbound;
147 else if (udp->udp_state == TS_IDLE)
148 state = MIB2_UDP_idle;
149 else if (udp->udp_state == TS_DATA_XFER)
150 state = MIB2_UDP_connected;
151 else
152 state = MIB2_UDP_unknown;
155 * Create an IPv4 table entry for IPv4 entries and also
156 * any IPv6 entries which are bound to in6addr_any
157 * (i.e. anything a IPv4 peer could connect/send to).
159 if (connp->conn_ipversion == IPV4_VERSION ||
160 (udp->udp_state <= TS_IDLE &&
161 IN6_IS_ADDR_UNSPECIFIED(&connp->conn_laddr_v6))) {
162 ude.udpEntryInfo.ue_state = state;
164 * If in6addr_any this will set it to
165 * INADDR_ANY
167 ude.udpLocalAddress = connp->conn_laddr_v4;
168 ude.udpLocalPort = ntohs(connp->conn_lport);
169 if (udp->udp_state == TS_DATA_XFER) {
171 * Can potentially get here for
172 * v6 socket if another process
173 * (say, ping) has just done a
174 * sendto(), changing the state
175 * from the TS_IDLE above to
176 * TS_DATA_XFER by the time we hit
177 * this part of the code.
179 ude.udpEntryInfo.ue_RemoteAddress =
180 connp->conn_faddr_v4;
181 ude.udpEntryInfo.ue_RemotePort =
182 ntohs(connp->conn_fport);
183 } else {
184 ude.udpEntryInfo.ue_RemoteAddress = 0;
185 ude.udpEntryInfo.ue_RemotePort = 0;
189 * We make the assumption that all udp_t
190 * structs will be created within an address
191 * region no larger than 32-bits.
193 ude.udpInstance = (uint32_t)(uintptr_t)udp;
194 ude.udpCreationProcess =
195 (connp->conn_cpid < 0) ?
196 MIB2_UNKNOWN_PROCESS :
197 connp->conn_cpid;
198 ude.udpCreationTime = connp->conn_open_time;
200 (void) snmp_append_data2(mp_conn_ctl->b_cont,
201 &mp_conn_tail, (char *)&ude, ude_size);
203 if (connp->conn_ipversion == IPV6_VERSION) {
204 ude6.udp6EntryInfo.ue_state = state;
205 ude6.udp6LocalAddress = connp->conn_laddr_v6;
206 ude6.udp6LocalPort = ntohs(connp->conn_lport);
207 mutex_enter(&connp->conn_lock);
208 if (connp->conn_ixa->ixa_flags &
209 IXAF_SCOPEID_SET) {
210 ude6.udp6IfIndex =
211 connp->conn_ixa->ixa_scopeid;
212 } else {
213 ude6.udp6IfIndex = connp->conn_bound_if;
215 mutex_exit(&connp->conn_lock);
216 if (udp->udp_state == TS_DATA_XFER) {
217 ude6.udp6EntryInfo.ue_RemoteAddress =
218 connp->conn_faddr_v6;
219 ude6.udp6EntryInfo.ue_RemotePort =
220 ntohs(connp->conn_fport);
221 } else {
222 ude6.udp6EntryInfo.ue_RemoteAddress =
223 sin6_null.sin6_addr;
224 ude6.udp6EntryInfo.ue_RemotePort = 0;
227 * We make the assumption that all udp_t
228 * structs will be created within an address
229 * region no larger than 32-bits.
231 ude6.udp6Instance = (uint32_t)(uintptr_t)udp;
232 ude6.udp6CreationProcess =
233 (connp->conn_cpid < 0) ?
234 MIB2_UNKNOWN_PROCESS :
235 connp->conn_cpid;
236 ude6.udp6CreationTime = connp->conn_open_time;
238 (void) snmp_append_data2(mp6_conn_ctl->b_cont,
239 &mp6_conn_tail, (char *)&ude6, ude6_size);
244 /* IPv4 UDP endpoints */
245 optp = (struct opthdr *)&mp_conn_ctl->b_rptr[
246 sizeof (struct T_optmgmt_ack)];
247 optp->level = MIB2_UDP;
248 optp->name = MIB2_UDP_ENTRY;
249 optp->len = msgdsize(mp_conn_ctl->b_cont);
250 qreply(q, mp_conn_ctl);
252 /* IPv6 UDP endpoints */
253 optp = (struct opthdr *)&mp6_conn_ctl->b_rptr[
254 sizeof (struct T_optmgmt_ack)];
255 optp->level = MIB2_UDP6;
256 optp->name = MIB2_UDP6_ENTRY;
257 optp->len = msgdsize(mp6_conn_ctl->b_cont);
258 qreply(q, mp6_conn_ctl);
260 return (mp2ctl);
264 * Return 0 if invalid set request, 1 otherwise, including non-udp requests.
265 * NOTE: Per MIB-II, UDP has no writable data.
266 * TODO: If this ever actually tries to set anything, it needs to be
267 * to do the appropriate locking.
269 /* ARGSUSED */
271 udp_snmp_set(queue_t *q, t_scalar_t level, t_scalar_t name,
272 uchar_t *ptr, int len)
274 switch (level) {
275 case MIB2_UDP:
276 return (0);
277 default:
278 return (1);
282 void
283 udp_kstat_fini(netstackid_t stackid, kstat_t *ksp)
285 if (ksp != NULL) {
286 ASSERT(stackid == (netstackid_t)(uintptr_t)ksp->ks_private);
287 kstat_delete_netstack(ksp, stackid);
292 * To add stats from one mib2_udp_t to another. Static fields are not added.
293 * The caller should set them up propertly.
295 static void
296 udp_add_mib(mib2_udp_t *from, mib2_udp_t *to)
298 to->udpHCInDatagrams += from->udpHCInDatagrams;
299 to->udpInErrors += from->udpInErrors;
300 to->udpHCOutDatagrams += from->udpHCOutDatagrams;
301 to->udpOutErrors += from->udpOutErrors;
305 void *
306 udp_kstat2_init(netstackid_t stackid)
308 kstat_t *ksp;
310 udp_stat_t template = {
311 { "udp_sock_fallback", KSTAT_DATA_UINT64 },
312 { "udp_out_opt", KSTAT_DATA_UINT64 },
313 { "udp_out_err_notconn", KSTAT_DATA_UINT64 },
314 { "udp_out_err_output", KSTAT_DATA_UINT64 },
315 { "udp_out_err_tudr", KSTAT_DATA_UINT64 },
316 #ifdef DEBUG
317 { "udp_data_conn", KSTAT_DATA_UINT64 },
318 { "udp_data_notconn", KSTAT_DATA_UINT64 },
319 { "udp_out_lastdst", KSTAT_DATA_UINT64 },
320 { "udp_out_diffdst", KSTAT_DATA_UINT64 },
321 { "udp_out_ipv6", KSTAT_DATA_UINT64 },
322 { "udp_out_mapped", KSTAT_DATA_UINT64 },
323 { "udp_out_ipv4", KSTAT_DATA_UINT64 },
324 #endif
327 ksp = kstat_create_netstack(UDP_MOD_NAME, 0, "udpstat", "net",
328 KSTAT_TYPE_NAMED, sizeof (template) / sizeof (kstat_named_t),
329 0, stackid);
331 if (ksp == NULL)
332 return (NULL);
334 bcopy(&template, ksp->ks_data, sizeof (template));
335 ksp->ks_update = udp_kstat2_update;
336 ksp->ks_private = (void *)(uintptr_t)stackid;
338 kstat_install(ksp);
339 return (ksp);
342 void
343 udp_kstat2_fini(netstackid_t stackid, kstat_t *ksp)
345 if (ksp != NULL) {
346 ASSERT(stackid == (netstackid_t)(uintptr_t)ksp->ks_private);
347 kstat_delete_netstack(ksp, stackid);
352 * To copy counters from the per CPU udpp_stat_counter_t to the stack
353 * udp_stat_t.
355 static void
356 udp_add_stats(udp_stat_counter_t *from, udp_stat_t *to)
358 to->udp_sock_fallback.value.ui64 += from->udp_sock_fallback;
359 to->udp_out_opt.value.ui64 += from->udp_out_opt;
360 to->udp_out_err_notconn.value.ui64 += from->udp_out_err_notconn;
361 to->udp_out_err_output.value.ui64 += from->udp_out_err_output;
362 to->udp_out_err_tudr.value.ui64 += from->udp_out_err_tudr;
363 #ifdef DEBUG
364 to->udp_data_conn.value.ui64 += from->udp_data_conn;
365 to->udp_data_notconn.value.ui64 += from->udp_data_notconn;
366 to->udp_out_lastdst.value.ui64 += from->udp_out_lastdst;
367 to->udp_out_diffdst.value.ui64 += from->udp_out_diffdst;
368 to->udp_out_ipv6.value.ui64 += from->udp_out_ipv6;
369 to->udp_out_mapped.value.ui64 += from->udp_out_mapped;
370 to->udp_out_ipv4.value.ui64 += from->udp_out_ipv4;
371 #endif
375 * To set all udp_stat_t counters to 0.
377 static void
378 udp_clr_stats(udp_stat_t *stats)
380 stats->udp_sock_fallback.value.ui64 = 0;
381 stats->udp_out_opt.value.ui64 = 0;
382 stats->udp_out_err_notconn.value.ui64 = 0;
383 stats->udp_out_err_output.value.ui64 = 0;
384 stats->udp_out_err_tudr.value.ui64 = 0;
385 #ifdef DEBUG
386 stats->udp_data_conn.value.ui64 = 0;
387 stats->udp_data_notconn.value.ui64 = 0;
388 stats->udp_out_lastdst.value.ui64 = 0;
389 stats->udp_out_diffdst.value.ui64 = 0;
390 stats->udp_out_ipv6.value.ui64 = 0;
391 stats->udp_out_mapped.value.ui64 = 0;
392 stats->udp_out_ipv4.value.ui64 = 0;
393 #endif
397 udp_kstat2_update(kstat_t *kp, int rw)
399 udp_stat_t *stats;
400 netstackid_t stackid = (netstackid_t)(uintptr_t)kp->ks_private;
401 netstack_t *ns;
402 udp_stack_t *us;
403 int i;
404 int cnt;
406 if (rw == KSTAT_WRITE)
407 return (EACCES);
409 ns = netstack_find_by_stackid(stackid);
410 if (ns == NULL)
411 return (-1);
412 us = ns->netstack_udp;
413 if (us == NULL) {
414 netstack_rele(ns);
415 return (-1);
417 stats = (udp_stat_t *)kp->ks_data;
418 udp_clr_stats(stats);
420 cnt = us->us_sc_cnt;
421 for (i = 0; i < cnt; i++)
422 udp_add_stats(&us->us_sc[i]->udp_sc_stats, stats);
424 netstack_rele(ns);
425 return (0);
428 void *
429 udp_kstat_init(netstackid_t stackid)
431 kstat_t *ksp;
433 udp_named_kstat_t template = {
434 { "inDatagrams", KSTAT_DATA_UINT64, 0 },
435 { "inErrors", KSTAT_DATA_UINT32, 0 },
436 { "outDatagrams", KSTAT_DATA_UINT64, 0 },
437 { "entrySize", KSTAT_DATA_INT32, 0 },
438 { "entry6Size", KSTAT_DATA_INT32, 0 },
439 { "outErrors", KSTAT_DATA_UINT32, 0 },
442 ksp = kstat_create_netstack(UDP_MOD_NAME, 0, UDP_MOD_NAME, "mib2",
443 KSTAT_TYPE_NAMED, NUM_OF_FIELDS(udp_named_kstat_t), 0, stackid);
445 if (ksp == NULL)
446 return (NULL);
448 template.entrySize.value.ui32 = sizeof (mib2_udpEntry_t);
449 template.entry6Size.value.ui32 = sizeof (mib2_udp6Entry_t);
451 bcopy(&template, ksp->ks_data, sizeof (template));
452 ksp->ks_update = udp_kstat_update;
453 ksp->ks_private = (void *)(uintptr_t)stackid;
455 kstat_install(ksp);
456 return (ksp);
460 * To sum up all MIB2 stats for a udp_stack_t from all per CPU stats. The
461 * caller should initialize the target mib2_udp_t properly as this function
462 * just adds up all the per CPU stats.
464 static void
465 udp_sum_mib(udp_stack_t *us, mib2_udp_t *udp_mib)
467 int i;
468 int cnt;
470 cnt = us->us_sc_cnt;
471 for (i = 0; i < cnt; i++)
472 udp_add_mib(&us->us_sc[i]->udp_sc_mib, udp_mib);
475 static int
476 udp_kstat_update(kstat_t *kp, int rw)
478 udp_named_kstat_t *udpkp;
479 netstackid_t stackid = (netstackid_t)(uintptr_t)kp->ks_private;
480 netstack_t *ns;
481 udp_stack_t *us;
482 mib2_udp_t udp_mib;
484 if (rw == KSTAT_WRITE)
485 return (EACCES);
487 ns = netstack_find_by_stackid(stackid);
488 if (ns == NULL)
489 return (-1);
490 us = ns->netstack_udp;
491 if (us == NULL) {
492 netstack_rele(ns);
493 return (-1);
495 udpkp = (udp_named_kstat_t *)kp->ks_data;
497 bzero(&udp_mib, sizeof (udp_mib));
498 udp_sum_mib(us, &udp_mib);
500 udpkp->inDatagrams.value.ui64 = udp_mib.udpHCInDatagrams;
501 udpkp->inErrors.value.ui32 = udp_mib.udpInErrors;
502 udpkp->outDatagrams.value.ui64 = udp_mib.udpHCOutDatagrams;
503 udpkp->outErrors.value.ui32 = udp_mib.udpOutErrors;
504 netstack_rele(ns);
505 return (0);