xref: /openbsd-src/usr.bin/netstat/mroute.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: mroute.c,v 1.18 2009/02/07 15:06:04 chl Exp $	*/
2 /*	$NetBSD: mroute.c,v 1.10 1996/05/11 13:51:27 mycroft Exp $	*/
3 
4 /*
5  * Copyright (c) 1989 Stephen Deering
6  * Copyright (c) 1992, 1993
7  *	The Regents of the University of California.  All rights reserved.
8  *
9  * This code is derived from software contributed to Berkeley by
10  * Stephen Deering of Stanford University.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  *	from: @(#)mroute.c	8.1 (Berkeley) 6/6/93
37  */
38 
39 /*
40  * Print multicast routing structures and statistics.
41  *
42  * MROUTING 1.0
43  */
44 
45 #include <sys/param.h>
46 #include <sys/socket.h>
47 #include <sys/socketvar.h>
48 #include <sys/protosw.h>
49 #include <sys/sysctl.h>
50 
51 #include <net/if.h>
52 #include <net/route.h>
53 #include <netinet/in.h>
54 #include <netinet/igmp.h>
55 #define _KERNEL
56 #include <netinet/ip_mroute.h>
57 #undef _KERNEL
58 
59 #include <err.h>
60 #include <errno.h>
61 #include <limits.h>
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include "netstat.h"
65 
66 static void print_bw_meter(struct bw_meter *bw_meter, int *banner_printed);
67 
68 static char *
69 pktscale(u_long n)
70 {
71 	static char buf[8];
72 	char t;
73 
74 	if (n < 1024)
75 		t = ' ';
76 	else if (n < 1024 * 1024) {
77 		t = 'k';
78 		n /= 1024;
79 	} else {
80 		t = 'm';
81 		n /= 1048576;
82 	}
83 
84 	snprintf(buf, sizeof buf, "%lu%c", n, t);
85 	return (buf);
86 }
87 
88 void
89 mroutepr(u_long mfchashtbladdr, u_long mfchashaddr, u_long vifaddr)
90 {
91 	u_int mrtproto;
92 	LIST_HEAD(, mfc) *mfchashtbl;
93 	u_long mfchash;
94 	struct vif viftable[MAXVIFS], *v;
95 	struct mfc *mfcp, mfc;
96 	vifi_t vifi;
97 	int mib[] = { CTL_NET, AF_INET, IPPROTO_IP, IPCTL_MRTPROTO };
98 	size_t len = sizeof(int);
99 	int i, banner_printed = 0, saved_nflag, numvifs = 0;
100 	int nmfc;		/* No. of cache entries */
101 
102 	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]),
103 	    &mrtproto, &len, NULL, 0) == -1) {
104 		if (errno != ENOPROTOOPT)
105 			warn("mroute");
106 		return;
107 	}
108 	switch (mrtproto) {
109 	case 0:
110 		printf("no multicast routing compiled into this system\n");
111 		return;
112 	case IGMP_DVMRP:
113 		break;
114 	default:
115 		printf("multicast routing protocol %u, unknown\n", mrtproto);
116 		return;
117 	}
118 
119 	if (mfchashtbladdr == 0) {
120 		printf("mfchashtbl: symbol not in namelist\n");
121 		return;
122 	}
123 	if (mfchashaddr == 0) {
124 		printf("mfchash: symbol not in namelist\n");
125 		return;
126 	}
127 	if (vifaddr == 0) {
128 		printf("viftable: symbol not in namelist\n");
129 		return;
130 	}
131 
132 	saved_nflag = nflag;
133 	nflag = 1;
134 
135 	kread(vifaddr, &viftable, sizeof(viftable));
136 
137 	for (vifi = 0, v = viftable; vifi < MAXVIFS; ++vifi, ++v) {
138 		if (v->v_lcl_addr.s_addr == 0)
139 			continue;
140 		numvifs = vifi;
141 
142 		if (!banner_printed) {
143 			printf("\nVirtual Interface Table\n %s%s",
144 			    "Vif  Thresh  Limit  Local-Address    ",
145 			    "Remote-Address   Pkt_in  Pkt_out\n");
146 			banner_printed = 1;
147 		}
148 
149 		printf(" %3u     %3u  %5u  %-15.15s",
150 		    vifi, v->v_threshold, v->v_rate_limit,
151 		    routename4(v->v_lcl_addr.s_addr));
152 		printf("  %-15.15s  %6lu  %7lu\n", (v->v_flags & VIFF_TUNNEL) ?
153 		    routename4(v->v_rmt_addr.s_addr) : "",
154 		    v->v_pkt_in, v->v_pkt_out);
155 	}
156 	if (!banner_printed)
157 		printf("Virtual Interface Table is empty\n");
158 
159 	kread(mfchashtbladdr, &mfchashtbl, sizeof(mfchashtbl));
160 	kread(mfchashaddr, &mfchash, sizeof(mfchash));
161 	banner_printed = 0;
162 	nmfc = 0;
163 
164 	if (mfchashtbl != 0)
165 		for (i = 0; i <= mfchash; ++i) {
166 			kread((u_long)&mfchashtbl[i], &mfcp, sizeof(mfcp));
167 
168 			for (; mfcp != 0; mfcp = LIST_NEXT(&mfc, mfc_hash)) {
169 				if (!banner_printed) {
170 					printf("\nMulticast Forwarding Cache\n %s%s",
171 					    "Hash  Origin           Mcastgroup       ",
172 					    "Traffic  In-Vif  Out-Vifs/Forw-ttl\n");
173 					banner_printed = 1;
174 				}
175 
176 				kread((u_long)mfcp, &mfc, sizeof(mfc));
177 				printf("  %3u  %-15.15s",
178 				    i, routename4(mfc.mfc_origin.s_addr));
179 				printf("  %-15.15s  %7s     %3u ",
180 				    routename4(mfc.mfc_mcastgrp.s_addr),
181 				    pktscale(mfc.mfc_pkt_cnt), mfc.mfc_parent);
182 				for (vifi = 0; vifi <= numvifs; ++vifi)
183 					if (mfc.mfc_ttls[vifi])
184 						printf(" %u/%u", vifi,
185 						    mfc.mfc_ttls[vifi]);
186 
187 				printf("\n");
188 
189 				/* Print the bw meter information */
190 				{
191 					struct bw_meter bw_meter, *bwm;
192 					int banner_printed2 = 0;
193 
194 					bwm = mfc.mfc_bw_meter;
195 					while (bwm) {
196 						kread((u_long)bwm,
197 						    &bw_meter,
198 						    sizeof bw_meter);
199 						print_bw_meter(&bw_meter,
200 						    &banner_printed2);
201 						bwm = bw_meter.bm_mfc_next;
202 					}
203 #if 0	/* Don't ever print it? */
204 					if (! banner_printed2)
205 						printf("\n  No Bandwidth Meters\n");
206 #endif
207 				}
208 
209 				nmfc++;
210 			}
211 		}
212 	if (!banner_printed)
213 		printf("Multicast Forwarding Cache is empty\n");
214 	else
215 		printf("\nTotal no. of entries in cache: %d\n", nmfc);
216 
217 	printf("\n");
218 	nflag = saved_nflag;
219 }
220 
221 static void
222 print_bw_meter(struct bw_meter *bw_meter, int *banner_printed)
223 {
224 	char s0[256], s1[256], s2[256], s3[256];
225 	struct timeval now, end, delta;
226 
227 	gettimeofday(&now, NULL);
228 
229 	if (! *banner_printed) {
230 		printf(" Bandwidth Meters\n");
231 		printf("  %-30s", "Measured(Start|Packets|Bytes)");
232 		printf(" %s", "Type");
233 		printf("  %-30s", "Thresh(Interval|Packets|Bytes)");
234 		printf(" Remain");
235 		printf("\n");
236 		*banner_printed = 1;
237 	}
238 
239 	/* The measured values */
240 	if (bw_meter->bm_flags & BW_METER_UNIT_PACKETS)
241 		snprintf(s1, sizeof s1, "%llu",
242 			 bw_meter->bm_measured.b_packets);
243 	else
244 		snprintf(s1, sizeof s1, "?");
245 	if (bw_meter->bm_flags & BW_METER_UNIT_BYTES)
246 		snprintf(s2, sizeof s2, "%llu", bw_meter->bm_measured.b_bytes);
247 	else
248 		snprintf(s2, sizeof s2, "?");
249 	snprintf(s0, sizeof s0, "%lu.%lu|%s|%s",
250 		 bw_meter->bm_start_time.tv_sec,
251 		 bw_meter->bm_start_time.tv_usec,
252 		 s1, s2);
253 	printf("  %-30s", s0);
254 
255 	/* The type of entry */
256 	snprintf(s0, sizeof s0, "%s", "?");
257 	if (bw_meter->bm_flags & BW_METER_GEQ)
258 		snprintf(s0, sizeof s0, "%s", ">=");
259 	else if (bw_meter->bm_flags & BW_METER_LEQ)
260 		snprintf(s0, sizeof s0, "%s", "<=");
261 	printf("  %-3s", s0);
262 
263 	/* The threshold values */
264 	if (bw_meter->bm_flags & BW_METER_UNIT_PACKETS)
265 		snprintf(s1, sizeof s1, "%llu",
266 			 bw_meter->bm_threshold.b_packets);
267 	else
268 		snprintf(s1, sizeof s1, "?");
269 	if (bw_meter->bm_flags & BW_METER_UNIT_BYTES)
270 		snprintf(s2, sizeof s2, "%llu",
271 			 bw_meter->bm_threshold.b_bytes);
272 	else
273 		snprintf(s2, sizeof s2, "?");
274 	snprintf(s0, sizeof s0, "%lu.%lu|%s|%s",
275 		 bw_meter->bm_threshold.b_time.tv_sec,
276 		 bw_meter->bm_threshold.b_time.tv_usec,
277 		 s1, s2);
278 	printf("  %-30s", s0);
279 
280 	/* Remaining time */
281 	timeradd(&bw_meter->bm_start_time,
282 		 &bw_meter->bm_threshold.b_time, &end);
283 	if (timercmp(&now, &end, <=)) {
284 		timersub(&end, &now, &delta);
285 		snprintf(s3, sizeof s3, "%lu.%lu",
286 			 delta.tv_sec, delta.tv_usec);
287 	} else {
288 		/* Negative time */
289 		timersub(&now, &end, &delta);
290 		snprintf(s3, sizeof s3, "-%lu.%lu",
291 			 delta.tv_sec, delta.tv_usec);
292 	}
293 	printf(" %s", s3);
294 
295 	printf("\n");
296 }
297 
298 void
299 mrt_stats(void)
300 {
301 	u_int mrtproto;
302 	struct mrtstat mrtstat;
303 	int mib[] = { CTL_NET, AF_INET, IPPROTO_IP, IPCTL_MRTPROTO };
304 	int mib2[] = { CTL_NET, AF_INET, IPPROTO_IP, IPCTL_MRTSTATS };
305 	size_t len = sizeof(int);
306 
307 	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]),
308 	    &mrtproto, &len, NULL, 0) == -1) {
309 		if (errno != ENOPROTOOPT)
310 			warn("mroute");
311 		return;
312 	}
313 	switch (mrtproto) {
314 	case 0:
315 		printf("no multicast routing compiled into this system\n");
316 		return;
317 
318 	case IGMP_DVMRP:
319 		break;
320 
321 	default:
322 		printf("multicast routing protocol %u, unknown\n", mrtproto);
323 		return;
324 	}
325 
326 	len = sizeof(mrtstat);
327 	if (sysctl(mib2, sizeof(mib2) / sizeof(mib2[0]),
328 	    &mrtstat, &len, NULL, 0) == -1) {
329 		if (errno != ENOPROTOOPT)
330 			warn("mroute");
331 		return;
332 	}
333 
334 	printf("multicast routing:\n");
335 	printf("\t%lu datagram%s with no route for origin\n",
336 	    mrtstat.mrts_no_route, plural(mrtstat.mrts_no_route));
337 	printf("\t%lu upcall%s made to mrouted\n",
338 	    mrtstat.mrts_upcalls, plural(mrtstat.mrts_upcalls));
339 	printf("\t%lu datagram%s with malformed tunnel options\n",
340 	    mrtstat.mrts_bad_tunnel, plural(mrtstat.mrts_bad_tunnel));
341 	printf("\t%lu datagram%s with no room for tunnel options\n",
342 	    mrtstat.mrts_cant_tunnel, plural(mrtstat.mrts_cant_tunnel));
343 	printf("\t%lu datagram%s arrived on wrong interface\n",
344 	    mrtstat.mrts_wrong_if, plural(mrtstat.mrts_wrong_if));
345 	printf("\t%lu datagram%s dropped due to upcall Q overflow\n",
346 	    mrtstat.mrts_upq_ovflw, plural(mrtstat.mrts_upq_ovflw));
347 	printf("\t%lu datagram%s dropped due to upcall socket overflow\n",
348 	    mrtstat.mrts_upq_sockfull, plural(mrtstat.mrts_upq_sockfull));
349 	printf("\t%lu datagram%s cleaned up by the cache\n",
350 	    mrtstat.mrts_cache_cleanups, plural(mrtstat.mrts_cache_cleanups));
351 	printf("\t%lu datagram%s dropped selectively by ratelimiter\n",
352 	    mrtstat.mrts_drop_sel, plural(mrtstat.mrts_drop_sel));
353 	printf("\t%lu datagram%s dropped - bucket Q overflow\n",
354 	    mrtstat.mrts_q_overflow, plural(mrtstat.mrts_q_overflow));
355 	printf("\t%lu datagram%s dropped - larger than bkt size\n",
356 	    mrtstat.mrts_pkt2large, plural(mrtstat.mrts_pkt2large));
357 }
358