1 /* $OpenBSD: mroute.c,v 1.17 2007/12/14 18:35:46 deraadt 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 <limits.h> 60 #include <stdio.h> 61 #include <stdlib.h> 62 #include <errno.h> 63 #include "netstat.h" 64 65 static void print_bw_meter(struct bw_meter *bw_meter, int *banner_printed); 66 67 static char * 68 pktscale(u_long n) 69 { 70 static char buf[8]; 71 char t; 72 73 if (n < 1024) 74 t = ' '; 75 else if (n < 1024 * 1024) { 76 t = 'k'; 77 n /= 1024; 78 } else { 79 t = 'm'; 80 n /= 1048576; 81 } 82 83 snprintf(buf, sizeof buf, "%lu%c", n, t); 84 return (buf); 85 } 86 87 void 88 mroutepr(u_long mfchashtbladdr, u_long mfchashaddr, u_long vifaddr) 89 { 90 u_int mrtproto; 91 LIST_HEAD(, mfc) *mfchashtbl; 92 u_long mfchash; 93 struct vif viftable[MAXVIFS], *v; 94 struct mfc *mfcp, mfc; 95 vifi_t vifi; 96 int mib[] = { CTL_NET, AF_INET, IPPROTO_IP, IPCTL_MRTPROTO }; 97 size_t len = sizeof(int); 98 int i, banner_printed = 0, saved_nflag, numvifs = 0; 99 int nmfc; /* No. of cache entries */ 100 101 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), 102 &mrtproto, &len, NULL, 0) == -1) { 103 if (errno != ENOPROTOOPT) 104 warn("mroute"); 105 return; 106 } 107 switch (mrtproto) { 108 case 0: 109 printf("no multicast routing compiled into this system\n"); 110 return; 111 case IGMP_DVMRP: 112 break; 113 default: 114 printf("multicast routing protocol %u, unknown\n", mrtproto); 115 return; 116 } 117 118 if (mfchashtbladdr == 0) { 119 printf("mfchashtbl: symbol not in namelist\n"); 120 return; 121 } 122 if (mfchashaddr == 0) { 123 printf("mfchash: symbol not in namelist\n"); 124 return; 125 } 126 if (vifaddr == 0) { 127 printf("viftable: symbol not in namelist\n"); 128 return; 129 } 130 131 saved_nflag = nflag; 132 nflag = 1; 133 134 kread(vifaddr, &viftable, sizeof(viftable)); 135 136 for (vifi = 0, v = viftable; vifi < MAXVIFS; ++vifi, ++v) { 137 if (v->v_lcl_addr.s_addr == 0) 138 continue; 139 numvifs = vifi; 140 141 if (!banner_printed) { 142 printf("\nVirtual Interface Table\n %s%s", 143 "Vif Thresh Limit Local-Address ", 144 "Remote-Address Pkt_in Pkt_out\n"); 145 banner_printed = 1; 146 } 147 148 printf(" %3u %3u %5u %-15.15s", 149 vifi, v->v_threshold, v->v_rate_limit, 150 routename4(v->v_lcl_addr.s_addr)); 151 printf(" %-15.15s %6lu %7lu\n", (v->v_flags & VIFF_TUNNEL) ? 152 routename4(v->v_rmt_addr.s_addr) : "", 153 v->v_pkt_in, v->v_pkt_out); 154 } 155 if (!banner_printed) 156 printf("Virtual Interface Table is empty\n"); 157 158 kread(mfchashtbladdr, &mfchashtbl, sizeof(mfchashtbl)); 159 kread(mfchashaddr, &mfchash, sizeof(mfchash)); 160 banner_printed = 0; 161 nmfc = 0; 162 163 if (mfchashtbl != 0) 164 for (i = 0; i <= mfchash; ++i) { 165 kread((u_long)&mfchashtbl[i], &mfcp, sizeof(mfcp)); 166 167 for (; mfcp != 0; mfcp = LIST_NEXT(&mfc, mfc_hash)) { 168 if (!banner_printed) { 169 printf("\nMulticast Forwarding Cache\n %s%s", 170 "Hash Origin Mcastgroup ", 171 "Traffic In-Vif Out-Vifs/Forw-ttl\n"); 172 banner_printed = 1; 173 } 174 175 kread((u_long)mfcp, &mfc, sizeof(mfc)); 176 printf(" %3u %-15.15s", 177 i, routename4(mfc.mfc_origin.s_addr)); 178 printf(" %-15.15s %7s %3u ", 179 routename4(mfc.mfc_mcastgrp.s_addr), 180 pktscale(mfc.mfc_pkt_cnt), mfc.mfc_parent); 181 for (vifi = 0; vifi <= numvifs; ++vifi) 182 if (mfc.mfc_ttls[vifi]) 183 printf(" %u/%u", vifi, 184 mfc.mfc_ttls[vifi]); 185 186 printf("\n"); 187 188 /* Print the bw meter information */ 189 { 190 struct bw_meter bw_meter, *bwm; 191 int banner_printed2 = 0; 192 193 bwm = mfc.mfc_bw_meter; 194 while (bwm) { 195 kread((u_long)bwm, 196 &bw_meter, 197 sizeof bw_meter); 198 print_bw_meter(&bw_meter, 199 &banner_printed2); 200 bwm = bw_meter.bm_mfc_next; 201 } 202 #if 0 /* Don't ever print it? */ 203 if (! banner_printed2) 204 printf("\n No Bandwidth Meters\n"); 205 #endif 206 } 207 208 nmfc++; 209 } 210 } 211 if (!banner_printed) 212 printf("Multicast Forwarding Cache is empty\n"); 213 else 214 printf("\nTotal no. of entries in cache: %d\n", nmfc); 215 216 printf("\n"); 217 nflag = saved_nflag; 218 } 219 220 static void 221 print_bw_meter(struct bw_meter *bw_meter, int *banner_printed) 222 { 223 char s0[256], s1[256], s2[256], s3[256]; 224 struct timeval now, end, delta; 225 226 gettimeofday(&now, NULL); 227 228 if (! *banner_printed) { 229 printf(" Bandwidth Meters\n"); 230 printf(" %-30s", "Measured(Start|Packets|Bytes)"); 231 printf(" %s", "Type"); 232 printf(" %-30s", "Thresh(Interval|Packets|Bytes)"); 233 printf(" Remain"); 234 printf("\n"); 235 *banner_printed = 1; 236 } 237 238 /* The measured values */ 239 if (bw_meter->bm_flags & BW_METER_UNIT_PACKETS) 240 snprintf(s1, sizeof s1, "%llu", 241 bw_meter->bm_measured.b_packets); 242 else 243 snprintf(s1, sizeof s1, "?"); 244 if (bw_meter->bm_flags & BW_METER_UNIT_BYTES) 245 snprintf(s2, sizeof s2, "%llu", bw_meter->bm_measured.b_bytes); 246 else 247 snprintf(s2, sizeof s2, "?"); 248 snprintf(s0, sizeof s0, "%lu.%lu|%s|%s", 249 bw_meter->bm_start_time.tv_sec, 250 bw_meter->bm_start_time.tv_usec, 251 s1, s2); 252 printf(" %-30s", s0); 253 254 /* The type of entry */ 255 snprintf(s0, sizeof s0, "%s", "?"); 256 if (bw_meter->bm_flags & BW_METER_GEQ) 257 snprintf(s0, sizeof s0, "%s", ">="); 258 else if (bw_meter->bm_flags & BW_METER_LEQ) 259 snprintf(s0, sizeof s0, "%s", "<="); 260 printf(" %-3s", s0); 261 262 /* The threshold values */ 263 if (bw_meter->bm_flags & BW_METER_UNIT_PACKETS) 264 snprintf(s1, sizeof s1, "%llu", 265 bw_meter->bm_threshold.b_packets); 266 else 267 snprintf(s1, sizeof s1, "?"); 268 if (bw_meter->bm_flags & BW_METER_UNIT_BYTES) 269 snprintf(s2, sizeof s2, "%llu", 270 bw_meter->bm_threshold.b_bytes); 271 else 272 snprintf(s2, sizeof s2, "?"); 273 snprintf(s0, sizeof s0, "%lu.%lu|%s|%s", 274 bw_meter->bm_threshold.b_time.tv_sec, 275 bw_meter->bm_threshold.b_time.tv_usec, 276 s1, s2); 277 printf(" %-30s", s0); 278 279 /* Remaining time */ 280 timeradd(&bw_meter->bm_start_time, 281 &bw_meter->bm_threshold.b_time, &end); 282 if (timercmp(&now, &end, <=)) { 283 timersub(&end, &now, &delta); 284 snprintf(s3, sizeof s3, "%lu.%lu", 285 delta.tv_sec, delta.tv_usec); 286 } else { 287 /* Negative time */ 288 timersub(&now, &end, &delta); 289 snprintf(s3, sizeof s3, "-%lu.%lu", 290 delta.tv_sec, delta.tv_usec); 291 } 292 printf(" %s", s3); 293 294 printf("\n"); 295 } 296 297 void 298 mrt_stats(void) 299 { 300 u_int mrtproto; 301 struct mrtstat mrtstat; 302 int mib[] = { CTL_NET, AF_INET, IPPROTO_IP, IPCTL_MRTPROTO }; 303 int mib2[] = { CTL_NET, AF_INET, IPPROTO_IP, IPCTL_MRTSTATS }; 304 size_t len = sizeof(int); 305 306 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), 307 &mrtproto, &len, NULL, 0) == -1) { 308 if (errno != ENOPROTOOPT) 309 warn("mroute"); 310 return; 311 } 312 switch (mrtproto) { 313 case 0: 314 printf("no multicast routing compiled into this system\n"); 315 return; 316 317 case IGMP_DVMRP: 318 break; 319 320 default: 321 printf("multicast routing protocol %u, unknown\n", mrtproto); 322 return; 323 } 324 325 len = sizeof(mrtstat); 326 if (sysctl(mib2, sizeof(mib2) / sizeof(mib2[0]), 327 &mrtstat, &len, NULL, 0) == -1) { 328 if (errno != ENOPROTOOPT) 329 warn("mroute"); 330 return; 331 } 332 333 printf("multicast routing:\n"); 334 printf("\t%lu datagram%s with no route for origin\n", 335 mrtstat.mrts_no_route, plural(mrtstat.mrts_no_route)); 336 printf("\t%lu upcall%s made to mrouted\n", 337 mrtstat.mrts_upcalls, plural(mrtstat.mrts_upcalls)); 338 printf("\t%lu datagram%s with malformed tunnel options\n", 339 mrtstat.mrts_bad_tunnel, plural(mrtstat.mrts_bad_tunnel)); 340 printf("\t%lu datagram%s with no room for tunnel options\n", 341 mrtstat.mrts_cant_tunnel, plural(mrtstat.mrts_cant_tunnel)); 342 printf("\t%lu datagram%s arrived on wrong interface\n", 343 mrtstat.mrts_wrong_if, plural(mrtstat.mrts_wrong_if)); 344 printf("\t%lu datagram%s dropped due to upcall Q overflow\n", 345 mrtstat.mrts_upq_ovflw, plural(mrtstat.mrts_upq_ovflw)); 346 printf("\t%lu datagram%s dropped due to upcall socket overflow\n", 347 mrtstat.mrts_upq_sockfull, plural(mrtstat.mrts_upq_sockfull)); 348 printf("\t%lu datagram%s cleaned up by the cache\n", 349 mrtstat.mrts_cache_cleanups, plural(mrtstat.mrts_cache_cleanups)); 350 printf("\t%lu datagram%s dropped selectively by ratelimiter\n", 351 mrtstat.mrts_drop_sel, plural(mrtstat.mrts_drop_sel)); 352 printf("\t%lu datagram%s dropped - bucket Q overflow\n", 353 mrtstat.mrts_q_overflow, plural(mrtstat.mrts_q_overflow)); 354 printf("\t%lu datagram%s dropped - larger than bkt size\n", 355 mrtstat.mrts_pkt2large, plural(mrtstat.mrts_pkt2large)); 356 } 357