1175061Sobrien/*-
21590Srgrimes * Copyright (c) 1989 Stephen Deering
31590Srgrimes * Copyright (c) 1992, 1993
41590Srgrimes *	The Regents of the University of California.  All rights reserved.
51590Srgrimes *
61590Srgrimes * This code is derived from software contributed to Berkeley by
71590Srgrimes * Stephen Deering of Stanford University.
81590Srgrimes *
91590Srgrimes * Redistribution and use in source and binary forms, with or without
101590Srgrimes * modification, are permitted provided that the following conditions
111590Srgrimes * are met:
121590Srgrimes * 1. Redistributions of source code must retain the above copyright
131590Srgrimes *    notice, this list of conditions and the following disclaimer.
141590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
151590Srgrimes *    notice, this list of conditions and the following disclaimer in the
161590Srgrimes *    documentation and/or other materials provided with the distribution.
171590Srgrimes * 3. All advertising materials mentioning features or use of this software
181590Srgrimes *    must display the following acknowledgement:
191590Srgrimes *	This product includes software developed by the University of
201590Srgrimes *	California, Berkeley and its contributors.
211590Srgrimes * 4. Neither the name of the University nor the names of its contributors
221590Srgrimes *    may be used to endorse or promote products derived from this software
231590Srgrimes *    without specific prior written permission.
241590Srgrimes *
251590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
261590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
271590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
281590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
291590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
301590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
311590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
321590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
331590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
341590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
351590Srgrimes * SUCH DAMAGE.
361590Srgrimes *
3713430Speter *	@(#)mroute.c	8.2 (Berkeley) 4/28/95
381590Srgrimes */
391590Srgrimes
40132671Scharnier#include <sys/cdefs.h>
41132671Scharnier__FBSDID("$FreeBSD: releng/10.2/usr.bin/netstat/mroute.c 285022 2015-07-02 10:31:08Z garga $");
4252415Sjulian
431590Srgrimes/*
44118502Shsu * Print multicast routing structures and statistics.
451590Srgrimes *
461590Srgrimes * MROUTING 1.0
471590Srgrimes */
481590Srgrimes
491590Srgrimes#include <sys/param.h>
5014543Sdg#include <sys/queue.h>
511590Srgrimes#include <sys/socket.h>
521590Srgrimes#include <sys/socketvar.h>
5380351Sfenner#include <sys/sysctl.h>
541590Srgrimes#include <sys/protosw.h>
559215Swollman#include <sys/mbuf.h>
5620287Swollman#include <sys/time.h>
571590Srgrimes
582553Swollman#include <net/if.h>
591590Srgrimes#include <netinet/in.h>
601590Srgrimes#include <netinet/igmp.h>
619215Swollman#include <net/route.h>
62191356Sbms
63191356Sbms#define _KERNEL 1
641590Srgrimes#include <netinet/ip_mroute.h>
65191356Sbms#undef _KERNEL
661590Srgrimes
6780351Sfenner#include <err.h>
68263335Sglebius#include <nlist.h>
69160787Syar#include <stdint.h>
701590Srgrimes#include <stdio.h>
711590Srgrimes#include <stdlib.h>
721590Srgrimes#include "netstat.h"
731590Srgrimes
74263335Sglebius/*
75263335Sglebius * kvm(3) bindings for every needed symbol
76263335Sglebius */
77263335Sglebiusstatic struct nlist mrl[] = {
78263335Sglebius#define	N_MRTSTAT	0
79263335Sglebius	{ .n_name = "_mrtstat" },
80263335Sglebius#define	N_MFCHASHTBL	1
81263335Sglebius	{ .n_name = "_mfchashtbl" },
82263335Sglebius#define	N_VIFTABLE	2
83263335Sglebius	{ .n_name = "_viftable" },
84263335Sglebius#define	N_MFCTABLESIZE	3
85263335Sglebius	{ .n_name = "_mfctablesize" },
86263335Sglebius	{ .n_name = NULL },
87263335Sglebius};
88118627Shsu
89190012Sbmsstatic void	print_bw_meter(struct bw_meter *, int *);
90190012Sbmsstatic void	print_mfc(struct mfc *, int, int *);
911590Srgrimes
92118627Shsustatic void
93118627Shsuprint_bw_meter(struct bw_meter *bw_meter, int *banner_printed)
94118627Shsu{
95118627Shsu	char s0[256], s1[256], s2[256], s3[256];
96118627Shsu	struct timeval now, end, delta;
971590Srgrimes
98118627Shsu	gettimeofday(&now, NULL);
99118627Shsu
100118627Shsu	if (! *banner_printed) {
101118627Shsu		printf(" Bandwidth Meters\n");
102118627Shsu		printf("  %-30s", "Measured(Start|Packets|Bytes)");
103118627Shsu		printf(" %s", "Type");
104118627Shsu		printf("  %-30s", "Thresh(Interval|Packets|Bytes)");
105118627Shsu		printf(" Remain");
106118627Shsu		printf("\n");
107118627Shsu		*banner_printed = 1;
108118627Shsu	}
109118627Shsu
110118627Shsu	/* The measured values */
111118627Shsu	if (bw_meter->bm_flags & BW_METER_UNIT_PACKETS)
112160787Syar		sprintf(s1, "%ju", (uintmax_t)bw_meter->bm_measured.b_packets);
113118627Shsu	else
114118627Shsu		sprintf(s1, "?");
115118627Shsu	if (bw_meter->bm_flags & BW_METER_UNIT_BYTES)
116160787Syar		sprintf(s2, "%ju", (uintmax_t)bw_meter->bm_measured.b_bytes);
117118627Shsu	else
118118627Shsu		sprintf(s2, "?");
119118627Shsu	sprintf(s0, "%lu.%lu|%s|%s",
120160781Syar		(u_long)bw_meter->bm_start_time.tv_sec,
121160781Syar		(u_long)bw_meter->bm_start_time.tv_usec,
122118627Shsu		s1, s2);
123118627Shsu	printf("  %-30s", s0);
124118627Shsu
125118627Shsu	/* The type of entry */
126118627Shsu	sprintf(s0, "%s", "?");
127118627Shsu	if (bw_meter->bm_flags & BW_METER_GEQ)
128118627Shsu		sprintf(s0, "%s", ">=");
129118627Shsu	else if (bw_meter->bm_flags & BW_METER_LEQ)
130118627Shsu		sprintf(s0, "%s", "<=");
131118627Shsu	printf("  %-3s", s0);
132118627Shsu
133118627Shsu	/* The threshold values */
134118627Shsu	if (bw_meter->bm_flags & BW_METER_UNIT_PACKETS)
135160787Syar		sprintf(s1, "%ju", (uintmax_t)bw_meter->bm_threshold.b_packets);
136118627Shsu	else
137118627Shsu		sprintf(s1, "?");
138118627Shsu	if (bw_meter->bm_flags & BW_METER_UNIT_BYTES)
139160787Syar		sprintf(s2, "%ju", (uintmax_t)bw_meter->bm_threshold.b_bytes);
140118627Shsu	else
141118627Shsu		sprintf(s2, "?");
142118627Shsu	sprintf(s0, "%lu.%lu|%s|%s",
143160781Syar		(u_long)bw_meter->bm_threshold.b_time.tv_sec,
144160781Syar		(u_long)bw_meter->bm_threshold.b_time.tv_usec,
145118627Shsu		s1, s2);
146118627Shsu	printf("  %-30s", s0);
147118627Shsu
148118627Shsu	/* Remaining time */
149118627Shsu	timeradd(&bw_meter->bm_start_time,
150118627Shsu		 &bw_meter->bm_threshold.b_time, &end);
151118627Shsu	if (timercmp(&now, &end, <=)) {
152118627Shsu		timersub(&end, &now, &delta);
153160781Syar		sprintf(s3, "%lu.%lu",
154160781Syar			(u_long)delta.tv_sec,
155160781Syar			(u_long)delta.tv_usec);
156118627Shsu	} else {
157118627Shsu		/* Negative time */
158118627Shsu		timersub(&now, &end, &delta);
159160781Syar		sprintf(s3, "-%lu.%lu",
160160781Syar			(u_long)delta.tv_sec,
161160781Syar			(u_long)delta.tv_usec);
162118627Shsu	}
163118627Shsu	printf(" %s", s3);
164118627Shsu
165118627Shsu	printf("\n");
166118627Shsu}
167118627Shsu
168190012Sbmsstatic void
169190012Sbmsprint_mfc(struct mfc *m, int maxvif, int *banner_printed)
170190012Sbms{
171190012Sbms	struct bw_meter bw_meter, *bwm;
172190012Sbms	int bw_banner_printed;
173190012Sbms	int error;
174190012Sbms	vifi_t vifi;
175190012Sbms
176190012Sbms	bw_banner_printed = 0;
177190012Sbms
178190012Sbms	if (! *banner_printed) {
179190012Sbms		printf("\nIPv4 Multicast Forwarding Table\n"
180190012Sbms		       " Origin          Group            "
181190012Sbms		       " Packets In-Vif  Out-Vifs:Ttls\n");
182190012Sbms		*banner_printed = 1;
183190012Sbms	}
184190012Sbms
185190012Sbms	printf(" %-15.15s", routename(m->mfc_origin.s_addr));
186190012Sbms	printf(" %-15.15s", routename(m->mfc_mcastgrp.s_addr));
187190012Sbms	printf(" %9lu", m->mfc_pkt_cnt);
188190012Sbms	printf("  %3d   ", m->mfc_parent);
189190012Sbms	for (vifi = 0; vifi <= maxvif; vifi++) {
190190012Sbms		if (m->mfc_ttls[vifi] > 0)
191190012Sbms			printf(" %u:%u", vifi, m->mfc_ttls[vifi]);
192190012Sbms	}
193190012Sbms	printf("\n");
194190012Sbms
195190012Sbms	/*
196190012Sbms	 * XXX We break the rules and try to use KVM to read the
197190012Sbms	 * bandwidth meters, they are not retrievable via sysctl yet.
198190012Sbms	 */
199190012Sbms	bwm = m->mfc_bw_meter;
200190012Sbms	while (bwm != NULL) {
201190012Sbms		error = kread((u_long)bwm, (char *)&bw_meter,
202190012Sbms		    sizeof(bw_meter));
203190012Sbms		if (error)
204190012Sbms			break;
205190012Sbms		print_bw_meter(&bw_meter, &bw_banner_printed);
206190012Sbms		bwm = bw_meter.bm_mfc_next;
207190012Sbms	}
208190012Sbms}
209190012Sbms
2101590Srgrimesvoid
211263335Sglebiusmroutepr()
212190012Sbms{
213190012Sbms	struct vif viftable[MAXVIFS];
214190012Sbms	struct vif *v;
215190012Sbms	struct mfc *m;
216263335Sglebius	u_long pmfchashtbl, pmfctablesize, pviftbl;
217190012Sbms	int banner_printed;
218190012Sbms	int saved_numeric_addr;
219190012Sbms	size_t len;
220190012Sbms	vifi_t vifi, maxvif;
221190012Sbms
222190012Sbms	saved_numeric_addr = numeric_addr;
223190012Sbms	numeric_addr = 1;
224190012Sbms
225190012Sbms	/*
226190012Sbms	 * TODO:
227190012Sbms	 * The VIF table will move to hanging off the struct if_info for
228190012Sbms	 * each IPv4 configured interface. Currently it is statically
229190012Sbms	 * allocated, and retrieved either using KVM or an opaque SYSCTL.
230190012Sbms	 *
231190012Sbms	 * This can't happen until the API documented in multicast(4)
232190012Sbms	 * is itself refactored. The historical reason why VIFs use
233190012Sbms	 * a separate ifindex space is entirely due to the legacy
234190012Sbms	 * capability of the MROUTING code to create IPIP tunnels on
235190012Sbms	 * the fly to support DVMRP. When gif(4) became available, this
236190012Sbms	 * functionality was deprecated, as PIM does not use it.
237190012Sbms	 */
238190012Sbms	maxvif = 0;
239285022Sgarga	pmfchashtbl = pmfctablesize = pviftbl = 0;
240190012Sbms
241190012Sbms	len = sizeof(viftable);
242190012Sbms	if (live) {
243190012Sbms		if (sysctlbyname("net.inet.ip.viftable", viftable, &len, NULL,
244190012Sbms		    0) < 0) {
245190012Sbms			warn("sysctl: net.inet.ip.viftable");
246190012Sbms			return;
247190012Sbms		}
248285022Sgarga	} else {
249285022Sgarga		kresolve_list(mrl);
250285022Sgarga		pmfchashtbl = mrl[N_MFCHASHTBL].n_value;
251285022Sgarga		pmfctablesize = mrl[N_MFCTABLESIZE].n_value;
252285022Sgarga		pviftbl = mrl[N_VIFTABLE].n_value;
253285022Sgarga
254285022Sgarga		if (pmfchashtbl == 0 || pmfctablesize == 0 || pviftbl == 0) {
255285022Sgarga			fprintf(stderr, "No IPv4 MROUTING kernel support.\n");
256285022Sgarga			return;
257285022Sgarga		}
258285022Sgarga
259190012Sbms		kread(pviftbl, (char *)viftable, sizeof(viftable));
260285022Sgarga	}
261190012Sbms
262190012Sbms	banner_printed = 0;
263190012Sbms	for (vifi = 0, v = viftable; vifi < MAXVIFS; ++vifi, ++v) {
264190012Sbms		if (v->v_lcl_addr.s_addr == 0)
265190012Sbms			continue;
266190012Sbms
267190012Sbms		maxvif = vifi;
268190012Sbms		if (!banner_printed) {
269190012Sbms			printf("\nIPv4 Virtual Interface Table\n"
270190012Sbms			       " Vif   Thresh   Local-Address   "
271190012Sbms			       "Remote-Address    Pkts-In   Pkts-Out\n");
272190012Sbms			banner_printed = 1;
273190012Sbms		}
274190012Sbms
275190012Sbms		printf(" %2u    %6u   %-15.15s",
276190012Sbms					/* opposite math of add_vif() */
277190012Sbms		    vifi, v->v_threshold,
278190012Sbms		    routename(v->v_lcl_addr.s_addr));
279190012Sbms		printf(" %-15.15s", (v->v_flags & VIFF_TUNNEL) ?
280190012Sbms		    routename(v->v_rmt_addr.s_addr) : "");
281190012Sbms
282190012Sbms		printf(" %9lu  %9lu\n", v->v_pkt_in, v->v_pkt_out);
283190012Sbms	}
284190012Sbms	if (!banner_printed)
285190012Sbms		printf("\nIPv4 Virtual Interface Table is empty\n");
286190012Sbms
287190012Sbms	banner_printed = 0;
288190012Sbms
289190012Sbms	/*
290190012Sbms	 * TODO:
291190012Sbms	 * The MFC table will move into the AF_INET radix trie in future.
292190012Sbms	 * In 8.x, it becomes a dynamically allocated structure referenced
293190012Sbms	 * by a hashed LIST, allowing more than 256 entries w/o kernel tuning.
294190012Sbms	 *
295190012Sbms	 * If retrieved via opaque SYSCTL, the kernel will coalesce it into
296190012Sbms	 * a static table for us.
297190012Sbms	 * If retrieved via KVM, the hash list pointers must be followed.
298190012Sbms	 */
299190012Sbms	if (live) {
300190012Sbms		struct mfc *mfctable;
301190012Sbms
302190012Sbms		len = 0;
303190012Sbms		if (sysctlbyname("net.inet.ip.mfctable", NULL, &len, NULL,
304190012Sbms		    0) < 0) {
305190012Sbms			warn("sysctl: net.inet.ip.mfctable");
306190012Sbms			return;
307190012Sbms		}
308190012Sbms
309190012Sbms		mfctable = malloc(len);
310190012Sbms		if (mfctable == NULL) {
311190012Sbms			warnx("malloc %lu bytes", (u_long)len);
312190012Sbms			return;
313190012Sbms		}
314190012Sbms		if (sysctlbyname("net.inet.ip.mfctable", mfctable, &len, NULL,
315190012Sbms		    0) < 0) {
316190012Sbms			free(mfctable);
317190012Sbms			warn("sysctl: net.inet.ip.mfctable");
318190012Sbms			return;
319190012Sbms		}
320190012Sbms
321190012Sbms		m = mfctable;
322190012Sbms		while (len >= sizeof(*m)) {
323190012Sbms			print_mfc(m++, maxvif, &banner_printed);
324190012Sbms			len -= sizeof(*m);
325190012Sbms		}
326190012Sbms		if (len != 0)
327190024Sbms			warnx("print_mfc: %lu trailing bytes", (u_long)len);
328190012Sbms
329190012Sbms		free(mfctable);
330190012Sbms	} else {
331190012Sbms		LIST_HEAD(, mfc) *mfchashtbl;
332190012Sbms		u_long i, mfctablesize;
333190012Sbms		struct mfc mfc;
334190012Sbms		int error;
335190012Sbms
336190012Sbms		error = kread(pmfctablesize, (char *)&mfctablesize,
337190012Sbms		    sizeof(u_long));
338190012Sbms		if (error) {
339190012Sbms			warn("kread: mfctablesize");
340190012Sbms			return;
341190012Sbms		}
342190012Sbms
343190012Sbms		len = sizeof(*mfchashtbl) * mfctablesize;
344190012Sbms		mfchashtbl = malloc(len);
345190012Sbms		if (mfchashtbl == NULL) {
346190012Sbms			warnx("malloc %lu bytes", (u_long)len);
347190012Sbms			return;
348190012Sbms		}
349190012Sbms		kread(pmfchashtbl, (char *)&mfchashtbl, len);
350190012Sbms
351190012Sbms		for (i = 0; i < mfctablesize; i++) {
352190012Sbms			LIST_FOREACH(m, &mfchashtbl[i], mfc_hash) {
353190012Sbms				kread((u_long)m, (char *)&mfc, sizeof(mfc));
354190012Sbms				print_mfc(m, maxvif, &banner_printed);
355190012Sbms			}
356190012Sbms		}
357190012Sbms
358190012Sbms		free(mfchashtbl);
359190012Sbms	}
360190012Sbms
361190012Sbms	if (!banner_printed)
362190012Sbms		printf("\nIPv4 Multicast Forwarding Table is empty\n");
363190012Sbms
364190012Sbms	printf("\n");
365190012Sbms	numeric_addr = saved_numeric_addr;
366190012Sbms}
367190012Sbms
368190012Sbmsvoid
369263335Sglebiusmrt_stats()
3701590Srgrimes{
3711590Srgrimes	struct mrtstat mrtstat;
372263335Sglebius	u_long mstaddr;
373263335Sglebius	size_t len = sizeof(mrtstat);
3741590Srgrimes
375263335Sglebius	kresolve_list(mrl);
376263335Sglebius	mstaddr = mrl[N_MRTSTAT].n_value;
377263335Sglebius
378263335Sglebius	if (mstaddr == 0) {
379263335Sglebius		fprintf(stderr, "No IPv4 MROUTING kernel support.\n");
380263335Sglebius		return;
381263335Sglebius	}
382263335Sglebius
383171465Sjhb	if (live) {
384171465Sjhb		if (sysctlbyname("net.inet.ip.mrtstat", &mrtstat, &len, NULL,
385171465Sjhb		    0) < 0) {
386263335Sglebius			warn("sysctl: net.inet.ip.mrtstat failed.");
38780351Sfenner			return;
38880351Sfenner		}
389171465Sjhb	} else
390253084Sae		kread_counters(mstaddr, &mrtstat, len);
391171465Sjhb
39262584Sitojun	printf("IPv4 multicast forwarding:\n");
39383204Sru
39483204Sru#define	p(f, m) if (mrtstat.f || sflag <= 1) \
395253081Sae	printf(m, (uintmax_t)mrtstat.f, plural(mrtstat.f))
39683204Sru#define	p2(f, m) if (mrtstat.f || sflag <= 1) \
397253081Sae	printf(m, (uintmax_t)mrtstat.f, plurales(mrtstat.f))
39883204Sru
399253081Sae	p(mrts_mfc_lookups, "\t%ju multicast forwarding cache lookup%s\n");
400253081Sae	p2(mrts_mfc_misses, "\t%ju multicast forwarding cache miss%s\n");
401253081Sae	p(mrts_upcalls, "\t%ju upcall%s to multicast routing daemon\n");
402253081Sae	p(mrts_upq_ovflw, "\t%ju upcall queue overflow%s\n");
40383204Sru	p(mrts_upq_sockfull,
404253081Sae	    "\t%ju upcall%s dropped due to full socket buffer\n");
405253081Sae	p(mrts_cache_cleanups, "\t%ju cache cleanup%s\n");
406253081Sae	p(mrts_no_route, "\t%ju datagram%s with no route for origin\n");
407253081Sae	p(mrts_bad_tunnel, "\t%ju datagram%s arrived with bad tunneling\n");
408253081Sae	p(mrts_cant_tunnel, "\t%ju datagram%s could not be tunneled\n");
409253081Sae	p(mrts_wrong_if, "\t%ju datagram%s arrived on wrong interface\n");
410253081Sae	p(mrts_drop_sel, "\t%ju datagram%s selectively dropped\n");
411253081Sae	p(mrts_q_overflow, "\t%ju datagram%s dropped due to queue overflow\n");
412253081Sae	p(mrts_pkt2large, "\t%ju datagram%s dropped for being too large\n");
41383204Sru
41483204Sru#undef	p2
41583204Sru#undef	p
4161590Srgrimes}
417