]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - usr.bin/netstat/mroute.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.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
63 #define _KERNEL 1
64 #include <netinet/ip_mroute.h>
65 #undef _KERNEL
66
67 #include <err.h>
68 #include <nlist.h>
69 #include <stdint.h>
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include "netstat.h"
73
74 /*
75  * kvm(3) bindings for every needed symbol
76  */
77 static struct nlist mrl[] = {
78 #define N_MRTSTAT       0
79         { .n_name = "_mrtstat" },
80 #define N_MFCHASHTBL    1
81         { .n_name = "_mfchashtbl" },
82 #define N_VIFTABLE      2
83         { .n_name = "_viftable" },
84 #define N_MFCTABLESIZE  3
85         { .n_name = "_mfctablesize" },
86         { .n_name = NULL },
87 };
88
89 static void     print_bw_meter(struct bw_meter *, int *);
90 static void     print_mfc(struct mfc *, int, int *);
91
92 static void
93 print_bw_meter(struct bw_meter *bw_meter, int *banner_printed)
94 {
95         char s0[256], s1[256], s2[256], s3[256];
96         struct timeval now, end, delta;
97
98         gettimeofday(&now, NULL);
99
100         if (! *banner_printed) {
101                 printf(" Bandwidth Meters\n");
102                 printf("  %-30s", "Measured(Start|Packets|Bytes)");
103                 printf(" %s", "Type");
104                 printf("  %-30s", "Thresh(Interval|Packets|Bytes)");
105                 printf(" Remain");
106                 printf("\n");
107                 *banner_printed = 1;
108         }
109
110         /* The measured values */
111         if (bw_meter->bm_flags & BW_METER_UNIT_PACKETS)
112                 sprintf(s1, "%ju", (uintmax_t)bw_meter->bm_measured.b_packets);
113         else
114                 sprintf(s1, "?");
115         if (bw_meter->bm_flags & BW_METER_UNIT_BYTES)
116                 sprintf(s2, "%ju", (uintmax_t)bw_meter->bm_measured.b_bytes);
117         else
118                 sprintf(s2, "?");
119         sprintf(s0, "%lu.%lu|%s|%s",
120                 (u_long)bw_meter->bm_start_time.tv_sec,
121                 (u_long)bw_meter->bm_start_time.tv_usec,
122                 s1, s2);
123         printf("  %-30s", s0);
124
125         /* The type of entry */
126         sprintf(s0, "%s", "?");
127         if (bw_meter->bm_flags & BW_METER_GEQ)
128                 sprintf(s0, "%s", ">=");
129         else if (bw_meter->bm_flags & BW_METER_LEQ)
130                 sprintf(s0, "%s", "<=");
131         printf("  %-3s", s0);
132
133         /* The threshold values */
134         if (bw_meter->bm_flags & BW_METER_UNIT_PACKETS)
135                 sprintf(s1, "%ju", (uintmax_t)bw_meter->bm_threshold.b_packets);
136         else
137                 sprintf(s1, "?");
138         if (bw_meter->bm_flags & BW_METER_UNIT_BYTES)
139                 sprintf(s2, "%ju", (uintmax_t)bw_meter->bm_threshold.b_bytes);
140         else
141                 sprintf(s2, "?");
142         sprintf(s0, "%lu.%lu|%s|%s",
143                 (u_long)bw_meter->bm_threshold.b_time.tv_sec,
144                 (u_long)bw_meter->bm_threshold.b_time.tv_usec,
145                 s1, s2);
146         printf("  %-30s", s0);
147
148         /* Remaining time */
149         timeradd(&bw_meter->bm_start_time,
150                  &bw_meter->bm_threshold.b_time, &end);
151         if (timercmp(&now, &end, <=)) {
152                 timersub(&end, &now, &delta);
153                 sprintf(s3, "%lu.%lu",
154                         (u_long)delta.tv_sec,
155                         (u_long)delta.tv_usec);
156         } else {
157                 /* Negative time */
158                 timersub(&now, &end, &delta);
159                 sprintf(s3, "-%lu.%lu",
160                         (u_long)delta.tv_sec,
161                         (u_long)delta.tv_usec);
162         }
163         printf(" %s", s3);
164
165         printf("\n");
166 }
167
168 static void
169 print_mfc(struct mfc *m, int maxvif, int *banner_printed)
170 {
171         struct bw_meter bw_meter, *bwm;
172         int bw_banner_printed;
173         int error;
174         vifi_t vifi;
175
176         bw_banner_printed = 0;
177
178         if (! *banner_printed) {
179                 printf("\nIPv4 Multicast Forwarding Table\n"
180                        " Origin          Group            "
181                        " Packets In-Vif  Out-Vifs:Ttls\n");
182                 *banner_printed = 1;
183         }
184
185         printf(" %-15.15s", routename(m->mfc_origin.s_addr));
186         printf(" %-15.15s", routename(m->mfc_mcastgrp.s_addr));
187         printf(" %9lu", m->mfc_pkt_cnt);
188         printf("  %3d   ", m->mfc_parent);
189         for (vifi = 0; vifi <= maxvif; vifi++) {
190                 if (m->mfc_ttls[vifi] > 0)
191                         printf(" %u:%u", vifi, m->mfc_ttls[vifi]);
192         }
193         printf("\n");
194
195         /*
196          * XXX We break the rules and try to use KVM to read the
197          * bandwidth meters, they are not retrievable via sysctl yet.
198          */
199         bwm = m->mfc_bw_meter;
200         while (bwm != NULL) {
201                 error = kread((u_long)bwm, (char *)&bw_meter,
202                     sizeof(bw_meter));
203                 if (error)
204                         break;
205                 print_bw_meter(&bw_meter, &bw_banner_printed);
206                 bwm = bw_meter.bm_mfc_next;
207         }
208 }
209
210 void
211 mroutepr()
212 {
213         struct vif viftable[MAXVIFS];
214         struct vif *v;
215         struct mfc *m;
216         u_long pmfchashtbl, pmfctablesize, pviftbl;
217         int banner_printed;
218         int saved_numeric_addr;
219         size_t len;
220         vifi_t vifi, maxvif;
221
222         saved_numeric_addr = numeric_addr;
223         numeric_addr = 1;
224
225         /*
226          * TODO:
227          * The VIF table will move to hanging off the struct if_info for
228          * each IPv4 configured interface. Currently it is statically
229          * allocated, and retrieved either using KVM or an opaque SYSCTL.
230          *
231          * This can't happen until the API documented in multicast(4)
232          * is itself refactored. The historical reason why VIFs use
233          * a separate ifindex space is entirely due to the legacy
234          * capability of the MROUTING code to create IPIP tunnels on
235          * the fly to support DVMRP. When gif(4) became available, this
236          * functionality was deprecated, as PIM does not use it.
237          */
238         maxvif = 0;
239         pmfchashtbl = pmfctablesize = pviftbl = 0;
240
241         len = sizeof(viftable);
242         if (live) {
243                 if (sysctlbyname("net.inet.ip.viftable", viftable, &len, NULL,
244                     0) < 0) {
245                         warn("sysctl: net.inet.ip.viftable");
246                         return;
247                 }
248         } else {
249                 kresolve_list(mrl);
250                 pmfchashtbl = mrl[N_MFCHASHTBL].n_value;
251                 pmfctablesize = mrl[N_MFCTABLESIZE].n_value;
252                 pviftbl = mrl[N_VIFTABLE].n_value;
253
254                 if (pmfchashtbl == 0 || pmfctablesize == 0 || pviftbl == 0) {
255                         fprintf(stderr, "No IPv4 MROUTING kernel support.\n");
256                         return;
257                 }
258
259                 kread(pviftbl, (char *)viftable, sizeof(viftable));
260         }
261
262         banner_printed = 0;
263         for (vifi = 0, v = viftable; vifi < MAXVIFS; ++vifi, ++v) {
264                 if (v->v_lcl_addr.s_addr == 0)
265                         continue;
266
267                 maxvif = vifi;
268                 if (!banner_printed) {
269                         printf("\nIPv4 Virtual Interface Table\n"
270                                " Vif   Thresh   Local-Address   "
271                                "Remote-Address    Pkts-In   Pkts-Out\n");
272                         banner_printed = 1;
273                 }
274
275                 printf(" %2u    %6u   %-15.15s",
276                                         /* opposite math of add_vif() */
277                     vifi, v->v_threshold,
278                     routename(v->v_lcl_addr.s_addr));
279                 printf(" %-15.15s", (v->v_flags & VIFF_TUNNEL) ?
280                     routename(v->v_rmt_addr.s_addr) : "");
281
282                 printf(" %9lu  %9lu\n", v->v_pkt_in, v->v_pkt_out);
283         }
284         if (!banner_printed)
285                 printf("\nIPv4 Virtual Interface Table is empty\n");
286
287         banner_printed = 0;
288
289         /*
290          * TODO:
291          * The MFC table will move into the AF_INET radix trie in future.
292          * In 8.x, it becomes a dynamically allocated structure referenced
293          * by a hashed LIST, allowing more than 256 entries w/o kernel tuning.
294          *
295          * If retrieved via opaque SYSCTL, the kernel will coalesce it into
296          * a static table for us.
297          * If retrieved via KVM, the hash list pointers must be followed.
298          */
299         if (live) {
300                 struct mfc *mfctable;
301
302                 len = 0;
303                 if (sysctlbyname("net.inet.ip.mfctable", NULL, &len, NULL,
304                     0) < 0) {
305                         warn("sysctl: net.inet.ip.mfctable");
306                         return;
307                 }
308
309                 mfctable = malloc(len);
310                 if (mfctable == NULL) {
311                         warnx("malloc %lu bytes", (u_long)len);
312                         return;
313                 }
314                 if (sysctlbyname("net.inet.ip.mfctable", mfctable, &len, NULL,
315                     0) < 0) {
316                         free(mfctable);
317                         warn("sysctl: net.inet.ip.mfctable");
318                         return;
319                 }
320
321                 m = mfctable;
322                 while (len >= sizeof(*m)) {
323                         print_mfc(m++, maxvif, &banner_printed);
324                         len -= sizeof(*m);
325                 }
326                 if (len != 0)
327                         warnx("print_mfc: %lu trailing bytes", (u_long)len);
328
329                 free(mfctable);
330         } else {
331                 LIST_HEAD(, mfc) *mfchashtbl;
332                 u_long i, mfctablesize;
333                 struct mfc mfc;
334                 int error;
335
336                 error = kread(pmfctablesize, (char *)&mfctablesize,
337                     sizeof(u_long));
338                 if (error) {
339                         warn("kread: mfctablesize");
340                         return;
341                 }
342
343                 len = sizeof(*mfchashtbl) * mfctablesize;
344                 mfchashtbl = malloc(len);
345                 if (mfchashtbl == NULL) {
346                         warnx("malloc %lu bytes", (u_long)len);
347                         return;
348                 }
349                 kread(pmfchashtbl, (char *)&mfchashtbl, len);
350
351                 for (i = 0; i < mfctablesize; i++) {
352                         LIST_FOREACH(m, &mfchashtbl[i], mfc_hash) {
353                                 kread((u_long)m, (char *)&mfc, sizeof(mfc));
354                                 print_mfc(m, maxvif, &banner_printed);
355                         }
356                 }
357
358                 free(mfchashtbl);
359         }
360
361         if (!banner_printed)
362                 printf("\nIPv4 Multicast Forwarding Table is empty\n");
363
364         printf("\n");
365         numeric_addr = saved_numeric_addr;
366 }
367
368 void
369 mrt_stats()
370 {
371         struct mrtstat mrtstat;
372         u_long mstaddr;
373         size_t len = sizeof(mrtstat);
374
375         kresolve_list(mrl);
376         mstaddr = mrl[N_MRTSTAT].n_value;
377
378         if (mstaddr == 0) {
379                 fprintf(stderr, "No IPv4 MROUTING kernel support.\n");
380                 return;
381         }
382
383         if (live) {
384                 if (sysctlbyname("net.inet.ip.mrtstat", &mrtstat, &len, NULL,
385                     0) < 0) {
386                         warn("sysctl: net.inet.ip.mrtstat failed.");
387                         return;
388                 }
389         } else
390                 kread_counters(mstaddr, &mrtstat, len);
391
392         printf("IPv4 multicast forwarding:\n");
393
394 #define p(f, m) if (mrtstat.f || sflag <= 1) \
395         printf(m, (uintmax_t)mrtstat.f, plural(mrtstat.f))
396 #define p2(f, m) if (mrtstat.f || sflag <= 1) \
397         printf(m, (uintmax_t)mrtstat.f, plurales(mrtstat.f))
398
399         p(mrts_mfc_lookups, "\t%ju multicast forwarding cache lookup%s\n");
400         p2(mrts_mfc_misses, "\t%ju multicast forwarding cache miss%s\n");
401         p(mrts_upcalls, "\t%ju upcall%s to multicast routing daemon\n");
402         p(mrts_upq_ovflw, "\t%ju upcall queue overflow%s\n");
403         p(mrts_upq_sockfull,
404             "\t%ju upcall%s dropped due to full socket buffer\n");
405         p(mrts_cache_cleanups, "\t%ju cache cleanup%s\n");
406         p(mrts_no_route, "\t%ju datagram%s with no route for origin\n");
407         p(mrts_bad_tunnel, "\t%ju datagram%s arrived with bad tunneling\n");
408         p(mrts_cant_tunnel, "\t%ju datagram%s could not be tunneled\n");
409         p(mrts_wrong_if, "\t%ju datagram%s arrived on wrong interface\n");
410         p(mrts_drop_sel, "\t%ju datagram%s selectively dropped\n");
411         p(mrts_q_overflow, "\t%ju datagram%s dropped due to queue overflow\n");
412         p(mrts_pkt2large, "\t%ju datagram%s dropped for being too large\n");
413
414 #undef  p2
415 #undef  p
416 }