]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/netstat/mroute.c
Fix size_t merge-o.
[FreeBSD/FreeBSD.git] / usr.bin / netstat / mroute.c
1 /*-
2  * Copyright (c) 1989 Stephen Deering
3  * Copyright (c) 1992, 1993
4  *      The Regents of the University of California.  All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * Stephen Deering of Stanford University.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed by the University of
20  *      California, Berkeley and its contributors.
21  * 4. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  *
37  *      @(#)mroute.c    8.2 (Berkeley) 4/28/95
38  */
39
40 #include <sys/cdefs.h>
41 __FBSDID("$FreeBSD$");
42
43 /*
44  * Print multicast routing structures and statistics.
45  *
46  * MROUTING 1.0
47  */
48
49 #include <sys/param.h>
50 #include <sys/queue.h>
51 #include <sys/socket.h>
52 #include <sys/socketvar.h>
53 #include <sys/sysctl.h>
54 #include <sys/protosw.h>
55 #include <sys/mbuf.h>
56 #include <sys/time.h>
57
58 #include <net/if.h>
59 #include <netinet/in.h>
60 #include <netinet/igmp.h>
61 #include <net/route.h>
62 #include <netinet/ip_mroute.h>
63
64 #include <err.h>
65 #include <stdint.h>
66 #include <stdio.h>
67 #include <stdlib.h>
68 #include "netstat.h"
69
70
71 static void     print_bw_meter(struct bw_meter *, int *);
72 static void     print_mfc(struct mfc *, int, int *);
73
74 static void
75 print_bw_meter(struct bw_meter *bw_meter, int *banner_printed)
76 {
77         char s0[256], s1[256], s2[256], s3[256];
78         struct timeval now, end, delta;
79
80         gettimeofday(&now, NULL);
81
82         if (! *banner_printed) {
83                 printf(" Bandwidth Meters\n");
84                 printf("  %-30s", "Measured(Start|Packets|Bytes)");
85                 printf(" %s", "Type");
86                 printf("  %-30s", "Thresh(Interval|Packets|Bytes)");
87                 printf(" Remain");
88                 printf("\n");
89                 *banner_printed = 1;
90         }
91
92         /* The measured values */
93         if (bw_meter->bm_flags & BW_METER_UNIT_PACKETS)
94                 sprintf(s1, "%ju", (uintmax_t)bw_meter->bm_measured.b_packets);
95         else
96                 sprintf(s1, "?");
97         if (bw_meter->bm_flags & BW_METER_UNIT_BYTES)
98                 sprintf(s2, "%ju", (uintmax_t)bw_meter->bm_measured.b_bytes);
99         else
100                 sprintf(s2, "?");
101         sprintf(s0, "%lu.%lu|%s|%s",
102                 (u_long)bw_meter->bm_start_time.tv_sec,
103                 (u_long)bw_meter->bm_start_time.tv_usec,
104                 s1, s2);
105         printf("  %-30s", s0);
106
107         /* The type of entry */
108         sprintf(s0, "%s", "?");
109         if (bw_meter->bm_flags & BW_METER_GEQ)
110                 sprintf(s0, "%s", ">=");
111         else if (bw_meter->bm_flags & BW_METER_LEQ)
112                 sprintf(s0, "%s", "<=");
113         printf("  %-3s", s0);
114
115         /* The threshold values */
116         if (bw_meter->bm_flags & BW_METER_UNIT_PACKETS)
117                 sprintf(s1, "%ju", (uintmax_t)bw_meter->bm_threshold.b_packets);
118         else
119                 sprintf(s1, "?");
120         if (bw_meter->bm_flags & BW_METER_UNIT_BYTES)
121                 sprintf(s2, "%ju", (uintmax_t)bw_meter->bm_threshold.b_bytes);
122         else
123                 sprintf(s2, "?");
124         sprintf(s0, "%lu.%lu|%s|%s",
125                 (u_long)bw_meter->bm_threshold.b_time.tv_sec,
126                 (u_long)bw_meter->bm_threshold.b_time.tv_usec,
127                 s1, s2);
128         printf("  %-30s", s0);
129
130         /* Remaining time */
131         timeradd(&bw_meter->bm_start_time,
132                  &bw_meter->bm_threshold.b_time, &end);
133         if (timercmp(&now, &end, <=)) {
134                 timersub(&end, &now, &delta);
135                 sprintf(s3, "%lu.%lu",
136                         (u_long)delta.tv_sec,
137                         (u_long)delta.tv_usec);
138         } else {
139                 /* Negative time */
140                 timersub(&now, &end, &delta);
141                 sprintf(s3, "-%lu.%lu",
142                         (u_long)delta.tv_sec,
143                         (u_long)delta.tv_usec);
144         }
145         printf(" %s", s3);
146
147         printf("\n");
148 }
149
150 static void
151 print_mfc(struct mfc *m, int maxvif, int *banner_printed)
152 {
153         struct bw_meter bw_meter, *bwm;
154         int bw_banner_printed;
155         int error;
156         vifi_t vifi;
157
158         bw_banner_printed = 0;
159
160         if (! *banner_printed) {
161                 printf("\nIPv4 Multicast Forwarding Table\n"
162                        " Origin          Group            "
163                        " Packets In-Vif  Out-Vifs:Ttls\n");
164                 *banner_printed = 1;
165         }
166
167         printf(" %-15.15s", routename(m->mfc_origin.s_addr));
168         printf(" %-15.15s", routename(m->mfc_mcastgrp.s_addr));
169         printf(" %9lu", m->mfc_pkt_cnt);
170         printf("  %3d   ", m->mfc_parent);
171         for (vifi = 0; vifi <= maxvif; vifi++) {
172                 if (m->mfc_ttls[vifi] > 0)
173                         printf(" %u:%u", vifi, m->mfc_ttls[vifi]);
174         }
175         printf("\n");
176
177         /*
178          * XXX We break the rules and try to use KVM to read the
179          * bandwidth meters, they are not retrievable via sysctl yet.
180          */
181         bwm = m->mfc_bw_meter;
182         while (bwm != NULL) {
183                 error = kread((u_long)bwm, (char *)&bw_meter,
184                     sizeof(bw_meter));
185                 if (error)
186                         break;
187                 print_bw_meter(&bw_meter, &bw_banner_printed);
188                 bwm = bw_meter.bm_mfc_next;
189         }
190 }
191
192 void
193 mroutepr(u_long pmfchashtbl, u_long pmfctablesize, u_long pviftbl)
194 {
195         struct vif viftable[MAXVIFS];
196         struct vif *v;
197         struct mfc *m;
198         int banner_printed;
199         int saved_numeric_addr;
200         size_t len;
201         vifi_t vifi, maxvif;
202
203         saved_numeric_addr = numeric_addr;
204         numeric_addr = 1;
205
206         /*
207          * TODO:
208          * The VIF table will move to hanging off the struct if_info for
209          * each IPv4 configured interface. Currently it is statically
210          * allocated, and retrieved either using KVM or an opaque SYSCTL.
211          *
212          * This can't happen until the API documented in multicast(4)
213          * is itself refactored. The historical reason why VIFs use
214          * a separate ifindex space is entirely due to the legacy
215          * capability of the MROUTING code to create IPIP tunnels on
216          * the fly to support DVMRP. When gif(4) became available, this
217          * functionality was deprecated, as PIM does not use it.
218          */
219         maxvif = 0;
220
221         len = sizeof(viftable);
222         if (live) {
223                 if (sysctlbyname("net.inet.ip.viftable", viftable, &len, NULL,
224                     0) < 0) {
225                         warn("sysctl: net.inet.ip.viftable");
226                         return;
227                 }
228         } else
229                 kread(pviftbl, (char *)viftable, sizeof(viftable));
230
231         banner_printed = 0;
232         for (vifi = 0, v = viftable; vifi < MAXVIFS; ++vifi, ++v) {
233                 if (v->v_lcl_addr.s_addr == 0)
234                         continue;
235
236                 maxvif = vifi;
237                 if (!banner_printed) {
238                         printf("\nIPv4 Virtual Interface Table\n"
239                                " Vif   Thresh   Local-Address   "
240                                "Remote-Address    Pkts-In   Pkts-Out\n");
241                         banner_printed = 1;
242                 }
243
244                 printf(" %2u    %6u   %-15.15s",
245                                         /* opposite math of add_vif() */
246                     vifi, v->v_threshold,
247                     routename(v->v_lcl_addr.s_addr));
248                 printf(" %-15.15s", (v->v_flags & VIFF_TUNNEL) ?
249                     routename(v->v_rmt_addr.s_addr) : "");
250
251                 printf(" %9lu  %9lu\n", v->v_pkt_in, v->v_pkt_out);
252         }
253         if (!banner_printed)
254                 printf("\nIPv4 Virtual Interface Table is empty\n");
255
256         banner_printed = 0;
257
258         /*
259          * TODO:
260          * The MFC table will move into the AF_INET radix trie in future.
261          * In 8.x, it becomes a dynamically allocated structure referenced
262          * by a hashed LIST, allowing more than 256 entries w/o kernel tuning.
263          *
264          * If retrieved via opaque SYSCTL, the kernel will coalesce it into
265          * a static table for us.
266          * If retrieved via KVM, the hash list pointers must be followed.
267          */
268         if (live) {
269                 struct mfc *mfctable;
270
271                 len = 0;
272                 if (sysctlbyname("net.inet.ip.mfctable", NULL, &len, NULL,
273                     0) < 0) {
274                         warn("sysctl: net.inet.ip.mfctable");
275                         return;
276                 }
277
278                 mfctable = malloc(len);
279                 if (mfctable == NULL) {
280                         warnx("malloc %lu bytes", (u_long)len);
281                         return;
282                 }
283                 if (sysctlbyname("net.inet.ip.mfctable", mfctable, &len, NULL,
284                     0) < 0) {
285                         free(mfctable);
286                         warn("sysctl: net.inet.ip.mfctable");
287                         return;
288                 }
289
290                 m = mfctable;
291                 while (len >= sizeof(*m)) {
292                         print_mfc(m++, maxvif, &banner_printed);
293                         len -= sizeof(*m);
294                 }
295                 if (len != 0)
296                         warnx("print_mfc: %lu trailing bytes", (u_long)len);
297
298                 free(mfctable);
299         } else {
300                 LIST_HEAD(, mfc) *mfchashtbl;
301                 u_long i, mfctablesize;
302                 struct mfc mfc;
303                 int error;
304
305                 error = kread(pmfctablesize, (char *)&mfctablesize,
306                     sizeof(u_long));
307                 if (error) {
308                         warn("kread: mfctablesize");
309                         return;
310                 }
311
312                 len = sizeof(*mfchashtbl) * mfctablesize;
313                 mfchashtbl = malloc(len);
314                 if (mfchashtbl == NULL) {
315                         warnx("malloc %lu bytes", (u_long)len);
316                         return;
317                 }
318                 kread(pmfchashtbl, (char *)&mfchashtbl, len);
319
320                 for (i = 0; i < mfctablesize; i++) {
321                         LIST_FOREACH(m, &mfchashtbl[i], mfc_hash) {
322                                 kread((u_long)m, (char *)&mfc, sizeof(mfc));
323                                 print_mfc(m, maxvif, &banner_printed);
324                         }
325                 }
326
327                 free(mfchashtbl);
328         }
329
330         if (!banner_printed)
331                 printf("\nIPv4 Multicast Forwarding Table is empty\n");
332
333         printf("\n");
334         numeric_addr = saved_numeric_addr;
335 }
336
337 void
338 mrt_stats(u_long mstaddr)
339 {
340         struct mrtstat mrtstat;
341         size_t len = sizeof mrtstat;
342
343         if (live) {
344                 if (sysctlbyname("net.inet.ip.mrtstat", &mrtstat, &len, NULL,
345                     0) < 0) {
346                         warn("sysctl: net.inet.ip.mrtstat");
347                         return;
348                 }
349         } else
350                 kread(mstaddr, (char *)&mrtstat, sizeof(mrtstat));
351
352         printf("IPv4 multicast forwarding:\n");
353
354 #define p(f, m) if (mrtstat.f || sflag <= 1) \
355         printf(m, mrtstat.f, plural(mrtstat.f))
356 #define p2(f, m) if (mrtstat.f || sflag <= 1) \
357         printf(m, mrtstat.f, plurales(mrtstat.f))
358
359         p(mrts_mfc_lookups, "\t%lu multicast forwarding cache lookup%s\n");
360         p2(mrts_mfc_misses, "\t%lu multicast forwarding cache miss%s\n");
361         p(mrts_upcalls, "\t%lu upcall%s to multicast routing daemon\n");
362         p(mrts_upq_ovflw, "\t%lu upcall queue overflow%s\n");
363         p(mrts_upq_sockfull,
364             "\t%lu upcall%s dropped due to full socket buffer\n");
365         p(mrts_cache_cleanups, "\t%lu cache cleanup%s\n");
366         p(mrts_no_route, "\t%lu datagram%s with no route for origin\n");
367         p(mrts_bad_tunnel, "\t%lu datagram%s arrived with bad tunneling\n");
368         p(mrts_cant_tunnel, "\t%lu datagram%s could not be tunneled\n");
369         p(mrts_wrong_if, "\t%lu datagram%s arrived on wrong interface\n");
370         p(mrts_drop_sel, "\t%lu datagram%s selectively dropped\n");
371         p(mrts_q_overflow, "\t%lu datagram%s dropped due to queue overflow\n");
372         p(mrts_pkt2large, "\t%lu datagram%s dropped for being too large\n");
373
374 #undef  p2
375 #undef  p
376 }