/*
 * Print DVMRP multicast routing structures and statistics.
 *
 * MROUTING $Revision: 3.5 $
 */

#include <stdio.h>
#include <sys/param.h>
#include <sys/mbuf.h>
#include <netinet/in.h>
#include <netinet/igmp.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <net/route.h>
#define KERNEL 1
#include <netinet/ip_mroute.h>
#undef KERNEL

extern int kmem;
extern int nflag;
extern char *routename();
extern char *netname();
extern char *plural();

static char *
pktscale(n)
	int n;
{
	static char buf[6];
	char t;

	if (n < 1024) {
		t = ' ';
	} else if (n < 1048576) {
		t = 'k';
		n /= 1024;
	} else {
		t = 'm';
		n /= 1048576;
	}

	sprintf(buf, "%4u%c", n, t);

	return buf;
}

mroutepr(mrpaddr, mfcaddr, vifaddr)
	off_t mrpaddr, mfcaddr, vifaddr;
{
	u_int mrtproto;
	struct mbuf *mfctable[MFCTBLSIZ];
	struct vif viftable[MAXVIFS];
	struct mfc *mfc;
	struct mbuf mb;
	struct mbuf *mp;
	register struct vif *v;
	register vifi_t vifi;
	struct in_addr *grp;
	int i;
	int banner_printed;
	int saved_nflag;
	int numvifs;
	int nmfc;			/* No. of cache entries */
	
	if(mrpaddr == 0) {
		printf("ip_mrtproto: symbol not in namelist\n");
		return;
	}

	kread(mrpaddr, (char *)&mrtproto, sizeof(mrtproto));
	switch (mrtproto) {
	    case 0:
		printf("no multicast routing compiled into this system\n");
		return;

	    case IGMP_DVMRP:
		break;

	    default:
		printf("multicast routing protocol %u, unknown\n", mrtproto);
		return;
	}

 	if (mfcaddr == 0) {
		printf("mfctable: symbol not in namelist\n");
		return;
	}
	if (vifaddr == 0) {
		printf("viftable: symbol not in namelist\n");
		return;
	}

	saved_nflag = nflag;
	nflag = 1;

	kread(vifaddr, (char *)viftable, sizeof(viftable));
	banner_printed = 0;
	numvifs = 0;
	
	for (vifi = 0, v = viftable; vifi < MAXVIFS; ++vifi, ++v) {

		if (v->v_lcl_addr.s_addr == 0) continue;

		numvifs = vifi;
		
		if (!banner_printed) {
			printf("\nVirtual Interface Table\n%s%s%s",
			       " Vif  Thresh  Rate_lmt  ",
				   "Local-Address   ",
			       "Remote-Address     Pkt_in   Pkt_out\n");
			banner_printed = 1;
		}

		printf(" %2u    %3u   %6u     %-15.15s",
			   vifi, v->v_threshold, 
			   v->v_rate_limit, routename(v->v_lcl_addr));
		printf(" %-15.15s  %8u  %8u\n",
			(v->v_flags & VIFF_TUNNEL) ?
				routename(v->v_rmt_addr) : " ",
		       v->v_pkt_in, v->v_pkt_out);
	}
	if (!banner_printed) printf("\nVirtual Interface Table is empty\n");

	kread(mfcaddr, (char *)mfctable, sizeof(mfctable));
	banner_printed = 0;
	for (i = 0, nmfc = 0; i < MFCTBLSIZ; ++i) {
	    for (mp = mfctable[i]; mp != NULL; mp = mb.m_next) {

		if (!banner_printed) {
			printf("\nMulticast Forwarding Cache\n%s%s",
			       " Hash  Origin-Subnet     Mcastgroup  ",
			       "   # pkts In-Vif  Out-Vifs/Forw-ttl\n");
			banner_printed = 1;
		}

		kread((off_t)mp, (char *)&mb, sizeof(mb));
		mfc = mtod(&mb, struct mfc *);
		printf(" %3u   %-15.15s",
			i,
		       routename(mfc->mfc_origin));
		printf("  %-15.15s %5s   %2u    ",
			routename(mfc->mfc_mcastgrp),
			pktscale(mfc->mfc_pkt_cnt), mfc->mfc_parent);
		for (vifi = 0; vifi <= numvifs; ++vifi)
			if (mfc->mfc_ttls[vifi]) 
				printf(" %u/%u", vifi, mfc->mfc_ttls[vifi]);

		printf("\n");
		nmfc++;
	    }
	}
	if (!banner_printed) printf("\nMulticast Forwarding Cache is empty\n");
	else printf("\nTotal no. of entries in cache: %d\n", nmfc);

	printf("\n");
	nflag = saved_nflag;
}


mrt_stats(mrpaddr, mstaddr, mdaddr)
	off_t mrpaddr, mstaddr, mdaddr;
{
	u_int mrtproto;
	struct mrtstat mrtstat;
	int i, j, k, max;
	u_long upcall_data[51];
	
	if(mrpaddr == 0) {
		printf("ip_mrtproto: symbol not in namelist\n");
		return;
	}

	kread(mrpaddr, (char *)&mrtproto, sizeof(mrtproto));
	switch (mrtproto) {
	    case 0:
		printf("no multicast routing compiled into this system\n");
		return;

	    case IGMP_DVMRP:
		break;

	    default:
		printf("multicast routing protocol %u, unknown\n", mrtproto);
		return;
	}

	if (mstaddr == 0) {
		printf("mrtstat: symbol not in namelist\n");
		return;
	}

	kread(mstaddr, (char *)&mrtstat, sizeof(mrtstat));
	printf("multicast routing:\n");
	printf(" %10u datagram%s with no route for origin\n",
	  mrtstat.mrts_no_route, plural(mrtstat.mrts_no_route));
	printf(" %10u upcall%s made to mrouted\n",
	  mrtstat.mrts_upcalls, plural(mrtstat.mrts_upcalls));
	printf(" %10u datagram%s with malformed tunnel options\n",
	  mrtstat.mrts_bad_tunnel, plural(mrtstat.mrts_bad_tunnel));
	printf(" %10u datagram%s with no room for tunnel options\n",
	  mrtstat.mrts_cant_tunnel, plural(mrtstat.mrts_cant_tunnel));
	printf(" %10u datagram%s arrived on wrong interface\n",
	  mrtstat.mrts_wrong_if, plural(mrtstat.mrts_wrong_if));
	printf(" %10u datagram%s dropped due to upcall Q overflow\n",
	  mrtstat.mrts_upq_ovflw, plural(mrtstat.mrts_upq_ovflw));
	printf(" %10u datagram%s dropped due to upcall socket overflow\n",
	  mrtstat.mrts_upq_sockfull, plural(mrtstat.mrts_upq_sockfull));
	printf(" %10u datagram%s cleaned up by the cache\n",
	  mrtstat.mrts_cache_cleanups, plural(mrtstat.mrts_cache_cleanups));
	printf(" %10u datagram%s dropped selectively by ratelimiter\n",
	  mrtstat.mrts_drop_sel, plural(mrtstat.mrts_drop_sel));
	printf(" %10u datagram%s dropped - bucket Q overflow\n",
	  mrtstat.mrts_q_overflow, plural(mrtstat.mrts_q_overflow));
	printf(" %10u datagram%s dropped - larger than bkt size\n",
	  mrtstat.mrts_pkt2large, plural(mrtstat.mrts_pkt2large));

	if (mdaddr == 0) {
/*
		printf("timing info: data symbol not in namelist\n");
*/
		return;
	}
	
	max = 1;
	kread(mdaddr, (char *)upcall_data, sizeof(upcall_data));
	for (i = 0; i <= 50; i++)
	    max = (max > upcall_data[i]) ? max : upcall_data[i];

	printf("\n\nTiming histogram of upcalls for new packets\n");
	printf("Upcall time(mS)    No. of packets\n");
	
	for (i = 0; i < 50; i++)
	{
	    printf(" %3d - %3d  |", i, i+1);
	    
	    if (upcall_data[i] == 0)
	    	j = 0;
	    else
	    	j = 1 + 50 * upcall_data[i] / max;

	    for (k = 0; k < j; k++)
		printf("%c",'*');

	    printf("[%d]\n", upcall_data[i]);
	}
	printf("  >50       |");

	if (upcall_data[i] == 0)
    		j = 0;
	else
    		j = 1 + 50 * upcall_data[i] / max;
	
	for (k = 0; k < j; k++)
	    printf("%c",'*');

    printf(" [%d]\n", upcall_data[50]);
}
