inet6.c revision 355869
1130803Smarcel/*	BSDI inet.c,v 2.3 1995/10/24 02:19:29 prb Exp	*/
2130803Smarcel/*-
3130803Smarcel * Copyright (c) 1983, 1988, 1993
4130803Smarcel *	The Regents of the University of California.  All rights reserved.
5130803Smarcel *
6130803Smarcel * Redistribution and use in source and binary forms, with or without
7130803Smarcel * modification, are permitted provided that the following conditions
8130803Smarcel * are met:
9130803Smarcel * 1. Redistributions of source code must retain the above copyright
10130803Smarcel *    notice, this list of conditions and the following disclaimer.
11130803Smarcel * 2. Redistributions in binary form must reproduce the above copyright
12130803Smarcel *    notice, this list of conditions and the following disclaimer in the
13130803Smarcel *    documentation and/or other materials provided with the distribution.
14130803Smarcel * 4. Neither the name of the University nor the names of its contributors
15130803Smarcel *    may be used to endorse or promote products derived from this software
16130803Smarcel *    without specific prior written permission.
17130803Smarcel *
18130803Smarcel * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19130803Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20130803Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21130803Smarcel * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22130803Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23130803Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24130803Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25130803Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26130803Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27130803Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28130803Smarcel * SUCH DAMAGE.
29130803Smarcel */
30130803Smarcel
31130803Smarcel#if 0
32130803Smarcel#ifndef lint
33130803Smarcelstatic char sccsid[] = "@(#)inet6.c	8.4 (Berkeley) 4/20/94";
34130803Smarcel#endif /* not lint */
35130803Smarcel#endif
36130803Smarcel
37130803Smarcel#include <sys/cdefs.h>
38130803Smarcel__FBSDID("$FreeBSD: stable/11/usr.bin/netstat/inet6.c 355869 2019-12-17 23:45:50Z bz $");
39130803Smarcel
40130803Smarcel#ifdef INET6
41130803Smarcel#include <sys/param.h>
42130803Smarcel#include <sys/socket.h>
43130803Smarcel#include <sys/socketvar.h>
44130803Smarcel#include <sys/ioctl.h>
45130803Smarcel#include <sys/mbuf.h>
46130803Smarcel#include <sys/protosw.h>
47130803Smarcel
48130803Smarcel#include <net/route.h>
49130803Smarcel#include <net/if.h>
50130803Smarcel#include <netinet/in.h>
51130803Smarcel#include <netinet/ip6.h>
52130803Smarcel#include <netinet/icmp6.h>
53130803Smarcel#include <netinet/in_systm.h>
54130803Smarcel#include <netinet6/in6_pcb.h>
55130803Smarcel#include <netinet6/in6_var.h>
56130803Smarcel#include <netinet6/ip6_var.h>
57130803Smarcel#include <netinet6/pim6_var.h>
58130803Smarcel#include <netinet6/raw_ip6.h>
59130803Smarcel
60130803Smarcel#include <arpa/inet.h>
61130803Smarcel#include <netdb.h>
62130803Smarcel
63130803Smarcel#include <err.h>
64130803Smarcel#include <stdint.h>
65130803Smarcel#include <stdio.h>
66130803Smarcel#include <stdbool.h>
67130803Smarcel#include <errno.h>
68130803Smarcel#include <string.h>
69130803Smarcel#include <unistd.h>
70130803Smarcel#include <libxo/xo.h>
71130803Smarcel#include "netstat.h"
72130803Smarcel
73130803Smarcelstatic char ntop_buf[INET6_ADDRSTRLEN];
74130803Smarcel
75130803Smarcelstatic	const char *ip6nh[] = {
76130803Smarcel	"hop by hop",
77130803Smarcel	"ICMP",
78130803Smarcel	"IGMP",
79130803Smarcel	"#3",
80130803Smarcel	"IP",
81130803Smarcel	"#5",
82130803Smarcel	"TCP",
83130803Smarcel	"#7",
84130803Smarcel	"#8",
85130803Smarcel	"#9",
86130803Smarcel	"#10",
87130803Smarcel	"#11",
88130803Smarcel	"#12",
89130803Smarcel	"#13",
90130803Smarcel	"#14",
91130803Smarcel	"#15",
92130803Smarcel	"#16",
93130803Smarcel	"UDP",
94130803Smarcel	"#18",
95130803Smarcel	"#19",
96130803Smarcel	"#20",
97130803Smarcel	"#21",
98130803Smarcel	"IDP",
99130803Smarcel	"#23",
100130803Smarcel	"#24",
101130803Smarcel	"#25",
102130803Smarcel	"#26",
103130803Smarcel	"#27",
104130803Smarcel	"#28",
105130803Smarcel	"TP",
106130803Smarcel	"#30",
107130803Smarcel	"#31",
108130803Smarcel	"#32",
109130803Smarcel	"#33",
110130803Smarcel	"#34",
111130803Smarcel	"#35",
112130803Smarcel	"#36",
113130803Smarcel	"#37",
114130803Smarcel	"#38",
115130803Smarcel	"#39",
116130803Smarcel	"#40",
117130803Smarcel	"IP6",
118130803Smarcel	"#42",
119130803Smarcel	"routing",
120130803Smarcel	"fragment",
121130803Smarcel	"#45",
122130803Smarcel	"#46",
123130803Smarcel	"#47",
124130803Smarcel	"#48",
125130803Smarcel	"#49",
126130803Smarcel	"ESP",
127130803Smarcel	"AH",
128130803Smarcel	"#52",
129130803Smarcel	"#53",
130130803Smarcel	"#54",
131130803Smarcel	"#55",
132130803Smarcel	"#56",
133130803Smarcel	"#57",
134130803Smarcel	"ICMP6",
135130803Smarcel	"no next header",
136130803Smarcel	"destination option",
137130803Smarcel	"#61",
138130803Smarcel	"mobility",
139130803Smarcel	"#63",
140130803Smarcel	"#64",
141130803Smarcel	"#65",
142130803Smarcel	"#66",
143130803Smarcel	"#67",
144130803Smarcel	"#68",
145130803Smarcel	"#69",
146130803Smarcel	"#70",
147130803Smarcel	"#71",
148130803Smarcel	"#72",
149130803Smarcel	"#73",
150130803Smarcel	"#74",
151130803Smarcel	"#75",
152130803Smarcel	"#76",
153130803Smarcel	"#77",
154130803Smarcel	"#78",
155130803Smarcel	"#79",
156130803Smarcel	"ISOIP",
157130803Smarcel	"#81",
158130803Smarcel	"#82",
159130803Smarcel	"#83",
160130803Smarcel	"#84",
161130803Smarcel	"#85",
162130803Smarcel	"#86",
163130803Smarcel	"#87",
164130803Smarcel	"#88",
165130803Smarcel	"OSPF",
166130803Smarcel	"#80",
167130803Smarcel	"#91",
168130803Smarcel	"#92",
169130803Smarcel	"#93",
170130803Smarcel	"#94",
171130803Smarcel	"#95",
172130803Smarcel	"#96",
173130803Smarcel	"Ethernet",
174130803Smarcel	"#98",
175130803Smarcel	"#99",
176130803Smarcel	"#100",
177130803Smarcel	"#101",
178130803Smarcel	"#102",
179130803Smarcel	"PIM",
180130803Smarcel	"#104",
181130803Smarcel	"#105",
182130803Smarcel	"#106",
183130803Smarcel	"#107",
184130803Smarcel	"#108",
185130803Smarcel	"#109",
186130803Smarcel	"#110",
187130803Smarcel	"#111",
188130803Smarcel	"#112",
189130803Smarcel	"#113",
190130803Smarcel	"#114",
191130803Smarcel	"#115",
192130803Smarcel	"#116",
193130803Smarcel	"#117",
194130803Smarcel	"#118",
195130803Smarcel	"#119",
196130803Smarcel	"#120",
197130803Smarcel	"#121",
198130803Smarcel	"#122",
199130803Smarcel	"#123",
200130803Smarcel	"#124",
201130803Smarcel	"#125",
202130803Smarcel	"#126",
203130803Smarcel	"#127",
204130803Smarcel	"#128",
205130803Smarcel	"#129",
206130803Smarcel	"#130",
207130803Smarcel	"#131",
208130803Smarcel	"SCTP",
209130803Smarcel	"#133",
210130803Smarcel	"#134",
211130803Smarcel	"#135",
212130803Smarcel	"UDPLite",
213130803Smarcel	"#137",
214130803Smarcel	"#138",
215130803Smarcel	"#139",
216130803Smarcel	"#140",
217130803Smarcel	"#141",
218130803Smarcel	"#142",
219130803Smarcel	"#143",
220130803Smarcel	"#144",
221130803Smarcel	"#145",
222130803Smarcel	"#146",
223130803Smarcel	"#147",
224130803Smarcel	"#148",
225130803Smarcel	"#149",
226130803Smarcel	"#150",
227130803Smarcel	"#151",
228130803Smarcel	"#152",
229130803Smarcel	"#153",
230130803Smarcel	"#154",
231130803Smarcel	"#155",
232130803Smarcel	"#156",
233130803Smarcel	"#157",
234130803Smarcel	"#158",
235130803Smarcel	"#159",
236130803Smarcel	"#160",
237130803Smarcel	"#161",
238130803Smarcel	"#162",
239130803Smarcel	"#163",
240130803Smarcel	"#164",
241130803Smarcel	"#165",
242130803Smarcel	"#166",
243130803Smarcel	"#167",
244130803Smarcel	"#168",
245130803Smarcel	"#169",
246130803Smarcel	"#170",
247130803Smarcel	"#171",
248130803Smarcel	"#172",
249130803Smarcel	"#173",
250130803Smarcel	"#174",
251130803Smarcel	"#175",
252130803Smarcel	"#176",
253130803Smarcel	"#177",
254130803Smarcel	"#178",
255130803Smarcel	"#179",
256130803Smarcel	"#180",
257130803Smarcel	"#181",
258130803Smarcel	"#182",
259130803Smarcel	"#183",
260130803Smarcel	"#184",
261130803Smarcel	"#185",
262130803Smarcel	"#186",
263130803Smarcel	"#187",
264130803Smarcel	"#188",
265130803Smarcel	"#189",
266130803Smarcel	"#180",
267130803Smarcel	"#191",
268130803Smarcel	"#192",
269130803Smarcel	"#193",
270130803Smarcel	"#194",
271130803Smarcel	"#195",
272130803Smarcel	"#196",
273130803Smarcel	"#197",
274130803Smarcel	"#198",
275130803Smarcel	"#199",
276130803Smarcel	"#200",
277130803Smarcel	"#201",
278130803Smarcel	"#202",
279130803Smarcel	"#203",
280130803Smarcel	"#204",
281130803Smarcel	"#205",
282130803Smarcel	"#206",
283130803Smarcel	"#207",
284130803Smarcel	"#208",
285130803Smarcel	"#209",
286130803Smarcel	"#210",
287130803Smarcel	"#211",
288130803Smarcel	"#212",
289130803Smarcel	"#213",
290130803Smarcel	"#214",
291130803Smarcel	"#215",
292130803Smarcel	"#216",
293130803Smarcel	"#217",
294130803Smarcel	"#218",
295130803Smarcel	"#219",
296130803Smarcel	"#220",
297130803Smarcel	"#221",
298130803Smarcel	"#222",
299130803Smarcel	"#223",
300130803Smarcel	"#224",
301130803Smarcel	"#225",
302130803Smarcel	"#226",
303130803Smarcel	"#227",
304130803Smarcel	"#228",
305130803Smarcel	"#229",
306130803Smarcel	"#230",
307130803Smarcel	"#231",
308130803Smarcel	"#232",
309130803Smarcel	"#233",
310130803Smarcel	"#234",
311130803Smarcel	"#235",
312130803Smarcel	"#236",
313130803Smarcel	"#237",
314130803Smarcel	"#238",
315130803Smarcel	"#239",
316130803Smarcel	"#240",
317130803Smarcel	"#241",
318130803Smarcel	"#242",
319130803Smarcel	"#243",
320130803Smarcel	"#244",
321130803Smarcel	"#245",
322130803Smarcel	"#246",
323130803Smarcel	"#247",
324130803Smarcel	"#248",
325130803Smarcel	"#249",
326130803Smarcel	"#250",
327130803Smarcel	"#251",
328130803Smarcel	"#252",
329130803Smarcel	"#253",
330130803Smarcel	"#254",
331130803Smarcel	"#255",
332130803Smarcel};
333130803Smarcel
334130803Smarcelstatic const char *srcrule_str[] = {
335130803Smarcel	"first candidate",
336130803Smarcel	"same address",
337130803Smarcel	"appropriate scope",
338130803Smarcel	"deprecated address",
339130803Smarcel	"home address",
340130803Smarcel	"outgoing interface",
341130803Smarcel	"matching label",
342130803Smarcel	"public/temporary address",
343130803Smarcel	"alive interface",
344130803Smarcel	"better virtual status",
345130803Smarcel	"preferred source",
346130803Smarcel	"rule #11",
347130803Smarcel	"rule #12",
348130803Smarcel	"rule #13",
349130803Smarcel	"longest match",
350130803Smarcel	"rule #15",
351130803Smarcel};
352130803Smarcel
353130803Smarcel/*
354130803Smarcel * Dump IP6 statistics structure.
355130803Smarcel */
356130803Smarcelvoid
357130803Smarcelip6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
358130803Smarcel{
359130803Smarcel	struct ip6stat ip6stat;
360130803Smarcel	int first, i;
361130803Smarcel
362130803Smarcel	if (fetch_stats("net.inet6.ip6.stats", off, &ip6stat,
363130803Smarcel	    sizeof(ip6stat), kread_counters) != 0)
364130803Smarcel		return;
365130803Smarcel
366130803Smarcel	xo_open_container(name);
367130803Smarcel	xo_emit("{T:/%s}:\n", name);
368130803Smarcel
369130803Smarcel#define	p(f, m) if (ip6stat.f || sflag <= 1) \
370130803Smarcel	xo_emit(m, (uintmax_t)ip6stat.f, plural(ip6stat.f))
371130803Smarcel#define	p1a(f, m) if (ip6stat.f || sflag <= 1) \
372130803Smarcel	xo_emit(m, (uintmax_t)ip6stat.f)
373130803Smarcel
374130803Smarcel	p(ip6s_total, "\t{:received-packets/%ju} "
375130803Smarcel	    "{N:/total packet%s received}\n");
376130803Smarcel	p1a(ip6s_toosmall, "\t{:dropped-below-minimum-size/%ju} "
377130803Smarcel	    "{N:/with size smaller than minimum}\n");
378130803Smarcel	p1a(ip6s_tooshort, "\t{:dropped-short-packets/%ju} "
379130803Smarcel	    "{N:/with data size < data length}\n");
380130803Smarcel	p1a(ip6s_badoptions, "\t{:dropped-bad-options/%ju} "
381130803Smarcel	    "{N:/with bad options}\n");
382130803Smarcel	p1a(ip6s_badvers, "\t{:dropped-bad-version/%ju} "
383130803Smarcel	    "{N:/with incorrect version number}\n");
384130803Smarcel	p(ip6s_fragments, "\t{:received-fragments/%ju} "
385130803Smarcel	    "{N:/fragment%s received}\n");
386130803Smarcel	p(ip6s_fragdropped, "\t{:dropped-fragment/%ju} "
387130803Smarcel	    "{N:/fragment%s dropped (dup or out of space)}\n");
388130803Smarcel	p(ip6s_fragtimeout, "\t{:dropped-fragment-after-timeout/%ju} "
389130803Smarcel	    "{N:/fragment%s dropped after timeout}\n");
390130803Smarcel	p(ip6s_fragoverflow, "\t{:dropped-fragments-overflow/%ju} "
391130803Smarcel	    "{N:/fragment%s that exceeded limit}\n");
392130803Smarcel	p(ip6s_reassembled, "\t{:reassembled-packets/%ju} "
393130803Smarcel	    "{N:/packet%s reassembled ok}\n");
394130803Smarcel	p(ip6s_delivered, "\t{:received-local-packets/%ju} "
395130803Smarcel	    "{N:/packet%s for this host}\n");
396130803Smarcel	p(ip6s_forward, "\t{:forwarded-packets/%ju} "
397130803Smarcel	    "{N:/packet%s forwarded}\n");
398130803Smarcel	p(ip6s_cantforward, "\t{:packets-not-forwardable/%ju} "
399130803Smarcel	    "{N:/packet%s not forwardable}\n");
400130803Smarcel	p(ip6s_redirectsent, "\t{:sent-redirects/%ju} "
401130803Smarcel	    "{N:/redirect%s sent}\n");
402130803Smarcel	p(ip6s_localout, "\t{:sent-packets/%ju} "
403130803Smarcel	    "{N:/packet%s sent from this host}\n");
404130803Smarcel	p(ip6s_rawout, "\t{:send-packets-fabricated-header/%ju} "
405130803Smarcel	    "{N:/packet%s sent with fabricated ip header}\n");
406130803Smarcel	p(ip6s_odropped, "\t{:discard-no-mbufs/%ju} "
407130803Smarcel	    "{N:/output packet%s dropped due to no bufs, etc.}\n");
408130803Smarcel	p(ip6s_noroute, "\t{:discard-no-route/%ju} "
409130803Smarcel	    "{N:/output packet%s discarded due to no route}\n");
410130803Smarcel	p(ip6s_fragmented, "\t{:sent-fragments/%ju} "
411130803Smarcel	    "{N:/output datagram%s fragmented}\n");
412130803Smarcel	p(ip6s_ofragments, "\t{:fragments-created/%ju} "
413130803Smarcel	    "{N:/fragment%s created}\n");
414130803Smarcel	p(ip6s_cantfrag, "\t{:discard-cannot-fragment/%ju} "
415130803Smarcel	    "{N:/datagram%s that can't be fragmented}\n");
416130803Smarcel	p(ip6s_badscope, "\t{:discard-scope-violations/%ju} "
417130803Smarcel	    "{N:/packet%s that violated scope rules}\n");
418130803Smarcel	p(ip6s_notmember, "\t{:multicast-no-join-packets/%ju} "
419130803Smarcel	    "{N:/multicast packet%s which we don't join}\n");
420130803Smarcel	for (first = 1, i = 0; i < IP6S_HDRCNT; i++)
421130803Smarcel		if (ip6stat.ip6s_nxthist[i] != 0) {
422130803Smarcel			if (first) {
423130803Smarcel				xo_emit("\t{T:Input histogram}:\n");
424130803Smarcel				xo_open_list("input-histogram");
425130803Smarcel				first = 0;
426130803Smarcel			}
427130803Smarcel			xo_open_instance("input-histogram");
428130803Smarcel			xo_emit("\t\t{k:name/%s}: {:count/%ju}\n", ip6nh[i],
429130803Smarcel			    (uintmax_t)ip6stat.ip6s_nxthist[i]);
430130803Smarcel			xo_close_instance("input-histogram");
431130803Smarcel		}
432130803Smarcel	if (!first)
433130803Smarcel		xo_close_list("input-histogram");
434130803Smarcel
435130803Smarcel	xo_open_container("mbuf-statistics");
436130803Smarcel	xo_emit("\t{T:Mbuf statistics}:\n");
437130803Smarcel	xo_emit("\t\t{:one-mbuf/%ju} {N:/one mbuf}\n",
438130803Smarcel	    (uintmax_t)ip6stat.ip6s_m1);
439130803Smarcel	for (first = 1, i = 0; i < IP6S_M2MMAX; i++) {
440130803Smarcel		char ifbuf[IFNAMSIZ];
441130803Smarcel		if (ip6stat.ip6s_m2m[i] != 0) {
442130803Smarcel			if (first) {
443130803Smarcel				xo_emit("\t\t{N:two or more mbuf}:\n");
444130803Smarcel				xo_open_list("mbuf-data");
445130803Smarcel				first = 0;
446130803Smarcel			}
447130803Smarcel			xo_open_instance("mbuf-data");
448130803Smarcel			xo_emit("\t\t\t{k:name/%s}= {:count/%ju}\n",
449130803Smarcel			    if_indextoname(i, ifbuf),
450130803Smarcel			    (uintmax_t)ip6stat.ip6s_m2m[i]);
451130803Smarcel			xo_close_instance("mbuf-data");
452130803Smarcel		}
453130803Smarcel	}
454130803Smarcel	if (!first)
455130803Smarcel		xo_close_list("mbuf-data");
456130803Smarcel	xo_emit("\t\t{:one-extra-mbuf/%ju} {N:one ext mbuf}\n",
457130803Smarcel	    (uintmax_t)ip6stat.ip6s_mext1);
458130803Smarcel	xo_emit("\t\t{:two-or-more-extra-mbufs/%ju} "
459130803Smarcel	    "{N:/two or more ext mbuf}\n", (uintmax_t)ip6stat.ip6s_mext2m);
460130803Smarcel	xo_close_container("mbuf-statistics");
461130803Smarcel
462130803Smarcel	p(ip6s_exthdrtoolong, "\t{:dropped-header-too-long/%ju} "
463130803Smarcel	    "{N:/packet%s whose headers are not contiguous}\n");
464130803Smarcel	p(ip6s_nogif, "\t{:discard-tunnel-no-gif/%ju} "
465130803Smarcel	    "{N:/tunneling packet%s that can't find gif}\n");
466130803Smarcel	p(ip6s_toomanyhdr, "\t{:dropped-too-many-headers/%ju} "
467130803Smarcel	    "{N:/packet%s discarded because of too many headers}\n");
468130803Smarcel
469130803Smarcel	/* for debugging source address selection */
470130803Smarcel#define	PRINT_SCOPESTAT(s,i) do {\
471130803Smarcel		switch(i) { /* XXX hardcoding in each case */\
472130803Smarcel		case 1:\
473130803Smarcel			p(s, "\t\t{ke:name/interface-locals}{:count/%ju} " \
474130803Smarcel			  "{N:/interface-local%s}\n");	\
475130803Smarcel			break;\
476130803Smarcel		case 2:\
477130803Smarcel			p(s,"\t\t{ke:name/link-locals}{:count/%ju} " \
478130803Smarcel			"{N:/link-local%s}\n"); \
479130803Smarcel			break;\
480130803Smarcel		case 5:\
481130803Smarcel			p(s,"\t\t{ke:name/site-locals}{:count/%ju} " \
482130803Smarcel			  "{N:/site-local%s}\n");\
483130803Smarcel			break;\
484130803Smarcel		case 14:\
485130803Smarcel			p(s,"\t\t{ke:name/globals}{:count/%ju} " \
486130803Smarcel			  "{N:/global%s}\n");\
487130803Smarcel			break;\
488130803Smarcel		default:\
489130803Smarcel			xo_emit("\t\t{qke:name/%#x}{:count/%ju} " \
490130803Smarcel				"{N:/addresses scope=%#x}\n",\
491130803Smarcel				i, (uintmax_t)ip6stat.s, i);	   \
492130803Smarcel		}\
493130803Smarcel	} while (0);
494130803Smarcel
495130803Smarcel	xo_open_container("source-address-selection");
496130803Smarcel	p(ip6s_sources_none, "\t{:address-selection-failures/%ju} "
497130803Smarcel	    "{N:/failure%s of source address selection}\n");
498130803Smarcel
499130803Smarcel	for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) {
500130803Smarcel		if (ip6stat.ip6s_sources_sameif[i]) {
501130803Smarcel			if (first) {
502130803Smarcel				xo_open_list("outgoing-interface");
503130803Smarcel				xo_emit("\tsource addresses on an outgoing "
504130803Smarcel				    "I/F\n");
505130803Smarcel				first = 0;
506130803Smarcel			}
507130803Smarcel			xo_open_instance("outgoing-interface");
508130803Smarcel			PRINT_SCOPESTAT(ip6s_sources_sameif[i], i);
509130803Smarcel			xo_close_instance("outgoing-interface");
510130803Smarcel		}
511130803Smarcel	}
512130803Smarcel	if (!first)
513130803Smarcel		xo_close_list("outgoing-interface");
514130803Smarcel
515130803Smarcel	for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) {
516130803Smarcel		if (ip6stat.ip6s_sources_otherif[i]) {
517130803Smarcel			if (first) {
518130803Smarcel				xo_open_list("non-outgoing-interface");
519130803Smarcel				xo_emit("\tsource addresses on a non-outgoing "
520130803Smarcel				    "I/F\n");
521130803Smarcel				first = 0;
522130803Smarcel			}
523130803Smarcel			xo_open_instance("non-outgoing-interface");
524130803Smarcel			PRINT_SCOPESTAT(ip6s_sources_otherif[i], i);
525130803Smarcel			xo_close_instance("non-outgoing-interface");
526130803Smarcel		}
527130803Smarcel	}
528130803Smarcel	if (!first)
529130803Smarcel		xo_close_list("non-outgoing-interface");
530130803Smarcel
531130803Smarcel	for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) {
532130803Smarcel		if (ip6stat.ip6s_sources_samescope[i]) {
533130803Smarcel			if (first) {
534130803Smarcel				xo_open_list("same-source");
535130803Smarcel				xo_emit("\tsource addresses of same scope\n");
536130803Smarcel				first = 0;
537130803Smarcel			}
538130803Smarcel			xo_open_instance("same-source");
539130803Smarcel			PRINT_SCOPESTAT(ip6s_sources_samescope[i], i);
540130803Smarcel			xo_close_instance("same-source");
541130803Smarcel		}
542130803Smarcel	}
543130803Smarcel	if (!first)
544130803Smarcel		xo_close_list("same-source");
545130803Smarcel
546130803Smarcel	for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) {
547130803Smarcel		if (ip6stat.ip6s_sources_otherscope[i]) {
548130803Smarcel			if (first) {
549130803Smarcel				xo_open_list("different-scope");
550130803Smarcel				xo_emit("\tsource addresses of a different "
551130803Smarcel				    "scope\n");
552130803Smarcel				first = 0;
553130803Smarcel			}
554130803Smarcel			xo_open_instance("different-scope");
555130803Smarcel			PRINT_SCOPESTAT(ip6s_sources_otherscope[i], i);
556130803Smarcel			xo_close_instance("different-scope");
557130803Smarcel		}
558130803Smarcel	}
559130803Smarcel	if (!first)
560130803Smarcel		xo_close_list("different-scope");
561130803Smarcel
562130803Smarcel	for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) {
563130803Smarcel		if (ip6stat.ip6s_sources_deprecated[i]) {
564130803Smarcel			if (first) {
565130803Smarcel				xo_open_list("deprecated-source");
566130803Smarcel				xo_emit("\tdeprecated source addresses\n");
567130803Smarcel				first = 0;
568130803Smarcel			}
569130803Smarcel			xo_open_instance("deprecated-source");
570130803Smarcel			PRINT_SCOPESTAT(ip6s_sources_deprecated[i], i);
571130803Smarcel			xo_close_instance("deprecated-source");
572130803Smarcel		}
573130803Smarcel	}
574130803Smarcel	if (!first)
575130803Smarcel		xo_close_list("deprecated-source");
576130803Smarcel
577130803Smarcel	for (first = 1, i = 0; i < IP6S_RULESMAX; i++) {
578130803Smarcel		if (ip6stat.ip6s_sources_rule[i]) {
579130803Smarcel			if (first) {
580130803Smarcel				xo_open_list("rules-applied");
581130803Smarcel				xo_emit("\t{T:Source addresses selection "
582130803Smarcel				    "rule applied}:\n");
583130803Smarcel				first = 0;
584130803Smarcel			}
585130803Smarcel			xo_open_instance("rules-applied");
586130803Smarcel			xo_emit("\t\t{ke:name/%s}{:count/%ju} {d:name/%s}\n",
587130803Smarcel			    srcrule_str[i],
588130803Smarcel			    (uintmax_t)ip6stat.ip6s_sources_rule[i],
589130803Smarcel			    srcrule_str[i]);
590130803Smarcel			xo_close_instance("rules-applied");
591130803Smarcel		}
592130803Smarcel	}
593130803Smarcel	if (!first)
594130803Smarcel		xo_close_list("rules-applied");
595130803Smarcel
596130803Smarcel	xo_close_container("source-address-selection");
597130803Smarcel
598130803Smarcel#undef p
599130803Smarcel#undef p1a
600130803Smarcel	xo_close_container(name);
601130803Smarcel}
602130803Smarcel
603130803Smarcel/*
604130803Smarcel * Dump IPv6 per-interface statistics based on RFC 2465.
605130803Smarcel */
606130803Smarcelvoid
607130803Smarcelip6_ifstats(char *ifname)
608130803Smarcel{
609130803Smarcel	struct in6_ifreq ifr;
610130803Smarcel	int s;
611130803Smarcel
612130803Smarcel#define	p(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1)	\
613130803Smarcel	xo_emit(m, (uintmax_t)ifr.ifr_ifru.ifru_stat.f,		\
614130803Smarcel	    plural(ifr.ifr_ifru.ifru_stat.f))
615130803Smarcel
616130803Smarcel	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
617130803Smarcel		xo_warn("Warning: socket(AF_INET6)");
618130803Smarcel		return;
619130803Smarcel	}
620130803Smarcel
621130803Smarcel	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
622130803Smarcel	if (ioctl(s, SIOCGIFSTAT_IN6, (char *)&ifr) < 0) {
623130803Smarcel		if (errno != EPFNOSUPPORT)
624130803Smarcel			xo_warn("Warning: ioctl(SIOCGIFSTAT_IN6)");
625130803Smarcel		goto end;
626130803Smarcel	}
627130803Smarcel
628130803Smarcel	xo_emit("{T:/ip6 on %s}:\n", ifr.ifr_name);
629130803Smarcel
630130803Smarcel	xo_open_instance("ip6-interface-statistics");
631130803Smarcel	xo_emit("{ke:name/%s}", ifr.ifr_name);
632130803Smarcel
633130803Smarcel	p(ifs6_in_receive, "\t{:received-packets/%ju} "
634130803Smarcel	    "{N:/total input datagram%s}\n");
635130803Smarcel	p(ifs6_in_hdrerr, "\t{:dropped-invalid-header/%ju} "
636130803Smarcel	    "{N:/datagram%s with invalid header received}\n");
637130803Smarcel	p(ifs6_in_toobig, "\t{:dropped-mtu-exceeded/%ju} "
638130803Smarcel	    "{N:/datagram%s exceeded MTU received}\n");
639130803Smarcel	p(ifs6_in_noroute, "\t{:dropped-no-route/%ju} "
640130803Smarcel	    "{N:/datagram%s with no route received}\n");
641130803Smarcel	p(ifs6_in_addrerr, "\t{:dropped-invalid-destination/%ju} "
642130803Smarcel	    "{N:/datagram%s with invalid dst received}\n");
643130803Smarcel	p(ifs6_in_protounknown, "\t{:dropped-unknown-protocol/%ju} "
644130803Smarcel	    "{N:/datagram%s with unknown proto received}\n");
645130803Smarcel	p(ifs6_in_truncated, "\t{:dropped-truncated/%ju} "
646130803Smarcel	    "{N:/truncated datagram%s received}\n");
647130803Smarcel	p(ifs6_in_discard, "\t{:dropped-discarded/%ju} "
648130803Smarcel	    "{N:/input datagram%s discarded}\n");
649130803Smarcel 	p(ifs6_in_deliver, "\t{:received-valid-packets/%ju} "
650130803Smarcel	    "{N:/datagram%s delivered to an upper layer protocol}\n");
651130803Smarcel	p(ifs6_out_forward, "\t{:sent-forwarded/%ju} "
652130803Smarcel	    "{N:/datagram%s forwarded to this interface}\n");
653130803Smarcel 	p(ifs6_out_request, "\t{:sent-packets/%ju} "
654130803Smarcel	    "{N:/datagram%s sent from an upper layer protocol}\n");
655130803Smarcel	p(ifs6_out_discard, "\t{:discard-packets/%ju} "
656130803Smarcel	    "{N:/total discarded output datagram%s}\n");
657130803Smarcel	p(ifs6_out_fragok, "\t{:discard-fragments/%ju} "
658130803Smarcel	    "{N:/output datagram%s fragmented}\n");
659130803Smarcel	p(ifs6_out_fragfail, "\t{:fragments-failed/%ju} "
660130803Smarcel	    "{N:/output datagram%s failed on fragment}\n");
661130803Smarcel	p(ifs6_out_fragcreat, "\t{:fragments-created/%ju} "
662130803Smarcel	    "{N:/output datagram%s succeeded on fragment}\n");
663130803Smarcel	p(ifs6_reass_reqd, "\t{:reassembly-required/%ju} "
664130803Smarcel	    "{N:/incoming datagram%s fragmented}\n");
665130803Smarcel	p(ifs6_reass_ok, "\t{:reassembled-packets/%ju} "
666130803Smarcel	    "{N:/datagram%s reassembled}\n");
667130803Smarcel	p(ifs6_reass_fail, "\t{:reassembly-failed/%ju} "
668130803Smarcel	    "{N:/datagram%s failed on reassembly}\n");
669130803Smarcel	p(ifs6_in_mcast, "\t{:received-multicast/%ju} "
670130803Smarcel	    "{N:/multicast datagram%s received}\n");
671130803Smarcel	p(ifs6_out_mcast, "\t{:sent-multicast/%ju} "
672130803Smarcel	    "{N:/multicast datagram%s sent}\n");
673130803Smarcel
674130803Smarcel end:
675130803Smarcel	xo_close_instance("ip6-interface-statistics");
676130803Smarcel 	close(s);
677130803Smarcel
678130803Smarcel#undef p
679130803Smarcel}
680130803Smarcel
681130803Smarcelstatic	const char *icmp6names[] = {
682130803Smarcel	"#0",
683130803Smarcel	"unreach",
684130803Smarcel	"packet too big",
685130803Smarcel	"time exceed",
686130803Smarcel	"parameter problem",
687130803Smarcel	"#5",
688130803Smarcel	"#6",
689130803Smarcel	"#7",
690130803Smarcel	"#8",
691130803Smarcel	"#9",
692130803Smarcel	"#10",
693130803Smarcel	"#11",
694130803Smarcel	"#12",
695130803Smarcel	"#13",
696130803Smarcel	"#14",
697130803Smarcel	"#15",
698130803Smarcel	"#16",
699130803Smarcel	"#17",
700130803Smarcel	"#18",
701130803Smarcel	"#19",
702130803Smarcel	"#20",
703130803Smarcel	"#21",
704130803Smarcel	"#22",
705130803Smarcel	"#23",
706130803Smarcel	"#24",
707130803Smarcel	"#25",
708130803Smarcel	"#26",
709130803Smarcel	"#27",
710130803Smarcel	"#28",
711130803Smarcel	"#29",
712130803Smarcel	"#30",
713130803Smarcel	"#31",
714130803Smarcel	"#32",
715130803Smarcel	"#33",
716130803Smarcel	"#34",
717130803Smarcel	"#35",
718130803Smarcel	"#36",
719130803Smarcel	"#37",
720130803Smarcel	"#38",
721130803Smarcel	"#39",
722130803Smarcel	"#40",
723130803Smarcel	"#41",
724130803Smarcel	"#42",
725130803Smarcel	"#43",
726130803Smarcel	"#44",
727130803Smarcel	"#45",
728130803Smarcel	"#46",
729130803Smarcel	"#47",
730130803Smarcel	"#48",
731130803Smarcel	"#49",
732130803Smarcel	"#50",
733130803Smarcel	"#51",
734130803Smarcel	"#52",
735130803Smarcel	"#53",
736130803Smarcel	"#54",
737130803Smarcel	"#55",
738130803Smarcel	"#56",
739130803Smarcel	"#57",
740130803Smarcel	"#58",
741130803Smarcel	"#59",
742130803Smarcel	"#60",
743130803Smarcel	"#61",
744130803Smarcel	"#62",
745130803Smarcel	"#63",
746130803Smarcel	"#64",
747130803Smarcel	"#65",
748130803Smarcel	"#66",
749130803Smarcel	"#67",
750130803Smarcel	"#68",
751130803Smarcel	"#69",
752130803Smarcel	"#70",
753130803Smarcel	"#71",
754130803Smarcel	"#72",
755130803Smarcel	"#73",
756130803Smarcel	"#74",
757130803Smarcel	"#75",
758130803Smarcel	"#76",
759130803Smarcel	"#77",
760130803Smarcel	"#78",
761130803Smarcel	"#79",
762130803Smarcel	"#80",
763130803Smarcel	"#81",
764130803Smarcel	"#82",
765130803Smarcel	"#83",
766130803Smarcel	"#84",
767130803Smarcel	"#85",
768130803Smarcel	"#86",
769130803Smarcel	"#87",
770130803Smarcel	"#88",
771130803Smarcel	"#89",
772130803Smarcel	"#80",
773130803Smarcel	"#91",
774130803Smarcel	"#92",
775130803Smarcel	"#93",
776130803Smarcel	"#94",
777130803Smarcel	"#95",
778130803Smarcel	"#96",
779130803Smarcel	"#97",
780130803Smarcel	"#98",
781130803Smarcel	"#99",
782130803Smarcel	"#100",
783130803Smarcel	"#101",
784130803Smarcel	"#102",
785130803Smarcel	"#103",
786130803Smarcel	"#104",
787130803Smarcel	"#105",
788130803Smarcel	"#106",
789130803Smarcel	"#107",
790130803Smarcel	"#108",
791130803Smarcel	"#109",
792130803Smarcel	"#110",
793130803Smarcel	"#111",
794130803Smarcel	"#112",
795130803Smarcel	"#113",
796130803Smarcel	"#114",
797130803Smarcel	"#115",
798130803Smarcel	"#116",
799130803Smarcel	"#117",
800130803Smarcel	"#118",
801130803Smarcel	"#119",
802130803Smarcel	"#120",
803130803Smarcel	"#121",
804130803Smarcel	"#122",
805130803Smarcel	"#123",
806130803Smarcel	"#124",
807130803Smarcel	"#125",
808130803Smarcel	"#126",
809130803Smarcel	"#127",
810130803Smarcel	"echo",
811130803Smarcel	"echo reply",
812130803Smarcel	"multicast listener query",
813130803Smarcel	"MLDv1 listener report",
814130803Smarcel	"MLDv1 listener done",
815130803Smarcel	"router solicitation",
816130803Smarcel	"router advertisement",
817130803Smarcel	"neighbor solicitation",
818130803Smarcel	"neighbor advertisement",
819130803Smarcel	"redirect",
820130803Smarcel	"router renumbering",
821130803Smarcel	"node information request",
822130803Smarcel	"node information reply",
823130803Smarcel	"inverse neighbor solicitation",
824130803Smarcel	"inverse neighbor advertisement",
825130803Smarcel	"MLDv2 listener report",
826130803Smarcel	"#144",
827130803Smarcel	"#145",
828130803Smarcel	"#146",
829130803Smarcel	"#147",
830130803Smarcel	"#148",
831130803Smarcel	"#149",
832130803Smarcel	"#150",
833130803Smarcel	"#151",
834130803Smarcel	"#152",
835130803Smarcel	"#153",
836130803Smarcel	"#154",
837130803Smarcel	"#155",
838130803Smarcel	"#156",
839130803Smarcel	"#157",
840130803Smarcel	"#158",
841130803Smarcel	"#159",
842130803Smarcel	"#160",
843130803Smarcel	"#161",
844130803Smarcel	"#162",
845130803Smarcel	"#163",
846130803Smarcel	"#164",
847130803Smarcel	"#165",
848130803Smarcel	"#166",
849130803Smarcel	"#167",
850130803Smarcel	"#168",
851130803Smarcel	"#169",
852130803Smarcel	"#170",
853130803Smarcel	"#171",
854130803Smarcel	"#172",
855130803Smarcel	"#173",
856130803Smarcel	"#174",
857130803Smarcel	"#175",
858130803Smarcel	"#176",
859130803Smarcel	"#177",
860130803Smarcel	"#178",
861130803Smarcel	"#179",
862130803Smarcel	"#180",
863130803Smarcel	"#181",
864130803Smarcel	"#182",
865130803Smarcel	"#183",
866130803Smarcel	"#184",
867130803Smarcel	"#185",
868130803Smarcel	"#186",
869130803Smarcel	"#187",
870130803Smarcel	"#188",
871130803Smarcel	"#189",
872130803Smarcel	"#180",
873130803Smarcel	"#191",
874130803Smarcel	"#192",
875130803Smarcel	"#193",
876130803Smarcel	"#194",
877130803Smarcel	"#195",
878130803Smarcel	"#196",
879130803Smarcel	"#197",
880130803Smarcel	"#198",
881130803Smarcel	"#199",
882130803Smarcel	"#200",
883130803Smarcel	"#201",
884130803Smarcel	"#202",
885130803Smarcel	"#203",
886130803Smarcel	"#204",
887130803Smarcel	"#205",
888130803Smarcel	"#206",
889130803Smarcel	"#207",
890130803Smarcel	"#208",
891130803Smarcel	"#209",
892130803Smarcel	"#210",
893130803Smarcel	"#211",
894130803Smarcel	"#212",
895130803Smarcel	"#213",
896130803Smarcel	"#214",
897130803Smarcel	"#215",
898130803Smarcel	"#216",
899130803Smarcel	"#217",
900130803Smarcel	"#218",
901130803Smarcel	"#219",
902130803Smarcel	"#220",
903130803Smarcel	"#221",
904130803Smarcel	"#222",
905130803Smarcel	"#223",
906130803Smarcel	"#224",
907130803Smarcel	"#225",
908130803Smarcel	"#226",
909130803Smarcel	"#227",
910130803Smarcel	"#228",
911130803Smarcel	"#229",
912130803Smarcel	"#230",
913130803Smarcel	"#231",
914130803Smarcel	"#232",
915130803Smarcel	"#233",
916130803Smarcel	"#234",
917130803Smarcel	"#235",
918130803Smarcel	"#236",
919130803Smarcel	"#237",
920130803Smarcel	"#238",
921130803Smarcel	"#239",
922130803Smarcel	"#240",
923130803Smarcel	"#241",
924130803Smarcel	"#242",
925130803Smarcel	"#243",
926130803Smarcel	"#244",
927130803Smarcel	"#245",
928130803Smarcel	"#246",
929130803Smarcel	"#247",
930130803Smarcel	"#248",
931130803Smarcel	"#249",
932130803Smarcel	"#250",
933130803Smarcel	"#251",
934130803Smarcel	"#252",
935130803Smarcel	"#253",
936130803Smarcel	"#254",
937130803Smarcel	"#255",
938130803Smarcel};
939130803Smarcel
940130803Smarcel/*
941130803Smarcel * Dump ICMP6 statistics.
942130803Smarcel */
943130803Smarcelvoid
944130803Smarcelicmp6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
945130803Smarcel{
946130803Smarcel	struct icmp6stat icmp6stat;
947130803Smarcel	int i, first;
948130803Smarcel
949130803Smarcel	if (fetch_stats("net.inet6.icmp6.stats", off, &icmp6stat,
950130803Smarcel	    sizeof(icmp6stat), kread_counters) != 0)
951130803Smarcel		return;
952130803Smarcel
953130803Smarcel	xo_emit("{T:/%s}:\n", name);
954130803Smarcel	xo_open_container(name);
955130803Smarcel
956130803Smarcel#define	p(f, m) if (icmp6stat.f || sflag <= 1) \
957130803Smarcel	xo_emit(m, (uintmax_t)icmp6stat.f, plural(icmp6stat.f))
958130803Smarcel#define	p_5(f, m) if (icmp6stat.f || sflag <= 1) \
959130803Smarcel	xo_emit(m, (uintmax_t)icmp6stat.f)
960130803Smarcel
961130803Smarcel	p(icp6s_error, "\t{:icmp6-calls/%ju} "
962130803Smarcel	    "{N:/call%s to icmp6_error}\n");
963130803Smarcel	p(icp6s_canterror, "\t{:errors-not-generated-from-message/%ju} "
964130803Smarcel	    "{N:/error%s not generated in response to an icmp6 message}\n");
965130803Smarcel	p(icp6s_toofreq, "\t{:errors-discarded-by-rate-limitation/%ju} "
966130803Smarcel	    "{N:/error%s not generated because of rate limitation}\n");
967130803Smarcel#define	NELEM (int)(sizeof(icmp6stat.icp6s_outhist)/sizeof(icmp6stat.icp6s_outhist[0]))
968130803Smarcel	for (first = 1, i = 0; i < NELEM; i++)
969130803Smarcel		if (icmp6stat.icp6s_outhist[i] != 0) {
970130803Smarcel			if (first) {
971130803Smarcel				xo_open_list("output-histogram");
972130803Smarcel				xo_emit("\t{T:Output histogram}:\n");
973130803Smarcel				first = 0;
974130803Smarcel			}
975130803Smarcel			xo_open_instance("output-histogram");
976130803Smarcel			xo_emit("\t\t{k:name/%s}: {:count/%ju}\n",
977130803Smarcel			    icmp6names[i],
978130803Smarcel			    (uintmax_t)icmp6stat.icp6s_outhist[i]);
979130803Smarcel			xo_close_instance("output-histogram");
980130803Smarcel		}
981130803Smarcel	if (!first)
982130803Smarcel		xo_close_list("output-histogram");
983130803Smarcel#undef NELEM
984130803Smarcel
985130803Smarcel	p(icp6s_badcode, "\t{:dropped-bad-code/%ju} "
986130803Smarcel	    "{N:/message%s with bad code fields}\n");
987130803Smarcel	p(icp6s_tooshort, "\t{:dropped-too-short/%ju} "
988130803Smarcel	    "{N:/message%s < minimum length}\n");
989130803Smarcel	p(icp6s_checksum, "\t{:dropped-bad-checksum/%ju} "
990130803Smarcel	    "{N:/bad checksum%s}\n");
991130803Smarcel	p(icp6s_badlen, "\t{:dropped-bad-length/%ju} "
992130803Smarcel	    "{N:/message%s with bad length}\n");
993130803Smarcel#define	NELEM (int)(sizeof(icmp6stat.icp6s_inhist)/sizeof(icmp6stat.icp6s_inhist[0]))
994130803Smarcel	for (first = 1, i = 0; i < NELEM; i++)
995130803Smarcel		if (icmp6stat.icp6s_inhist[i] != 0) {
996130803Smarcel			if (first) {
997130803Smarcel				xo_open_list("input-histogram");
998130803Smarcel				xo_emit("\t{T:Input histogram}:\n");
999130803Smarcel				first = 0;
1000130803Smarcel			}
1001130803Smarcel			xo_open_instance("input-histogram");
1002130803Smarcel			xo_emit("\t\t{k:name/%s}: {:count/%ju}\n",
1003130803Smarcel			    icmp6names[i],
1004130803Smarcel			    (uintmax_t)icmp6stat.icp6s_inhist[i]);
1005130803Smarcel			xo_close_instance("input-histogram");
1006130803Smarcel		}
1007130803Smarcel	if (!first)
1008130803Smarcel		xo_close_list("input-histogram");
1009130803Smarcel#undef NELEM
1010130803Smarcel	xo_emit("\t{T:Histogram of error messages to be generated}:\n");
1011130803Smarcel	xo_open_container("errors");
1012130803Smarcel	p_5(icp6s_odst_unreach_noroute, "\t\t{:no-route/%ju} "
1013130803Smarcel	    "{N:/no route}\n");
1014130803Smarcel	p_5(icp6s_odst_unreach_admin, "\t\t{:admin-prohibited/%ju} "
1015130803Smarcel	    "{N:/administratively prohibited}\n");
1016130803Smarcel	p_5(icp6s_odst_unreach_beyondscope, "\t\t{:beyond-scope/%ju} "
1017130803Smarcel	    "{N:/beyond scope}\n");
1018130803Smarcel	p_5(icp6s_odst_unreach_addr, "\t\t{:address-unreachable/%ju} "
1019130803Smarcel	    "{N:/address unreachable}\n");
1020130803Smarcel	p_5(icp6s_odst_unreach_noport, "\t\t{:port-unreachable/%ju} "
1021130803Smarcel	    "{N:/port unreachable}\n");
1022130803Smarcel	p_5(icp6s_opacket_too_big, "\t\t{:packet-too-big/%ju} "
1023130803Smarcel	    "{N:/packet too big}\n");
1024130803Smarcel	p_5(icp6s_otime_exceed_transit, "\t\t{:time-exceed-transmit/%ju} "
1025130803Smarcel	    "{N:/time exceed transit}\n");
1026130803Smarcel	p_5(icp6s_otime_exceed_reassembly, "\t\t{:time-exceed-reassembly/%ju} "
1027130803Smarcel	    "{N:/time exceed reassembly}\n");
1028130803Smarcel	p_5(icp6s_oparamprob_header, "\t\t{:bad-header/%ju} "
1029130803Smarcel	    "{N:/erroneous header field}\n");
1030130803Smarcel	p_5(icp6s_oparamprob_nextheader, "\t\t{:bad-next-header/%ju} "
1031130803Smarcel	    "{N:/unrecognized next header}\n");
1032130803Smarcel	p_5(icp6s_oparamprob_option, "\t\t{:bad-option/%ju} "
1033130803Smarcel	    "{N:/unrecognized option}\n");
1034130803Smarcel	p_5(icp6s_oredirect, "\t\t{:redirects/%ju} "
1035130803Smarcel	    "{N:/redirect}\n");
1036130803Smarcel	p_5(icp6s_ounknown, "\t\t{:unknown/%ju} {N:unknown}\n");
1037130803Smarcel
1038130803Smarcel	p(icp6s_reflect, "\t{:reflect/%ju} "
1039130803Smarcel	    "{N:/message response%s generated}\n");
1040130803Smarcel	p(icp6s_nd_toomanyopt, "\t{:too-many-nd-options/%ju} "
1041130803Smarcel	    "{N:/message%s with too many ND options}\n");
1042130803Smarcel	p(icp6s_nd_badopt, "\t{:bad-nd-options/%ju} "
1043130803Smarcel	    "{N:/message%s with bad ND options}\n");
1044130803Smarcel	p(icp6s_badns, "\t{:bad-neighbor-solicitation/%ju} "
1045130803Smarcel	    "{N:/bad neighbor solicitation message%s}\n");
1046130803Smarcel	p(icp6s_badna, "\t{:bad-neighbor-advertisement/%ju} "
1047130803Smarcel	    "{N:/bad neighbor advertisement message%s}\n");
1048130803Smarcel	p(icp6s_badrs, "\t{:bad-router-solicitation/%ju} "
1049130803Smarcel	    "{N:/bad router solicitation message%s}\n");
1050130803Smarcel	p(icp6s_badra, "\t{:bad-router-advertisement/%ju} "
1051130803Smarcel	    "{N:/bad router advertisement message%s}\n");
1052130803Smarcel	p(icp6s_badredirect, "\t{:bad-redirect/%ju} "
1053130803Smarcel	    "{N:/bad redirect message%s}\n");
1054130803Smarcel	xo_close_container("errors");
1055130803Smarcel	p(icp6s_pmtuchg, "\t{:path-mtu-changes/%ju} {N:/path MTU change%s}\n");
1056130803Smarcel#undef p
1057130803Smarcel#undef p_5
1058130803Smarcel	xo_close_container(name);
1059130803Smarcel}
1060130803Smarcel
1061130803Smarcel/*
1062130803Smarcel * Dump ICMPv6 per-interface statistics based on RFC 2466.
1063130803Smarcel */
1064130803Smarcelvoid
1065130803Smarcelicmp6_ifstats(char *ifname)
1066130803Smarcel{
1067130803Smarcel	struct in6_ifreq ifr;
1068130803Smarcel	int s;
1069130803Smarcel
1070130803Smarcel#define	p(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1)	\
1071130803Smarcel	xo_emit(m, (uintmax_t)ifr.ifr_ifru.ifru_icmp6stat.f,		\
1072130803Smarcel	    plural(ifr.ifr_ifru.ifru_icmp6stat.f))
1073130803Smarcel#define	p2(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1)	\
1074130803Smarcel	xo_emit(m, (uintmax_t)ifr.ifr_ifru.ifru_icmp6stat.f,		\
1075130803Smarcel	    pluralies(ifr.ifr_ifru.ifru_icmp6stat.f))
1076130803Smarcel
1077130803Smarcel	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1078130803Smarcel		xo_warn("Warning: socket(AF_INET6)");
1079130803Smarcel		return;
1080130803Smarcel	}
1081130803Smarcel
1082130803Smarcel	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1083130803Smarcel	if (ioctl(s, SIOCGIFSTAT_ICMP6, (char *)&ifr) < 0) {
1084130803Smarcel		if (errno != EPFNOSUPPORT)
1085130803Smarcel			xo_warn("Warning: ioctl(SIOCGIFSTAT_ICMP6)");
1086130803Smarcel		goto end;
1087130803Smarcel	}
1088130803Smarcel
1089130803Smarcel	xo_emit("{T:/icmp6 on %s}:\n", ifr.ifr_name);
1090130803Smarcel
1091130803Smarcel	xo_open_instance("icmp6-interface-statistics");
1092130803Smarcel	xo_emit("{ke:name/%s}", ifr.ifr_name);
1093130803Smarcel	p(ifs6_in_msg, "\t{:received-packets/%ju} "
1094130803Smarcel	    "{N:/total input message%s}\n");
1095130803Smarcel	p(ifs6_in_error, "\t{:received-errors/%ju} "
1096130803Smarcel	    "{N:/total input error message%s}\n");
1097130803Smarcel	p(ifs6_in_dstunreach, "\t{:received-destination-unreachable/%ju} "
1098130803Smarcel	    "{N:/input destination unreachable error%s}\n");
1099130803Smarcel	p(ifs6_in_adminprohib, "\t{:received-admin-prohibited/%ju} "
1100130803Smarcel	    "{N:/input administratively prohibited error%s}\n");
1101130803Smarcel	p(ifs6_in_timeexceed, "\t{:received-time-exceeded/%ju} "
1102130803Smarcel	    "{N:/input time exceeded error%s}\n");
1103130803Smarcel	p(ifs6_in_paramprob, "\t{:received-bad-parameter/%ju} "
1104130803Smarcel	    "{N:/input parameter problem error%s}\n");
1105130803Smarcel	p(ifs6_in_pkttoobig, "\t{:received-packet-too-big/%ju} "
1106130803Smarcel	    "{N:/input packet too big error%s}\n");
1107130803Smarcel	p(ifs6_in_echo, "\t{:received-echo-requests/%ju} "
1108130803Smarcel	    "{N:/input echo request%s}\n");
1109130803Smarcel	p2(ifs6_in_echoreply, "\t{:received-echo-replies/%ju} "
1110130803Smarcel	    "{N:/input echo repl%s}\n");
1111130803Smarcel	p(ifs6_in_routersolicit, "\t{:received-router-solicitation/%ju} "
1112130803Smarcel	    "{N:/input router solicitation%s}\n");
1113130803Smarcel	p(ifs6_in_routeradvert, "\t{:received-router-advertisement/%ju} "
1114130803Smarcel	    "{N:/input router advertisement%s}\n");
1115130803Smarcel	p(ifs6_in_neighborsolicit, "\t{:received-neighbor-solicitation/%ju} "
1116130803Smarcel	    "{N:/input neighbor solicitation%s}\n");
1117130803Smarcel	p(ifs6_in_neighboradvert, "\t{:received-neighbor-advertisement/%ju} "
1118130803Smarcel	    "{N:/input neighbor advertisement%s}\n");
1119130803Smarcel	p(ifs6_in_redirect, "\t{received-redirects/%ju} "
1120130803Smarcel	    "{N:/input redirect%s}\n");
1121130803Smarcel	p2(ifs6_in_mldquery, "\t{:received-mld-queries/%ju} "
1122130803Smarcel	    "{N:/input MLD quer%s}\n");
1123130803Smarcel	p(ifs6_in_mldreport, "\t{:received-mld-reports/%ju} "
1124130803Smarcel	    "{N:/input MLD report%s}\n");
1125130803Smarcel	p(ifs6_in_mlddone, "\t{:received-mld-done/%ju} "
1126130803Smarcel	    "{N:/input MLD done%s}\n");
1127130803Smarcel
1128130803Smarcel	p(ifs6_out_msg, "\t{:sent-packets/%ju} "
1129130803Smarcel	    "{N:/total output message%s}\n");
1130130803Smarcel	p(ifs6_out_error, "\t{:sent-errors/%ju} "
1131130803Smarcel	    "{N:/total output error message%s}\n");
1132130803Smarcel	p(ifs6_out_dstunreach, "\t{:sent-destination-unreachable/%ju} "
1133130803Smarcel	    "{N:/output destination unreachable error%s}\n");
1134130803Smarcel	p(ifs6_out_adminprohib, "\t{:sent-admin-prohibited/%ju} "
1135130803Smarcel	    "{N:/output administratively prohibited error%s}\n");
1136130803Smarcel	p(ifs6_out_timeexceed, "\t{:sent-time-exceeded/%ju} "
1137130803Smarcel	    "{N:/output time exceeded error%s}\n");
1138130803Smarcel	p(ifs6_out_paramprob, "\t{:sent-bad-parameter/%ju} "
1139130803Smarcel	    "{N:/output parameter problem error%s}\n");
1140130803Smarcel	p(ifs6_out_pkttoobig, "\t{:sent-packet-too-big/%ju} "
1141130803Smarcel	    "{N:/output packet too big error%s}\n");
1142130803Smarcel	p(ifs6_out_echo, "\t{:sent-echo-requests/%ju} "
1143130803Smarcel	    "{N:/output echo request%s}\n");
1144130803Smarcel	p2(ifs6_out_echoreply, "\t{:sent-echo-replies/%ju} "
1145130803Smarcel	    "{N:/output echo repl%s}\n");
1146130803Smarcel	p(ifs6_out_routersolicit, "\t{:sent-router-solicitation/%ju} "
1147130803Smarcel	    "{N:/output router solicitation%s}\n");
1148130803Smarcel	p(ifs6_out_routeradvert, "\t{:sent-router-advertisement/%ju} "
1149130803Smarcel	    "{N:/output router advertisement%s}\n");
1150130803Smarcel	p(ifs6_out_neighborsolicit, "\t{:sent-neighbor-solicitation/%ju} "
1151130803Smarcel	    "{N:/output neighbor solicitation%s}\n");
1152130803Smarcel	p(ifs6_out_neighboradvert, "\t{:sent-neighbor-advertisement/%ju} "
1153130803Smarcel	    "{N:/output neighbor advertisement%s}\n");
1154130803Smarcel	p(ifs6_out_redirect, "\t{:sent-redirects/%ju} "
1155130803Smarcel	    "{N:/output redirect%s}\n");
1156130803Smarcel	p2(ifs6_out_mldquery, "\t{:sent-mld-queries/%ju} "
1157130803Smarcel	    "{N:/output MLD quer%s}\n");
1158130803Smarcel	p(ifs6_out_mldreport, "\t{:sent-mld-reports/%ju} "
1159130803Smarcel	    "{N:/output MLD report%s}\n");
1160130803Smarcel	p(ifs6_out_mlddone, "\t{:sent-mld-dones/%ju} "
1161130803Smarcel	    "{N:/output MLD done%s}\n");
1162130803Smarcel
1163130803Smarcelend:
1164130803Smarcel	xo_close_instance("icmp6-interface-statistics");
1165130803Smarcel	close(s);
1166130803Smarcel#undef p
1167130803Smarcel}
1168130803Smarcel
1169130803Smarcel/*
1170130803Smarcel * Dump PIM statistics structure.
1171130803Smarcel */
1172130803Smarcelvoid
1173130803Smarcelpim6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
1174130803Smarcel{
1175130803Smarcel	struct pim6stat pim6stat;
1176130803Smarcel
1177130803Smarcel	if (fetch_stats("net.inet6.pim.stats", off, &pim6stat,
1178130803Smarcel	    sizeof(pim6stat), kread) != 0)
1179130803Smarcel		return;
1180130803Smarcel
1181130803Smarcel	xo_emit("{T:/%s}:\n", name);
1182130803Smarcel	xo_open_container(name);
1183130803Smarcel
1184130803Smarcel#define	p(f, m) if (pim6stat.f || sflag <= 1) \
1185130803Smarcel	xo_emit(m, (uintmax_t)pim6stat.f, plural(pim6stat.f))
1186130803Smarcel
1187130803Smarcel	p(pim6s_rcv_total, "\t{:received-packets/%ju} "
1188130803Smarcel	    "{N:/message%s received}\n");
1189130803Smarcel	p(pim6s_rcv_tooshort, "\t{:dropped-too-short/%ju} "
1190130803Smarcel	    "{N:/message%s received with too few bytes}\n");
1191130803Smarcel	p(pim6s_rcv_badsum, "\t{:dropped-bad-checksum/%ju} "
1192130803Smarcel	    "{N:/message%s received with bad checksum}\n");
1193130803Smarcel	p(pim6s_rcv_badversion, "\t{:dropped-bad-version/%ju} "
1194130803Smarcel	    "{N:/message%s received with bad version}\n");
1195130803Smarcel	p(pim6s_rcv_registers, "\t{:received-registers/%ju} "
1196130803Smarcel	    "{N:/register%s received}\n");
1197130803Smarcel	p(pim6s_rcv_badregisters, "\t{:received-bad-registers/%ju} "
1198130803Smarcel	    "{N:/bad register%s received}\n");
1199130803Smarcel	p(pim6s_snd_registers, "\t{:sent-registers/%ju} "
1200130803Smarcel	    "{N:/register%s sent}\n");
1201130803Smarcel#undef p
1202130803Smarcel	xo_close_container(name);
1203130803Smarcel}
1204130803Smarcel
1205130803Smarcel/*
1206130803Smarcel * Dump raw ip6 statistics structure.
1207130803Smarcel */
1208130803Smarcelvoid
1209130803Smarcelrip6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
1210130803Smarcel{
1211130803Smarcel	struct rip6stat rip6stat;
1212130803Smarcel	u_quad_t delivered;
1213130803Smarcel
1214130803Smarcel	if (fetch_stats("net.inet6.ip6.rip6stats", off, &rip6stat,
1215130803Smarcel	    sizeof(rip6stat), kread_counters) != 0)
1216130803Smarcel		return;
1217130803Smarcel
1218130803Smarcel	xo_emit("{T:/%s}:\n", name);
1219130803Smarcel	xo_open_container(name);
1220130803Smarcel
1221130803Smarcel#define	p(f, m) if (rip6stat.f || sflag <= 1) \
1222130803Smarcel	xo_emit(m, (uintmax_t)rip6stat.f, plural(rip6stat.f))
1223130803Smarcel
1224130803Smarcel	p(rip6s_ipackets, "\t{:received-packets/%ju} "
1225130803Smarcel	    "{N:/message%s received}\n");
1226130803Smarcel	p(rip6s_isum, "\t{:input-checksum-computation/%ju} "
1227130803Smarcel	    "{N:/checksum calculation%s on inbound}\n");
1228130803Smarcel	p(rip6s_badsum, "\t{:received-bad-checksum/%ju} "
1229130803Smarcel	    "{N:/message%s with bad checksum}\n");
1230130803Smarcel	p(rip6s_nosock, "\t{:dropped-no-socket/%ju} "
1231130803Smarcel	    "{N:/message%s dropped due to no socket}\n");
1232130803Smarcel	p(rip6s_nosockmcast, "\t{:dropped-multicast-no-socket/%ju} "
1233130803Smarcel	    "{N:/multicast message%s dropped due to no socket}\n");
1234130803Smarcel	p(rip6s_fullsock, "\t{:dropped-full-socket-buffer/%ju} "
1235130803Smarcel	    "{N:/message%s dropped due to full socket buffers}\n");
1236130803Smarcel	delivered = rip6stat.rip6s_ipackets -
1237130803Smarcel		    rip6stat.rip6s_badsum -
1238130803Smarcel		    rip6stat.rip6s_nosock -
1239130803Smarcel		    rip6stat.rip6s_nosockmcast -
1240130803Smarcel		    rip6stat.rip6s_fullsock;
1241130803Smarcel	if (delivered || sflag <= 1)
1242130803Smarcel		xo_emit("\t{:delivered-packets/%ju} {N:/delivered}\n",
1243130803Smarcel		    (uintmax_t)delivered);
1244130803Smarcel	p(rip6s_opackets, "\t{:sent-packets/%ju} "
1245130803Smarcel	    "{N:/datagram%s output}\n");
1246130803Smarcel#undef p
1247130803Smarcel	xo_close_container(name);
1248130803Smarcel}
1249130803Smarcel
1250130803Smarcel/*
1251130803Smarcel * Pretty print an Internet address (net address + port).
1252130803Smarcel * Take numeric_addr and numeric_port into consideration.
1253130803Smarcel */
1254130803Smarcel#define	GETSERVBYPORT6(port, proto, ret)\
1255130803Smarcel{\
1256130803Smarcel	if (strcmp((proto), "tcp6") == 0)\
1257130803Smarcel		(ret) = getservbyport((int)(port), "tcp");\
1258130803Smarcel	else if (strcmp((proto), "udp6") == 0)\
1259130803Smarcel		(ret) = getservbyport((int)(port), "udp");\
1260130803Smarcel	else\
1261130803Smarcel		(ret) = getservbyport((int)(port), (proto));\
1262130803Smarcel};
1263130803Smarcel
1264130803Smarcelvoid
1265130803Smarcelinet6print(const char *container, struct in6_addr *in6, int port,
1266130803Smarcel    const char *proto, int numeric)
1267130803Smarcel{
1268130803Smarcel	struct servent *sp = 0;
1269130803Smarcel	char line[80], *cp;
1270130803Smarcel	int width;
1271130803Smarcel	size_t alen, plen;
1272130803Smarcel
1273130803Smarcel	if (container)
1274130803Smarcel		xo_open_container(container);
1275130803Smarcel
1276130803Smarcel	snprintf(line, sizeof(line), "%.*s.",
1277130803Smarcel	    Wflag ? 39 : (Aflag && !numeric) ? 12 : 16,
1278130803Smarcel	    inet6name(in6));
1279130803Smarcel	alen = strlen(line);
1280130803Smarcel	cp = line + alen;
1281130803Smarcel	if (!numeric && port)
1282130803Smarcel		GETSERVBYPORT6(port, proto, sp);
1283130803Smarcel	if (sp || port == 0)
1284130803Smarcel		snprintf(cp, sizeof(line) - alen,
1285130803Smarcel		    "%.15s", sp ? sp->s_name : "*");
1286130803Smarcel	else
1287130803Smarcel		snprintf(cp, sizeof(line) - alen,
1288130803Smarcel		    "%d", ntohs((u_short)port));
1289130803Smarcel	width = Wflag ? 45 : Aflag ? 18 : 22;
1290130803Smarcel
1291130803Smarcel	xo_emit("{d:target/%-*.*s} ", width, width, line);
1292130803Smarcel
1293130803Smarcel	plen = strlen(cp);
1294130803Smarcel	alen--;
1295130803Smarcel	xo_emit("{e:address/%*.*s}{e:port/%*.*s}", alen, alen, line, plen,
1296130803Smarcel	    plen, cp);
1297130803Smarcel
1298130803Smarcel	if (container)
1299130803Smarcel		xo_close_container(container);
1300130803Smarcel}
1301130803Smarcel
1302130803Smarcel/*
1303130803Smarcel * Construct an Internet address representation.
1304130803Smarcel * If the numeric_addr has been supplied, give
1305130803Smarcel * numeric value, otherwise try for symbolic name.
1306130803Smarcel */
1307130803Smarcel
1308130803Smarcelchar *
1309130803Smarcelinet6name(struct in6_addr *ia6)
1310130803Smarcel{
1311130803Smarcel	struct sockaddr_in6 sin6;
1312130803Smarcel	char hbuf[NI_MAXHOST], *cp;
1313130803Smarcel	static char line[NI_MAXHOST];
1314130803Smarcel	static char domain[MAXHOSTNAMELEN];
1315130803Smarcel	static int first = 1;
1316130803Smarcel	int flags, error;
1317130803Smarcel
1318130803Smarcel	if (IN6_IS_ADDR_UNSPECIFIED(ia6)) {
1319130803Smarcel		strcpy(line, "*");
1320130803Smarcel		return (line);
1321130803Smarcel	}
1322130803Smarcel	if (first && !numeric_addr) {
1323130803Smarcel		first = 0;
1324130803Smarcel		if (gethostname(domain, sizeof(domain)) == 0 &&
1325130803Smarcel		    (cp = strchr(domain, '.')))
1326130803Smarcel			strlcpy(domain, cp + 1, sizeof(domain));
1327130803Smarcel		else
1328130803Smarcel			domain[0] = 0;
1329130803Smarcel	}
1330130803Smarcel	memset(&sin6, 0, sizeof(sin6));
1331130803Smarcel	memcpy(&sin6.sin6_addr, ia6, sizeof(*ia6));
1332130803Smarcel	sin6.sin6_family = AF_INET6;
1333130803Smarcel	/* XXX: ia6.s6_addr[2] can contain scopeid. */
1334130803Smarcel	in6_fillscopeid(&sin6);
1335130803Smarcel	flags = (numeric_addr) ? NI_NUMERICHOST : 0;
1336130803Smarcel	error = getnameinfo((struct sockaddr *)&sin6, sizeof(sin6), hbuf,
1337130803Smarcel	    sizeof(hbuf), NULL, 0, flags);
1338130803Smarcel	if (error == 0) {
1339130803Smarcel		if ((flags & NI_NUMERICHOST) == 0 &&
1340130803Smarcel		    (cp = strchr(hbuf, '.')) &&
1341130803Smarcel		    !strcmp(cp + 1, domain))
1342130803Smarcel			*cp = 0;
1343130803Smarcel		strlcpy(line, hbuf, sizeof(line));
1344130803Smarcel	} else {
1345130803Smarcel		/* XXX: this should not happen. */
1346130803Smarcel		snprintf(line, sizeof(line), "%s",
1347130803Smarcel			inet_ntop(AF_INET6, (void *)&sin6.sin6_addr, ntop_buf,
1348130803Smarcel				sizeof(ntop_buf)));
1349130803Smarcel	}
1350130803Smarcel	return (line);
1351130803Smarcel}
1352130803Smarcel#endif /*INET6*/
1353130803Smarcel