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