2 * Copyright (c) 1989 Stephen Deering
3 * Copyright (c) 1992, 1993
4 * The Regents of the University of California. All rights reserved.
6 * This code is derived from software contributed to Berkeley by
7 * Stephen Deering of Stanford University.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the University of
20 * California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * @(#)mroute.c 8.2 (Berkeley) 4/28/95
40 #include <sys/cdefs.h>
41 __FBSDID("$FreeBSD$");
44 * Print multicast routing structures and statistics.
49 #include <sys/param.h>
50 #include <sys/queue.h>
51 #include <sys/socket.h>
52 #include <sys/socketvar.h>
53 #include <sys/sysctl.h>
54 #include <sys/protosw.h>
59 #include <netinet/in.h>
60 #include <netinet/igmp.h>
61 #include <net/route.h>
64 #include <netinet/ip_mroute.h>
77 static void print_bw_meter(struct bw_meter
*, int *);
78 static void print_mfc(struct mfc
*, int, int *);
81 print_bw_meter(struct bw_meter
*bw_meter
, int *banner_printed
)
83 char s1
[256], s2
[256], s3
[256];
84 struct timeval now
, end
, delta
;
86 gettimeofday(&now
, NULL
);
88 if (! *banner_printed
) {
89 xo_open_list("bandwidth-meter");
90 xo_emit(" {T:Bandwidth Meters}\n");
91 xo_emit(" {T:/%-30s}", "Measured(Start|Packets|Bytes)");
92 xo_emit(" {T:/%s}", "Type");
93 xo_emit(" {T:/%-30s}", "Thresh(Interval|Packets|Bytes)");
94 xo_emit(" {T:Remain}");
99 xo_open_instance("bandwidth-meter");
101 /* The measured values */
102 if (bw_meter
->bm_flags
& BW_METER_UNIT_PACKETS
) {
103 sprintf(s1
, "%ju", (uintmax_t)bw_meter
->bm_measured
.b_packets
);
104 xo_emit("{e:measured-packets/%ju}",
105 (uintmax_t)bw_meter
->bm_measured
.b_packets
);
108 if (bw_meter
->bm_flags
& BW_METER_UNIT_BYTES
) {
109 sprintf(s2
, "%ju", (uintmax_t)bw_meter
->bm_measured
.b_bytes
);
110 xo_emit("{e:measured-bytes/%ju}",
111 (uintmax_t)bw_meter
->bm_measured
.b_bytes
);
114 xo_emit(" {[:-30}{:start-time/%lu.%06lu}|{q:measured-packets/%s}"
115 "|{q:measured-bytes%s}{]:}",
116 (u_long
)bw_meter
->bm_start_time
.tv_sec
,
117 (u_long
)bw_meter
->bm_start_time
.tv_usec
, s1
, s2
);
119 /* The type of entry */
120 xo_emit(" {t:type/%-3s}", (bw_meter
->bm_flags
& BW_METER_GEQ
) ? ">=" :
121 (bw_meter
->bm_flags
& BW_METER_LEQ
) ? "<=" : "?");
123 /* The threshold values */
124 if (bw_meter
->bm_flags
& BW_METER_UNIT_PACKETS
) {
125 sprintf(s1
, "%ju", (uintmax_t)bw_meter
->bm_threshold
.b_packets
);
126 xo_emit("{e:threshold-packets/%ju}",
127 (uintmax_t)bw_meter
->bm_threshold
.b_packets
);
130 if (bw_meter
->bm_flags
& BW_METER_UNIT_BYTES
) {
131 sprintf(s2
, "%ju", (uintmax_t)bw_meter
->bm_threshold
.b_bytes
);
132 xo_emit("{e:threshold-bytes/%ju}",
133 (uintmax_t)bw_meter
->bm_threshold
.b_bytes
);
137 xo_emit(" {[:-30}{:threshold-time/%lu.%06lu}|{q:threshold-packets/%s}"
138 "|{q:threshold-bytes%s}{]:}",
139 (u_long
)bw_meter
->bm_threshold
.b_time
.tv_sec
,
140 (u_long
)bw_meter
->bm_threshold
.b_time
.tv_usec
, s1
, s2
);
143 timeradd(&bw_meter
->bm_start_time
,
144 &bw_meter
->bm_threshold
.b_time
, &end
);
145 if (timercmp(&now
, &end
, <=)) {
146 timersub(&end
, &now
, &delta
);
147 sprintf(s3
, "%lu.%06lu",
148 (u_long
)delta
.tv_sec
,
149 (u_long
)delta
.tv_usec
);
152 timersub(&now
, &end
, &delta
);
153 sprintf(s3
, "-%lu.06%lu",
154 (u_long
)delta
.tv_sec
,
155 (u_long
)delta
.tv_usec
);
157 xo_emit(" {:remaining-time/%s}", s3
);
159 xo_open_instance("bandwidth-meter");
165 print_mfc(struct mfc
*m
, int maxvif
, int *banner_printed
)
167 struct sockaddr_in sin
;
168 struct sockaddr
*sa
= (struct sockaddr
*)&sin
;
169 struct bw_meter bw_meter
, *bwm
;
170 int bw_banner_printed
;
174 bw_banner_printed
= 0;
175 memset(&sin
, 0, sizeof(sin
));
176 sin
.sin_len
= sizeof(sin
);
177 sin
.sin_family
= AF_INET
;
179 if (! *banner_printed
) {
180 xo_open_list("multicast-forwarding-entry");
181 xo_emit("\n{T:IPv4 Multicast Forwarding Table}\n"
182 " {T:Origin} {T:Group} "
183 " {T:Packets In-Vif} {T:Out-Vifs:Ttls}\n");
187 memcpy(&sin
.sin_addr
, &m
->mfc_origin
, sizeof(sin
.sin_addr
));
188 xo_emit(" {:origin-address/%-15.15s}", routename(sa
, numeric_addr
));
189 memcpy(&sin
.sin_addr
, &m
->mfc_mcastgrp
, sizeof(sin
.sin_addr
));
190 xo_emit(" {:group-address/%-15.15s}",
191 routename(sa
, numeric_addr
));
192 xo_emit(" {:sent-packets/%9lu}", m
->mfc_pkt_cnt
);
193 xo_emit(" {:parent/%3d} ", m
->mfc_parent
);
194 xo_open_list("vif-ttl");
195 for (vifi
= 0; vifi
<= maxvif
; vifi
++) {
196 if (m
->mfc_ttls
[vifi
] > 0) {
197 xo_open_instance("vif-ttl");
198 xo_emit(" {k:vif/%u}:{:ttl/%u}", vifi
,
200 xo_close_instance("vif-ttl");
203 xo_close_list("vif-ttl");
207 * XXX We break the rules and try to use KVM to read the
208 * bandwidth meters, they are not retrievable via sysctl yet.
210 bwm
= m
->mfc_bw_meter
;
211 while (bwm
!= NULL
) {
212 error
= kread((u_long
)bwm
, (char *)&bw_meter
,
216 print_bw_meter(&bw_meter
, &bw_banner_printed
);
217 bwm
= bw_meter
.bm_mfc_next
;
220 xo_close_list("bandwidth-meter");
226 struct sockaddr_in sin
;
227 struct sockaddr
*sa
= (struct sockaddr
*)&sin
;
228 struct vif viftable
[MAXVIFS
];
231 u_long pmfchashtbl
, pmfctablesize
, pviftbl
;
233 int saved_numeric_addr
;
237 saved_numeric_addr
= numeric_addr
;
240 memset(&sin
, 0, sizeof(sin
));
241 sin
.sin_len
= sizeof(sin
);
242 sin
.sin_family
= AF_INET
;
246 * The VIF table will move to hanging off the struct if_info for
247 * each IPv4 configured interface. Currently it is statically
248 * allocated, and retrieved either using KVM or an opaque SYSCTL.
250 * This can't happen until the API documented in multicast(4)
251 * is itself refactored. The historical reason why VIFs use
252 * a separate ifindex space is entirely due to the legacy
253 * capability of the MROUTING code to create IPIP tunnels on
254 * the fly to support DVMRP. When gif(4) became available, this
255 * functionality was deprecated, as PIM does not use it.
258 pmfchashtbl
= pmfctablesize
= pviftbl
= 0;
260 len
= sizeof(viftable
);
262 if (sysctlbyname("net.inet.ip.viftable", viftable
, &len
, NULL
,
264 xo_warn("sysctl: net.inet.ip.viftable");
268 pmfchashtbl
= nl
[N_MFCHASHTBL
].n_value
;
269 pmfctablesize
= nl
[N_MFCTABLESIZE
].n_value
;
270 pviftbl
= nl
[N_VIFTABLE
].n_value
;
272 if (pmfchashtbl
== 0 || pmfctablesize
== 0 || pviftbl
== 0) {
273 xo_warnx("No IPv4 MROUTING kernel support.");
277 kread(pviftbl
, (char *)viftable
, sizeof(viftable
));
281 for (vifi
= 0, v
= viftable
; vifi
< MAXVIFS
; ++vifi
, ++v
) {
282 if (v
->v_lcl_addr
.s_addr
== 0)
286 if (!banner_printed
) {
287 xo_emit("\n{T:IPv4 Virtual Interface Table\n"
288 " Vif Thresh Local-Address "
289 "Remote-Address Pkts-In Pkts-Out}\n");
294 xo_open_instance("vif");
295 memcpy(&sin
.sin_addr
, &v
->v_lcl_addr
, sizeof(sin
.sin_addr
));
296 xo_emit(" {:vif/%2u} {:threshold/%6u} {:route/%-15.15s}",
297 /* opposite math of add_vif() */
298 vifi
, v
->v_threshold
,
299 routename(sa
, numeric_addr
));
300 memcpy(&sin
.sin_addr
, &v
->v_rmt_addr
, sizeof(sin
.sin_addr
));
301 xo_emit(" {:source/%-15.15s}", (v
->v_flags
& VIFF_TUNNEL
) ?
302 routename(sa
, numeric_addr
) : "");
304 xo_emit(" {:received-packets/%9lu} {:sent-packets/%9lu}\n",
305 v
->v_pkt_in
, v
->v_pkt_out
);
306 xo_close_instance("vif");
309 xo_close_list("vif");
311 xo_emit("\n{T:IPv4 Virtual Interface Table is empty}\n");
317 * The MFC table will move into the AF_INET radix trie in future.
318 * In 8.x, it becomes a dynamically allocated structure referenced
319 * by a hashed LIST, allowing more than 256 entries w/o kernel tuning.
321 * If retrieved via opaque SYSCTL, the kernel will coalesce it into
322 * a static table for us.
323 * If retrieved via KVM, the hash list pointers must be followed.
326 struct mfc
*mfctable
;
329 if (sysctlbyname("net.inet.ip.mfctable", NULL
, &len
, NULL
,
331 xo_warn("sysctl: net.inet.ip.mfctable");
335 mfctable
= malloc(len
);
336 if (mfctable
== NULL
) {
337 xo_warnx("malloc %lu bytes", (u_long
)len
);
340 if (sysctlbyname("net.inet.ip.mfctable", mfctable
, &len
, NULL
,
343 xo_warn("sysctl: net.inet.ip.mfctable");
348 while (len
>= sizeof(*m
)) {
349 print_mfc(m
++, maxvif
, &banner_printed
);
353 xo_close_list("multicast-forwarding-entry");
355 xo_warnx("print_mfc: %lu trailing bytes", (u_long
)len
);
359 LIST_HEAD(, mfc
) *mfchashtbl
;
360 u_long i
, mfctablesize
;
364 error
= kread(pmfctablesize
, (char *)&mfctablesize
,
367 xo_warn("kread: mfctablesize");
371 len
= sizeof(*mfchashtbl
) * mfctablesize
;
372 mfchashtbl
= malloc(len
);
373 if (mfchashtbl
== NULL
) {
374 xo_warnx("malloc %lu bytes", (u_long
)len
);
377 kread(pmfchashtbl
, (char *)&mfchashtbl
, len
);
379 for (i
= 0; i
< mfctablesize
; i
++) {
380 LIST_FOREACH(m
, &mfchashtbl
[i
], mfc_hash
) {
381 kread((u_long
)m
, (char *)&mfc
, sizeof(mfc
));
382 print_mfc(m
, maxvif
, &banner_printed
);
386 xo_close_list("multicast-forwarding-entry");
392 xo_emit("\n{T:IPv4 Multicast Forwarding Table is empty}\n");
395 numeric_addr
= saved_numeric_addr
;
401 struct mrtstat mrtstat
;
404 mstaddr
= nl
[N_MRTSTAT
].n_value
;
407 fprintf(stderr
, "No IPv4 MROUTING kernel support.\n");
411 if (fetch_stats("net.inet.ip.mrtstat", mstaddr
, &mrtstat
,
412 sizeof(mrtstat
), kread_counters
) != 0)
415 xo_emit("{T:IPv4 multicast forwarding}:\n");
417 #define p(f, m) if (mrtstat.f || sflag <= 1) \
418 xo_emit(m, (uintmax_t)mrtstat.f, plural(mrtstat.f))
419 #define p2(f, m) if (mrtstat.f || sflag <= 1) \
420 xo_emit(m, (uintmax_t)mrtstat.f, plurales(mrtstat.f))
422 xo_open_container("multicast-statistics");
424 p(mrts_mfc_lookups
, "\t{:cache-lookups/%ju} "
425 "{N:/multicast forwarding cache lookup%s}\n");
426 p2(mrts_mfc_misses
, "\t{:cache-misses/%ju} "
427 "{N:/multicast forwarding cache miss%s}\n");
428 p(mrts_upcalls
, "\t{:upcalls-total/%ju} "
429 "{N:/upcall%s to multicast routing daemon}\n");
430 p(mrts_upq_ovflw
, "\t{:upcall-overflows/%ju} "
431 "{N:/upcall queue overflow%s}\n");
433 "\t{:upcalls-dropped-full-buffer/%ju} "
434 "{N:/upcall%s dropped due to full socket buffer}\n");
435 p(mrts_cache_cleanups
, "\t{:cache-cleanups/%ju} "
436 "{N:/cache cleanup%s}\n");
437 p(mrts_no_route
, "\t{:dropped-no-origin/%ju} "
438 "{N:/datagram%s with no route for origin}\n");
439 p(mrts_bad_tunnel
, "\t{:dropped-bad-tunnel/%ju} "
440 "{N:/datagram%s arrived with bad tunneling}\n");
441 p(mrts_cant_tunnel
, "\t{:dropped-could-not-tunnel/%ju} "
442 "{N:/datagram%s could not be tunneled}\n");
443 p(mrts_wrong_if
, "\t{:dropped-wrong-incoming-interface/%ju} "
444 "{N:/datagram%s arrived on wrong interface}\n");
445 p(mrts_drop_sel
, "\t{:dropped-selectively/%ju} "
446 "{N:/datagram%s selectively dropped}\n");
447 p(mrts_q_overflow
, "\t{:dropped-queue-overflow/%ju} "
448 "{N:/datagram%s dropped due to queue overflow}\n");
449 p(mrts_pkt2large
, "\t{:dropped-too-large/%ju} "
450 "{N:/datagram%s dropped for being too large}\n");