xref: /onnv-gate/usr/src/cmd/mdb/common/modules/ip/ip.c (revision 2546:3e3e9857b7e6)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*2546Scarlsonj  * Common Development and Distribution License (the "License").
6*2546Scarlsonj  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*2546Scarlsonj  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <sys/types.h>
290Sstevel@tonic-gate #include <sys/stropts.h>
300Sstevel@tonic-gate #include <sys/stream.h>
310Sstevel@tonic-gate #include <sys/socket.h>
320Sstevel@tonic-gate #include <sys/avl_impl.h>
330Sstevel@tonic-gate #include <net/if.h>
340Sstevel@tonic-gate #include <net/route.h>
350Sstevel@tonic-gate #include <netinet/in.h>
360Sstevel@tonic-gate #include <netinet/ip6.h>
370Sstevel@tonic-gate #include <netinet/udp.h>
380Sstevel@tonic-gate #include <netinet/sctp.h>
390Sstevel@tonic-gate #include <inet/mib2.h>
400Sstevel@tonic-gate #include <inet/common.h>
410Sstevel@tonic-gate #include <inet/ip.h>
420Sstevel@tonic-gate #include <inet/ip_ire.h>
430Sstevel@tonic-gate #include <inet/ip6.h>
440Sstevel@tonic-gate #include <inet/ipclassifier.h>
450Sstevel@tonic-gate #include <inet/mi.h>
460Sstevel@tonic-gate #include <sys/squeue_impl.h>
470Sstevel@tonic-gate 
480Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
490Sstevel@tonic-gate #include <mdb/mdb_ks.h>
500Sstevel@tonic-gate 
510Sstevel@tonic-gate #define	ADDR_WIDTH 11
520Sstevel@tonic-gate 
530Sstevel@tonic-gate typedef struct {
540Sstevel@tonic-gate 	const char *bit_name;	/* name of bit */
550Sstevel@tonic-gate 	const char *bit_descr;	/* description of bit's purpose */
560Sstevel@tonic-gate } bitname_t;
570Sstevel@tonic-gate 
580Sstevel@tonic-gate static const bitname_t squeue_states[] = {
590Sstevel@tonic-gate 	{ "SQS_PROC",		"being processed" },
600Sstevel@tonic-gate 	{ "SQS_WORKER",		"... by a worker thread" },
610Sstevel@tonic-gate 	{ "SQS_ENTER",		"... by an squeue_enter() thread" },
620Sstevel@tonic-gate 	{ "SQS_FAST",		"... in fast-path mode" },
630Sstevel@tonic-gate 	{ "SQS_USER", 		"A non interrupt user" },
640Sstevel@tonic-gate 	{ "SQS_BOUND",		"worker thread bound to CPU" },
650Sstevel@tonic-gate 	{ "SQS_PROFILE",	"profiling enabled" },
660Sstevel@tonic-gate 	{ "SQS_REENTER",	"re-entered thred" },
670Sstevel@tonic-gate 	{ NULL }
680Sstevel@tonic-gate };
690Sstevel@tonic-gate 
700Sstevel@tonic-gate typedef struct illif_walk_data {
710Sstevel@tonic-gate 	ill_g_head_t ill_g_heads[MAX_G_HEADS];
720Sstevel@tonic-gate 	int ill_list;
730Sstevel@tonic-gate 	ill_if_t ill_if;
740Sstevel@tonic-gate } illif_walk_data_t;
750Sstevel@tonic-gate 
760Sstevel@tonic-gate static int iphdr(uintptr_t, uint_t, int, const mdb_arg_t *);
770Sstevel@tonic-gate static int ip6hdr(uintptr_t, uint_t, int, const mdb_arg_t *);
780Sstevel@tonic-gate 
790Sstevel@tonic-gate int
800Sstevel@tonic-gate illif_walk_init(mdb_walk_state_t *wsp)
810Sstevel@tonic-gate {
820Sstevel@tonic-gate 	illif_walk_data_t *iw;
830Sstevel@tonic-gate 
840Sstevel@tonic-gate 	if (wsp->walk_addr != NULL) {
850Sstevel@tonic-gate 		mdb_warn("illif supports only global walks\n");
860Sstevel@tonic-gate 		return (WALK_ERR);
870Sstevel@tonic-gate 	}
880Sstevel@tonic-gate 
890Sstevel@tonic-gate 	iw = mdb_alloc(sizeof (illif_walk_data_t), UM_SLEEP);
900Sstevel@tonic-gate 
910Sstevel@tonic-gate 	if (mdb_readsym(iw->ill_g_heads, MAX_G_HEADS * sizeof (ill_g_head_t),
920Sstevel@tonic-gate 	    "ill_g_heads") == -1) {
930Sstevel@tonic-gate 		mdb_warn("failed to read 'ill_g_heads'");
940Sstevel@tonic-gate 		mdb_free(iw, sizeof (illif_walk_data_t));
950Sstevel@tonic-gate 		return (WALK_ERR);
960Sstevel@tonic-gate 	}
970Sstevel@tonic-gate 
980Sstevel@tonic-gate 	iw->ill_list = 0;
990Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)iw->IP_VX_ILL_G_LIST(0);
1000Sstevel@tonic-gate 	wsp->walk_data = iw;
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate 	return (WALK_NEXT);
1030Sstevel@tonic-gate }
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate int
1060Sstevel@tonic-gate illif_walk_step(mdb_walk_state_t *wsp)
1070Sstevel@tonic-gate {
1080Sstevel@tonic-gate 	uintptr_t addr = wsp->walk_addr;
1090Sstevel@tonic-gate 	illif_walk_data_t *iw = wsp->walk_data;
1100Sstevel@tonic-gate 	int list = iw->ill_list;
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 	if (mdb_vread(&iw->ill_if, sizeof (ill_if_t), addr) == -1) {
1130Sstevel@tonic-gate 		mdb_warn("failed to read ill_if_t at %p", addr);
1140Sstevel@tonic-gate 		return (WALK_ERR);
1150Sstevel@tonic-gate 	}
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)iw->ill_if.illif_next;
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate 	if (wsp->walk_addr == (uintptr_t)iw->IP_VX_ILL_G_LIST(list)) {
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate 		if (++list >= MAX_G_HEADS)
1220Sstevel@tonic-gate 			return (WALK_DONE);
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate 		iw->ill_list = list;
1250Sstevel@tonic-gate 		wsp->walk_addr = (uintptr_t)iw->IP_VX_ILL_G_LIST(list);
1260Sstevel@tonic-gate 		return (WALK_NEXT);
1270Sstevel@tonic-gate 	}
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate 	return (wsp->walk_callback(addr, iw, wsp->walk_cbdata));
1300Sstevel@tonic-gate }
1310Sstevel@tonic-gate 
1320Sstevel@tonic-gate void
1330Sstevel@tonic-gate illif_walk_fini(mdb_walk_state_t *wsp)
1340Sstevel@tonic-gate {
1350Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (illif_walk_data_t));
1360Sstevel@tonic-gate }
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate typedef struct illif_cbdata {
1390Sstevel@tonic-gate 	uint_t ill_flags;
1400Sstevel@tonic-gate 	uintptr_t ill_addr;
1410Sstevel@tonic-gate 	int ill_printlist;	/* list to be printed (MAX_G_HEADS for all) */
1420Sstevel@tonic-gate 	boolean_t ill_printed;
1430Sstevel@tonic-gate } illif_cbdata_t;
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate static int
1460Sstevel@tonic-gate illif_cb(uintptr_t addr, const illif_walk_data_t *iw, illif_cbdata_t *id)
1470Sstevel@tonic-gate {
1480Sstevel@tonic-gate 	const char *version;
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate 	if (id->ill_printlist < MAX_G_HEADS &&
1510Sstevel@tonic-gate 	    id->ill_printlist != iw->ill_list)
1520Sstevel@tonic-gate 		return (WALK_NEXT);
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate 	if (id->ill_flags & DCMD_ADDRSPEC && id->ill_addr != addr)
1550Sstevel@tonic-gate 		return (WALK_NEXT);
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate 	if (id->ill_flags & DCMD_PIPE_OUT) {
1580Sstevel@tonic-gate 		mdb_printf("%p\n", addr);
1590Sstevel@tonic-gate 		return (WALK_NEXT);
1600Sstevel@tonic-gate 	}
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate 	switch (iw->ill_list) {
1630Sstevel@tonic-gate 		case IP_V4_G_HEAD:	version = "v4";	break;
1640Sstevel@tonic-gate 		case IP_V6_G_HEAD:	version = "v6";	break;
1650Sstevel@tonic-gate 		default:		version = "??"; break;
1660Sstevel@tonic-gate 	}
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate 	mdb_printf("%?p %2s %?p %10d %?p %s\n",
1690Sstevel@tonic-gate 	    addr, version, addr + offsetof(ill_if_t, illif_avl_by_ppa),
1700Sstevel@tonic-gate 	    iw->ill_if.illif_avl_by_ppa.avl_numnodes,
1710Sstevel@tonic-gate 	    iw->ill_if.illif_ppa_arena, iw->ill_if.illif_name);
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 	id->ill_printed = TRUE;
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 	return (WALK_NEXT);
1760Sstevel@tonic-gate }
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate int
1790Sstevel@tonic-gate illif(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1800Sstevel@tonic-gate {
1810Sstevel@tonic-gate 	illif_cbdata_t id;
1820Sstevel@tonic-gate 	ill_if_t ill_if;
1830Sstevel@tonic-gate 	const char *opt_P = NULL;
1840Sstevel@tonic-gate 	int printlist = MAX_G_HEADS;
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
1870Sstevel@tonic-gate 	    'P', MDB_OPT_STR, &opt_P, NULL) != argc)
1880Sstevel@tonic-gate 		return (DCMD_USAGE);
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate 	if (opt_P != NULL) {
1910Sstevel@tonic-gate 		if (strcmp("v4", opt_P) == 0) {
1920Sstevel@tonic-gate 			printlist = IP_V4_G_HEAD;
1930Sstevel@tonic-gate 		} else if (strcmp("v6", opt_P) == 0) {
1940Sstevel@tonic-gate 			printlist = IP_V6_G_HEAD;
1950Sstevel@tonic-gate 		} else {
1960Sstevel@tonic-gate 			mdb_warn("invalid protocol '%s'\n", opt_P);
1970Sstevel@tonic-gate 			return (DCMD_USAGE);
1980Sstevel@tonic-gate 		}
1990Sstevel@tonic-gate 	}
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags) && (flags & DCMD_PIPE_OUT) == 0) {
2020Sstevel@tonic-gate 		mdb_printf("%<u>%?s %2s %?s %10s %?s %-10s%</u>\n",
2030Sstevel@tonic-gate 		    "ADDR", "IP", "AVLADDR", "NUMNODES", "ARENA", "NAME");
2040Sstevel@tonic-gate 	}
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 	id.ill_flags = flags;
2070Sstevel@tonic-gate 	id.ill_addr = addr;
2080Sstevel@tonic-gate 	id.ill_printlist = printlist;
2090Sstevel@tonic-gate 	id.ill_printed = FALSE;
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate 	if (mdb_walk("illif", (mdb_walk_cb_t)illif_cb, &id) == -1) {
2120Sstevel@tonic-gate 		mdb_warn("can't walk ill_if_t structures");
2130Sstevel@tonic-gate 		return (DCMD_ERR);
2140Sstevel@tonic-gate 	}
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC) || opt_P != NULL || id.ill_printed)
2170Sstevel@tonic-gate 		return (DCMD_OK);
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 	/*
2200Sstevel@tonic-gate 	 * If an address is specified and the walk doesn't find it,
2210Sstevel@tonic-gate 	 * print it anyway.
2220Sstevel@tonic-gate 	 */
2230Sstevel@tonic-gate 	if (mdb_vread(&ill_if, sizeof (ill_if_t), addr) == -1) {
2240Sstevel@tonic-gate 		mdb_warn("failed to read ill_if_t at %p", addr);
2250Sstevel@tonic-gate 		return (DCMD_ERR);
2260Sstevel@tonic-gate 	}
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 	mdb_printf("%?p %2s %?p %10d %?p %s\n",
2290Sstevel@tonic-gate 	    addr, "??", addr + offsetof(ill_if_t, illif_avl_by_ppa),
2300Sstevel@tonic-gate 	    ill_if.illif_avl_by_ppa.avl_numnodes,
2310Sstevel@tonic-gate 	    ill_if.illif_ppa_arena, ill_if.illif_name);
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 	return (DCMD_OK);
2340Sstevel@tonic-gate }
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate static void
2370Sstevel@tonic-gate illif_help(void)
2380Sstevel@tonic-gate {
2390Sstevel@tonic-gate 	mdb_printf("Options:\n");
2400Sstevel@tonic-gate 	mdb_printf("\t-P v4 | v6"
2410Sstevel@tonic-gate 	    "\tfilter interface structures for the specified protocol\n");
2420Sstevel@tonic-gate }
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate int
2450Sstevel@tonic-gate ire_walk_init(mdb_walk_state_t *wsp)
2460Sstevel@tonic-gate {
2470Sstevel@tonic-gate 	if (mdb_layered_walk("ire_cache", wsp) == -1) {
2480Sstevel@tonic-gate 		mdb_warn("can't walk 'ire_cache'");
2490Sstevel@tonic-gate 		return (WALK_ERR);
2500Sstevel@tonic-gate 	}
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 	return (WALK_NEXT);
2530Sstevel@tonic-gate }
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate int
2560Sstevel@tonic-gate ire_walk_step(mdb_walk_state_t *wsp)
2570Sstevel@tonic-gate {
2580Sstevel@tonic-gate 	ire_t ire;
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 	if (mdb_vread(&ire, sizeof (ire), wsp->walk_addr) == -1) {
2610Sstevel@tonic-gate 		mdb_warn("can't read ire at %p", wsp->walk_addr);
2620Sstevel@tonic-gate 		return (WALK_ERR);
2630Sstevel@tonic-gate 	}
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 	return (wsp->walk_callback(wsp->walk_addr, &ire, wsp->walk_cbdata));
2660Sstevel@tonic-gate }
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate static int
2690Sstevel@tonic-gate ire_format(uintptr_t addr, const ire_t *irep, uint_t *verbose)
2700Sstevel@tonic-gate {
2710Sstevel@tonic-gate 	static const mdb_bitmask_t tmasks[] = {
2720Sstevel@tonic-gate 		{ "BROADCAST",	IRE_BROADCAST,		IRE_BROADCAST	},
2730Sstevel@tonic-gate 		{ "DEFAULT",	IRE_DEFAULT,		IRE_DEFAULT	},
2740Sstevel@tonic-gate 		{ "LOCAL",	IRE_LOCAL,		IRE_LOCAL	},
2750Sstevel@tonic-gate 		{ "LOOPBACK",	IRE_LOOPBACK,		IRE_LOOPBACK	},
2760Sstevel@tonic-gate 		{ "PREFIX",	IRE_PREFIX,		IRE_PREFIX	},
2770Sstevel@tonic-gate 		{ "CACHE",	IRE_CACHE,		IRE_CACHE	},
2780Sstevel@tonic-gate 		{ "IF_NORESOLVER", IRE_IF_NORESOLVER,	IRE_IF_NORESOLVER },
2790Sstevel@tonic-gate 		{ "IF_RESOLVER", IRE_IF_RESOLVER,	IRE_IF_RESOLVER	},
2800Sstevel@tonic-gate 		{ "HOST",	IRE_HOST,		IRE_HOST	},
2810Sstevel@tonic-gate 		{ "HOST_REDIRECT", IRE_HOST_REDIRECT,	IRE_HOST_REDIRECT },
2820Sstevel@tonic-gate 		{ "MIPRTUN",	IRE_MIPRTUN,		IRE_MIPRTUN	},
2830Sstevel@tonic-gate 		{ NULL,		0,			0		}
2840Sstevel@tonic-gate 	};
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 	static const mdb_bitmask_t mmasks[] = {
2870Sstevel@tonic-gate 		{ "CONDEMNED",	IRE_MARK_CONDEMNED,	IRE_MARK_CONDEMNED },
2880Sstevel@tonic-gate 		{ "NORECV",	IRE_MARK_NORECV,	IRE_MARK_NORECV	},
2890Sstevel@tonic-gate 		{ "HIDDEN",	IRE_MARK_HIDDEN,	IRE_MARK_HIDDEN	},
2900Sstevel@tonic-gate 		{ "NOADD",	IRE_MARK_NOADD,		IRE_MARK_NOADD	},
2910Sstevel@tonic-gate 		{ "TEMPORARY",	IRE_MARK_TEMPORARY,	IRE_MARK_TEMPORARY },
2920Sstevel@tonic-gate 		{ NULL,		0,			0		}
2930Sstevel@tonic-gate 	};
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate 	static const mdb_bitmask_t fmasks[] = {
2960Sstevel@tonic-gate 		{ "UP",		RTF_UP,			RTF_UP		},
2970Sstevel@tonic-gate 		{ "GATEWAY",	RTF_GATEWAY,		RTF_GATEWAY	},
2980Sstevel@tonic-gate 		{ "HOST",	RTF_HOST,		RTF_HOST	},
2990Sstevel@tonic-gate 		{ "REJECT",	RTF_REJECT,		RTF_REJECT	},
3000Sstevel@tonic-gate 		{ "DYNAMIC",	RTF_DYNAMIC,		RTF_DYNAMIC	},
3010Sstevel@tonic-gate 		{ "MODIFIED",	RTF_MODIFIED,		RTF_MODIFIED	},
3020Sstevel@tonic-gate 		{ "DONE",	RTF_DONE,		RTF_DONE	},
3030Sstevel@tonic-gate 		{ "MASK",	RTF_MASK,		RTF_MASK	},
3040Sstevel@tonic-gate 		{ "CLONING",	RTF_CLONING,		RTF_CLONING	},
3050Sstevel@tonic-gate 		{ "XRESOLVE",	RTF_XRESOLVE,		RTF_XRESOLVE	},
3060Sstevel@tonic-gate 		{ "LLINFO",	RTF_LLINFO,		RTF_LLINFO	},
3070Sstevel@tonic-gate 		{ "STATIC",	RTF_STATIC,		RTF_STATIC	},
3080Sstevel@tonic-gate 		{ "BLACKHOLE",	RTF_BLACKHOLE,		RTF_BLACKHOLE	},
3090Sstevel@tonic-gate 		{ "PRIVATE",	RTF_PRIVATE,		RTF_PRIVATE	},
3100Sstevel@tonic-gate 		{ "PROTO2",	RTF_PROTO2,		RTF_PROTO2	},
3110Sstevel@tonic-gate 		{ "PROTO1",	RTF_PROTO1,		RTF_PROTO1	},
3120Sstevel@tonic-gate 		{ "MULTIRT",	RTF_MULTIRT,		RTF_MULTIRT	},
3130Sstevel@tonic-gate 		{ "SETSRC",	RTF_SETSRC,		RTF_SETSRC	},
3140Sstevel@tonic-gate 		{ NULL,		0,			0		}
3150Sstevel@tonic-gate 	};
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 	if (irep->ire_ipversion == 6 && *verbose) {
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 		mdb_printf("%<b>%?p%</b> %40N <%hb>\n"
3200Sstevel@tonic-gate 		    "%?s %40N <%hb>\n"
3210Sstevel@tonic-gate 		    "%?s %40d <%hb>\n",
3220Sstevel@tonic-gate 		    addr, &irep->ire_src_addr_v6, irep->ire_type, tmasks,
3230Sstevel@tonic-gate 		    "", &irep->ire_addr_v6, (ushort_t)irep->ire_marks, mmasks,
3240Sstevel@tonic-gate 		    "", irep->ire_zoneid, irep->ire_flags, fmasks);
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 	} else if (irep->ire_ipversion == 6) {
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 		mdb_printf("%?p %30N %30N %4d\n", addr, &irep->ire_src_addr_v6,
3290Sstevel@tonic-gate 		    &irep->ire_addr_v6, irep->ire_zoneid);
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate 	} else if (*verbose) {
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 		mdb_printf("%<b>%?p%</b> %40I <%hb>\n"
3340Sstevel@tonic-gate 		    "%?s %40I <%hb>\n"
3350Sstevel@tonic-gate 		    "%?s %40d <%hb>\n",
3360Sstevel@tonic-gate 		    addr, irep->ire_src_addr, irep->ire_type, tmasks,
3370Sstevel@tonic-gate 		    "", irep->ire_addr, (ushort_t)irep->ire_marks, mmasks,
3380Sstevel@tonic-gate 		    "", irep->ire_zoneid, irep->ire_flags, fmasks);
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 	} else {
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate 		mdb_printf("%?p %30I %30I %4d\n", addr, irep->ire_src_addr,
3430Sstevel@tonic-gate 		    irep->ire_addr, irep->ire_zoneid);
3440Sstevel@tonic-gate 	}
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate 	return (WALK_NEXT);
3470Sstevel@tonic-gate }
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate /*
3500Sstevel@tonic-gate  * There are faster ways to do this.  Given the interactive nature of this
3510Sstevel@tonic-gate  * use I don't think its worth much effort.
3520Sstevel@tonic-gate  */
3530Sstevel@tonic-gate static unsigned short
3540Sstevel@tonic-gate ipcksum(void *p, int len)
3550Sstevel@tonic-gate {
3560Sstevel@tonic-gate 	int32_t	sum = 0;
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 	while (len > 1) {
3590Sstevel@tonic-gate 		/* alignment */
3600Sstevel@tonic-gate 		sum += *(uint16_t *)p;
3610Sstevel@tonic-gate 		p = (char *)p + sizeof (uint16_t);
3620Sstevel@tonic-gate 		if (sum & 0x80000000)
3630Sstevel@tonic-gate 			sum = (sum & 0xFFFF) + (sum >> 16);
3640Sstevel@tonic-gate 		len -= 2;
3650Sstevel@tonic-gate 	}
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 	if (len)
3680Sstevel@tonic-gate 		sum += (uint16_t)*(unsigned char *)p;
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 	while (sum >> 16)
3710Sstevel@tonic-gate 		sum = (sum & 0xFFFF) + (sum >> 16);
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate 	return (~sum);
3740Sstevel@tonic-gate }
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate static const mdb_bitmask_t tcp_flags[] = {
3770Sstevel@tonic-gate 	{ "SYN",	TH_SYN,		TH_SYN	},
3780Sstevel@tonic-gate 	{ "ACK",	TH_ACK,		TH_ACK	},
3790Sstevel@tonic-gate 	{ "FIN",	TH_FIN,		TH_FIN	},
3800Sstevel@tonic-gate 	{ "RST",	TH_RST,		TH_RST	},
3810Sstevel@tonic-gate 	{ "PSH",	TH_PUSH,	TH_PUSH	},
3820Sstevel@tonic-gate 	{ "ECE",	TH_ECE,		TH_ECE	},
3830Sstevel@tonic-gate 	{ "CWR",	TH_CWR,		TH_CWR	},
3840Sstevel@tonic-gate 	{ NULL,		0,		0	}
3850Sstevel@tonic-gate };
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate static void
3880Sstevel@tonic-gate tcphdr_print(struct tcphdr *tcph)
3890Sstevel@tonic-gate {
3900Sstevel@tonic-gate 	in_port_t	sport, dport;
3910Sstevel@tonic-gate 	tcp_seq		seq, ack;
3920Sstevel@tonic-gate 	uint16_t	win, urp;
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	mdb_printf("%<b>TCP header%</b>\n");
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 	mdb_nhconvert(&sport, &tcph->th_sport, sizeof (sport));
3970Sstevel@tonic-gate 	mdb_nhconvert(&dport, &tcph->th_dport, sizeof (dport));
3980Sstevel@tonic-gate 	mdb_nhconvert(&seq, &tcph->th_seq, sizeof (seq));
3990Sstevel@tonic-gate 	mdb_nhconvert(&ack, &tcph->th_ack, sizeof (ack));
4000Sstevel@tonic-gate 	mdb_nhconvert(&win, &tcph->th_win, sizeof (win));
4010Sstevel@tonic-gate 	mdb_nhconvert(&urp, &tcph->th_urp, sizeof (urp));
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 	mdb_printf("%<u>%6s %6s %10s %10s %4s %5s %5s %5s %-15s%</u>\n",
4040Sstevel@tonic-gate 	    "SPORT", "DPORT", "SEQ", "ACK", "HLEN", "WIN", "CSUM", "URP",
4050Sstevel@tonic-gate 	    "FLAGS");
4060Sstevel@tonic-gate 	mdb_printf("%6hu %6hu %10u %10u %4d %5hu %5hu %5hu <%b>\n",
4070Sstevel@tonic-gate 	    sport, dport, seq, ack, tcph->th_off << 2, win,
4080Sstevel@tonic-gate 	    tcph->th_sum, urp, tcph->th_flags, tcp_flags);
4090Sstevel@tonic-gate 	mdb_printf("0x%04x 0x%04x 0x%08x 0x%08x\n\n",
4100Sstevel@tonic-gate 	    sport, dport, seq, ack);
4110Sstevel@tonic-gate }
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate /* ARGSUSED */
4140Sstevel@tonic-gate static int
4150Sstevel@tonic-gate tcphdr(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av)
4160Sstevel@tonic-gate {
4170Sstevel@tonic-gate 	struct tcphdr	tcph;
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
4200Sstevel@tonic-gate 		return (DCMD_USAGE);
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 	if (mdb_vread(&tcph, sizeof (tcph), addr) == -1) {
4230Sstevel@tonic-gate 		mdb_warn("failed to read TCP header at %p", addr);
4240Sstevel@tonic-gate 		return (DCMD_ERR);
4250Sstevel@tonic-gate 	}
4260Sstevel@tonic-gate 	tcphdr_print(&tcph);
4270Sstevel@tonic-gate 	return (DCMD_OK);
4280Sstevel@tonic-gate }
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate static void
4310Sstevel@tonic-gate udphdr_print(struct udphdr *udph)
4320Sstevel@tonic-gate {
4330Sstevel@tonic-gate 	in_port_t	sport, dport;
4340Sstevel@tonic-gate 	uint16_t	hlen;
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 	mdb_printf("%<b>UDP header%</b>\n");
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate 	mdb_nhconvert(&sport, &udph->uh_sport, sizeof (sport));
4390Sstevel@tonic-gate 	mdb_nhconvert(&dport, &udph->uh_dport, sizeof (dport));
4400Sstevel@tonic-gate 	mdb_nhconvert(&hlen, &udph->uh_ulen, sizeof (hlen));
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 	mdb_printf("%<u>%14s %14s %5s %6s%</u>\n",
4430Sstevel@tonic-gate 	    "SPORT", "DPORT", "LEN", "CSUM");
4440Sstevel@tonic-gate 	mdb_printf("%5hu (0x%04x) %5hu (0x%04x) %5hu 0x%04hx\n\n", sport, sport,
4450Sstevel@tonic-gate 	    dport, dport, hlen, udph->uh_sum);
4460Sstevel@tonic-gate }
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate /* ARGSUSED */
4490Sstevel@tonic-gate static int
4500Sstevel@tonic-gate udphdr(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av)
4510Sstevel@tonic-gate {
4520Sstevel@tonic-gate 	struct udphdr	udph;
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
4550Sstevel@tonic-gate 		return (DCMD_USAGE);
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate 	if (mdb_vread(&udph, sizeof (udph), addr) == -1) {
4580Sstevel@tonic-gate 		mdb_warn("failed to read UDP header at %p", addr);
4590Sstevel@tonic-gate 		return (DCMD_ERR);
4600Sstevel@tonic-gate 	}
4610Sstevel@tonic-gate 	udphdr_print(&udph);
4620Sstevel@tonic-gate 	return (DCMD_OK);
4630Sstevel@tonic-gate }
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate static void
4660Sstevel@tonic-gate sctphdr_print(sctp_hdr_t *sctph)
4670Sstevel@tonic-gate {
4680Sstevel@tonic-gate 	in_port_t sport, dport;
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	mdb_printf("%<b>SCTP header%</b>\n");
4710Sstevel@tonic-gate 	mdb_nhconvert(&sport, &sctph->sh_sport, sizeof (sport));
4720Sstevel@tonic-gate 	mdb_nhconvert(&dport, &sctph->sh_dport, sizeof (dport));
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 	mdb_printf("%<u>%14s %14s %10s %10s%</u>\n",
4750Sstevel@tonic-gate 	    "SPORT", "DPORT", "VTAG", "CHKSUM");
4760Sstevel@tonic-gate 	mdb_printf("%5hu (0x%04x) %5hu (0x%04x) %10u 0x%08x\n\n", sport, sport,
4770Sstevel@tonic-gate 	    dport, dport, sctph->sh_verf, sctph->sh_chksum);
4780Sstevel@tonic-gate }
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate /* ARGSUSED */
4810Sstevel@tonic-gate static int
4820Sstevel@tonic-gate sctphdr(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av)
4830Sstevel@tonic-gate {
4840Sstevel@tonic-gate 	sctp_hdr_t sctph;
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
4870Sstevel@tonic-gate 		return (DCMD_USAGE);
4880Sstevel@tonic-gate 
4890Sstevel@tonic-gate 	if (mdb_vread(&sctph, sizeof (sctph), addr) == -1) {
4900Sstevel@tonic-gate 		mdb_warn("failed to read SCTP header at %p", addr);
4910Sstevel@tonic-gate 		return (DCMD_ERR);
4920Sstevel@tonic-gate 	}
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 	sctphdr_print(&sctph);
4950Sstevel@tonic-gate 	return (DCMD_OK);
4960Sstevel@tonic-gate }
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate static int
4990Sstevel@tonic-gate transport_hdr(int proto, uintptr_t addr)
5000Sstevel@tonic-gate {
5010Sstevel@tonic-gate 	mdb_printf("\n");
5020Sstevel@tonic-gate 	switch (proto) {
5030Sstevel@tonic-gate 	case IPPROTO_TCP: {
5040Sstevel@tonic-gate 		struct tcphdr tcph;
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 		if (mdb_vread(&tcph, sizeof (tcph), addr) == -1) {
5070Sstevel@tonic-gate 			mdb_warn("failed to read TCP header at %p", addr);
5080Sstevel@tonic-gate 			return (DCMD_ERR);
5090Sstevel@tonic-gate 		}
5100Sstevel@tonic-gate 		tcphdr_print(&tcph);
5110Sstevel@tonic-gate 		break;
5120Sstevel@tonic-gate 	}
5130Sstevel@tonic-gate 	case IPPROTO_UDP:  {
5140Sstevel@tonic-gate 		struct udphdr udph;
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 		if (mdb_vread(&udph, sizeof (udph), addr) == -1) {
5170Sstevel@tonic-gate 			mdb_warn("failed to read UDP header at %p", addr);
5180Sstevel@tonic-gate 			return (DCMD_ERR);
5190Sstevel@tonic-gate 		}
5200Sstevel@tonic-gate 		udphdr_print(&udph);
5210Sstevel@tonic-gate 		break;
5220Sstevel@tonic-gate 	}
5230Sstevel@tonic-gate 	case IPPROTO_SCTP: {
5240Sstevel@tonic-gate 		sctp_hdr_t sctph;
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate 		if (mdb_vread(&sctph, sizeof (sctph), addr) == -1) {
5270Sstevel@tonic-gate 			mdb_warn("failed to read SCTP header at %p", addr);
5280Sstevel@tonic-gate 			return (DCMD_ERR);
5290Sstevel@tonic-gate 		}
5300Sstevel@tonic-gate 		sctphdr_print(&sctph);
5310Sstevel@tonic-gate 		break;
5320Sstevel@tonic-gate 	}
5330Sstevel@tonic-gate 	default:
5340Sstevel@tonic-gate 		break;
5350Sstevel@tonic-gate 	}
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate 	return (DCMD_OK);
5380Sstevel@tonic-gate }
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate static const mdb_bitmask_t ip_flags[] = {
5410Sstevel@tonic-gate 	{ "DF",	IPH_DF, IPH_DF	},
5420Sstevel@tonic-gate 	{ "MF", IPH_MF,	IPH_MF	},
5430Sstevel@tonic-gate 	{ NULL, 0,	0	}
5440Sstevel@tonic-gate };
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate /* ARGSUSED */
5470Sstevel@tonic-gate static int
5480Sstevel@tonic-gate iphdr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
5490Sstevel@tonic-gate {
5500Sstevel@tonic-gate 	uint_t		verbose = FALSE, force = FALSE;
5510Sstevel@tonic-gate 	ipha_t		iph[1];
5520Sstevel@tonic-gate 	uint16_t	ver, totlen, hdrlen, ipid, off, csum;
5530Sstevel@tonic-gate 	uintptr_t	nxt_proto;
5540Sstevel@tonic-gate 	char		exp_csum[8];
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
5570Sstevel@tonic-gate 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
5580Sstevel@tonic-gate 	    'f', MDB_OPT_SETBITS, TRUE, &force, NULL) != argc)
5590Sstevel@tonic-gate 		return (DCMD_USAGE);
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate 	if (mdb_vread(iph, sizeof (*iph), addr) == -1) {
5620Sstevel@tonic-gate 		mdb_warn("failed to read IPv4 header at %p", addr);
5630Sstevel@tonic-gate 		return (DCMD_ERR);
5640Sstevel@tonic-gate 	}
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate 	ver = (iph->ipha_version_and_hdr_length & 0xf0) >> 4;
5670Sstevel@tonic-gate 	if (ver != IPV4_VERSION) {
5680Sstevel@tonic-gate 		if (ver == IPV6_VERSION) {
5690Sstevel@tonic-gate 			return (ip6hdr(addr, flags, argc, argv));
5700Sstevel@tonic-gate 		} else if (!force) {
5710Sstevel@tonic-gate 			mdb_warn("unknown IP version: %d\n", ver);
5720Sstevel@tonic-gate 			return (DCMD_ERR);
5730Sstevel@tonic-gate 		}
5740Sstevel@tonic-gate 	}
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 	mdb_printf("%<b>IPv4 header%</b>\n");
5770Sstevel@tonic-gate 	mdb_printf("%-34s %-34s\n"
5780Sstevel@tonic-gate 	    "%<u>%-4s %-4s %-5s %-5s %-6s %-5s %-5s %-6s %-8s %-6s%</u>\n",
5790Sstevel@tonic-gate 	    "SRC", "DST",
5800Sstevel@tonic-gate 	    "HLEN", "TOS", "LEN", "ID", "OFFSET", "TTL", "PROTO", "CHKSUM",
5810Sstevel@tonic-gate 	    "EXP-CSUM", "FLGS");
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 	hdrlen = (iph->ipha_version_and_hdr_length & 0x0f) << 2;
5840Sstevel@tonic-gate 	mdb_nhconvert(&totlen, &iph->ipha_length, sizeof (totlen));
5850Sstevel@tonic-gate 	mdb_nhconvert(&ipid, &iph->ipha_ident, sizeof (ipid));
5860Sstevel@tonic-gate 	mdb_nhconvert(&off, &iph->ipha_fragment_offset_and_flags, sizeof (off));
5870Sstevel@tonic-gate 	if (hdrlen == IP_SIMPLE_HDR_LENGTH) {
5880Sstevel@tonic-gate 		if ((csum = ipcksum(iph, sizeof (*iph))) != 0)
5890Sstevel@tonic-gate 			csum = ~(~csum + ~iph->ipha_hdr_checksum);
5900Sstevel@tonic-gate 		else
5910Sstevel@tonic-gate 			csum = iph->ipha_hdr_checksum;
5920Sstevel@tonic-gate 		mdb_snprintf(exp_csum, 8, "%u", csum);
5930Sstevel@tonic-gate 	} else {
5940Sstevel@tonic-gate 		mdb_snprintf(exp_csum, 8, "<n/a>");
5950Sstevel@tonic-gate 	}
5960Sstevel@tonic-gate 
5970Sstevel@tonic-gate 	mdb_printf("%-34I %-34I%\n"
5980Sstevel@tonic-gate 	    "%-4d %-4d %-5hu %-5hu %-6hu %-5hu %-5hu %-6u %-8s <%5hb>\n",
5990Sstevel@tonic-gate 	    iph->ipha_src, iph->ipha_dst,
6000Sstevel@tonic-gate 	    hdrlen, iph->ipha_type_of_service, totlen, ipid,
6010Sstevel@tonic-gate 	    (off << 3) & 0xffff, iph->ipha_ttl, iph->ipha_protocol,
6020Sstevel@tonic-gate 	    iph->ipha_hdr_checksum, exp_csum, off, ip_flags);
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 	if (verbose) {
6050Sstevel@tonic-gate 		nxt_proto = addr + hdrlen;
6060Sstevel@tonic-gate 		return (transport_hdr(iph->ipha_protocol, nxt_proto));
6070Sstevel@tonic-gate 	} else {
6080Sstevel@tonic-gate 		return (DCMD_OK);
6090Sstevel@tonic-gate 	}
6100Sstevel@tonic-gate }
6110Sstevel@tonic-gate 
6120Sstevel@tonic-gate /* ARGSUSED */
6130Sstevel@tonic-gate static int
6140Sstevel@tonic-gate ip6hdr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
6150Sstevel@tonic-gate {
6160Sstevel@tonic-gate 	uint_t		verbose = FALSE, force = FALSE;
6170Sstevel@tonic-gate 	ip6_t		iph[1];
6180Sstevel@tonic-gate 	int		ver, class, flow;
6190Sstevel@tonic-gate 	uint16_t	plen;
6200Sstevel@tonic-gate 	uintptr_t	nxt_proto;
6210Sstevel@tonic-gate 
6220Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
6230Sstevel@tonic-gate 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
6240Sstevel@tonic-gate 	    'f', MDB_OPT_SETBITS, TRUE, &force, NULL) != argc)
6250Sstevel@tonic-gate 		return (DCMD_USAGE);
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate 	if (mdb_vread(iph, sizeof (*iph), addr) == -1) {
6280Sstevel@tonic-gate 		mdb_warn("failed to read IPv6 header at %p", addr);
6290Sstevel@tonic-gate 		return (DCMD_ERR);
6300Sstevel@tonic-gate 	}
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate 	ver = (iph->ip6_vfc & 0xf0) >> 4;
6330Sstevel@tonic-gate 	if (ver != IPV6_VERSION) {
6340Sstevel@tonic-gate 		if (ver == IPV4_VERSION) {
6350Sstevel@tonic-gate 			return (iphdr(addr, flags, argc, argv));
6360Sstevel@tonic-gate 		} else if (!force) {
6370Sstevel@tonic-gate 			mdb_warn("unknown IP version: %d\n", ver);
6380Sstevel@tonic-gate 			return (DCMD_ERR);
6390Sstevel@tonic-gate 		}
6400Sstevel@tonic-gate 	}
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate 	mdb_printf("%<b>IPv6 header%</b>\n");
6430Sstevel@tonic-gate 	mdb_printf("%<u>%-26s %-26s %4s %7s %5s %3s %3s%</u>\n",
6440Sstevel@tonic-gate 	    "SRC", "DST", "TCLS", "FLOW-ID", "PLEN", "NXT", "HOP");
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate 	class = (iph->ip6_vcf & IPV6_FLOWINFO_TCLASS) >> 20;
6470Sstevel@tonic-gate 	mdb_nhconvert(&class, &class, sizeof (class));
6480Sstevel@tonic-gate 	flow = iph->ip6_vcf & IPV6_FLOWINFO_FLOWLABEL;
6490Sstevel@tonic-gate 	mdb_nhconvert(&flow, &flow, sizeof (flow));
6500Sstevel@tonic-gate 	mdb_nhconvert(&plen, &iph->ip6_plen, sizeof (plen));
6510Sstevel@tonic-gate 
6520Sstevel@tonic-gate 	mdb_printf("%-26N %-26N %4d %7d %5hu %3d %3d\n",
6530Sstevel@tonic-gate 	    &iph->ip6_src, &iph->ip6_dst,
6540Sstevel@tonic-gate 	    class, flow, plen, iph->ip6_nxt, iph->ip6_hlim);
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate 	if (verbose) {
6570Sstevel@tonic-gate 		nxt_proto = addr + sizeof (ip6_t);
6580Sstevel@tonic-gate 		return (transport_hdr(iph->ip6_nxt, nxt_proto));
6590Sstevel@tonic-gate 	} else {
6600Sstevel@tonic-gate 		return (DCMD_OK);
6610Sstevel@tonic-gate 	}
6620Sstevel@tonic-gate }
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate int
6650Sstevel@tonic-gate ire(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
6660Sstevel@tonic-gate {
6670Sstevel@tonic-gate 	uint_t verbose = FALSE;
6680Sstevel@tonic-gate 	ire_t ire;
6690Sstevel@tonic-gate 
6700Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
6710Sstevel@tonic-gate 	    'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL) != argc)
6720Sstevel@tonic-gate 		return (DCMD_USAGE);
6730Sstevel@tonic-gate 
6740Sstevel@tonic-gate 	if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) {
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate 		if (verbose) {
6770Sstevel@tonic-gate 			mdb_printf("%?s %40s %-20s%\n"
6780Sstevel@tonic-gate 			    "%?s %40s %-20s%\n"
6790Sstevel@tonic-gate 			    "%<u>%?s %40s %-20s%</u>\n",
6800Sstevel@tonic-gate 			    "ADDR", "SRC", "TYPE",
6810Sstevel@tonic-gate 			    "", "DST", "MARKS",
6820Sstevel@tonic-gate 			    "", "ZONE", "FLAGS");
6830Sstevel@tonic-gate 		} else {
6840Sstevel@tonic-gate 			mdb_printf("%<u>%?s %30s %30s %4s%</u>\n",
6850Sstevel@tonic-gate 			    "ADDR", "SRC", "DST", "ZONE");
6860Sstevel@tonic-gate 		}
6870Sstevel@tonic-gate 	}
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 	if (flags & DCMD_ADDRSPEC) {
6900Sstevel@tonic-gate 		(void) mdb_vread(&ire, sizeof (ire_t), addr);
6910Sstevel@tonic-gate 		(void) ire_format(addr, &ire, &verbose);
6920Sstevel@tonic-gate 	} else if (mdb_walk("ire", (mdb_walk_cb_t)ire_format, &verbose) == -1) {
6930Sstevel@tonic-gate 		mdb_warn("failed to walk ire table");
6940Sstevel@tonic-gate 		return (DCMD_ERR);
6950Sstevel@tonic-gate 	}
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate 	return (DCMD_OK);
6980Sstevel@tonic-gate }
6990Sstevel@tonic-gate 
7000Sstevel@tonic-gate static size_t
7010Sstevel@tonic-gate mi_osize(const queue_t *q)
7020Sstevel@tonic-gate {
7030Sstevel@tonic-gate 	/*
7040Sstevel@tonic-gate 	 * The code in common/inet/mi.c allocates an extra word to store the
7050Sstevel@tonic-gate 	 * size of the allocation.  An mi_o_s is thus a size_t plus an mi_o_s.
7060Sstevel@tonic-gate 	 */
7070Sstevel@tonic-gate 	struct mi_block {
7080Sstevel@tonic-gate 		size_t mi_nbytes;
7090Sstevel@tonic-gate 		struct mi_o_s mi_o;
7100Sstevel@tonic-gate 	} m;
7110Sstevel@tonic-gate 
7120Sstevel@tonic-gate 	if (mdb_vread(&m, sizeof (m), (uintptr_t)q->q_ptr -
7130Sstevel@tonic-gate 	    sizeof (m)) == sizeof (m))
7140Sstevel@tonic-gate 		return (m.mi_nbytes - sizeof (m));
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 	return (0);
7170Sstevel@tonic-gate }
7180Sstevel@tonic-gate 
7190Sstevel@tonic-gate static void
7200Sstevel@tonic-gate ip_ill_qinfo(const queue_t *q, char *buf, size_t nbytes)
7210Sstevel@tonic-gate {
7220Sstevel@tonic-gate 	char name[32];
7230Sstevel@tonic-gate 	ill_t ill;
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate 	if (mdb_vread(&ill, sizeof (ill),
7260Sstevel@tonic-gate 	    (uintptr_t)q->q_ptr) == sizeof (ill) &&
7270Sstevel@tonic-gate 	    mdb_readstr(name, sizeof (name), (uintptr_t)ill.ill_name) > 0)
7280Sstevel@tonic-gate 		(void) mdb_snprintf(buf, nbytes, "if: %s", name);
7290Sstevel@tonic-gate }
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate void
7320Sstevel@tonic-gate ip_qinfo(const queue_t *q, char *buf, size_t nbytes)
7330Sstevel@tonic-gate {
7340Sstevel@tonic-gate 	size_t size = mi_osize(q);
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate 	if (size == sizeof (ill_t))
7370Sstevel@tonic-gate 		ip_ill_qinfo(q, buf, nbytes);
7380Sstevel@tonic-gate }
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate uintptr_t
7410Sstevel@tonic-gate ip_rnext(const queue_t *q)
7420Sstevel@tonic-gate {
7430Sstevel@tonic-gate 	size_t size = mi_osize(q);
7440Sstevel@tonic-gate 	ill_t ill;
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate 	if (size == sizeof (ill_t) && mdb_vread(&ill, sizeof (ill),
7470Sstevel@tonic-gate 	    (uintptr_t)q->q_ptr) == sizeof (ill))
7480Sstevel@tonic-gate 		return ((uintptr_t)ill.ill_rq);
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 	return (NULL);
7510Sstevel@tonic-gate }
7520Sstevel@tonic-gate 
7530Sstevel@tonic-gate uintptr_t
7540Sstevel@tonic-gate ip_wnext(const queue_t *q)
7550Sstevel@tonic-gate {
7560Sstevel@tonic-gate 	size_t size = mi_osize(q);
7570Sstevel@tonic-gate 	ill_t ill;
7580Sstevel@tonic-gate 
7590Sstevel@tonic-gate 	if (size == sizeof (ill_t) && mdb_vread(&ill, sizeof (ill),
7600Sstevel@tonic-gate 	    (uintptr_t)q->q_ptr) == sizeof (ill))
7610Sstevel@tonic-gate 		return ((uintptr_t)ill.ill_wq);
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate 	return (NULL);
7640Sstevel@tonic-gate }
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate /*
7670Sstevel@tonic-gate  * Print the core fields in an squeue_t.  With the "-v" argument,
7680Sstevel@tonic-gate  * provide more verbose output.
7690Sstevel@tonic-gate  */
7700Sstevel@tonic-gate static int
7710Sstevel@tonic-gate squeue(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
7720Sstevel@tonic-gate {
7730Sstevel@tonic-gate 	unsigned int	i;
7740Sstevel@tonic-gate 	unsigned int	verbose = FALSE;
7750Sstevel@tonic-gate 	const int	SQUEUE_STATEDELT = (int)(sizeof (uintptr_t) + 9);
7760Sstevel@tonic-gate 	boolean_t	arm;
7770Sstevel@tonic-gate 	squeue_t	squeue;
7780Sstevel@tonic-gate 
7790Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
7800Sstevel@tonic-gate 		if (mdb_walk_dcmd("genunix`squeue_cache", "ip`squeue",
7810Sstevel@tonic-gate 		    argc, argv) == -1) {
7820Sstevel@tonic-gate 			mdb_warn("failed to walk squeue cache");
7830Sstevel@tonic-gate 			return (DCMD_ERR);
7840Sstevel@tonic-gate 		}
7850Sstevel@tonic-gate 		return (DCMD_OK);
7860Sstevel@tonic-gate 	}
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate 	if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL)
7890Sstevel@tonic-gate 	    != argc)
7900Sstevel@tonic-gate 		return (DCMD_USAGE);
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate 	if (!DCMD_HDRSPEC(flags) && verbose)
7930Sstevel@tonic-gate 		mdb_printf("\n\n");
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags) || verbose) {
7960Sstevel@tonic-gate 		mdb_printf("%?s %-5s %-3s %?s %?s %?s\n",
7970Sstevel@tonic-gate 		    "ADDR", "STATE", "CPU",
7980Sstevel@tonic-gate 		    "FIRST", "LAST", "WORKER");
7990Sstevel@tonic-gate 	}
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 	if (mdb_vread(&squeue, sizeof (squeue_t), addr) == -1) {
8020Sstevel@tonic-gate 		mdb_warn("cannot read squeue_t at %p", addr);
8030Sstevel@tonic-gate 		return (DCMD_ERR);
8040Sstevel@tonic-gate 	}
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate 	mdb_printf("%0?p %05x %3d %0?p %0?p %0?p\n",
8070Sstevel@tonic-gate 	    addr, squeue.sq_state, squeue.sq_bind,
8080Sstevel@tonic-gate 	    squeue.sq_first, squeue.sq_last, squeue.sq_worker);
8090Sstevel@tonic-gate 
8100Sstevel@tonic-gate 	if (!verbose)
8110Sstevel@tonic-gate 		return (DCMD_OK);
8120Sstevel@tonic-gate 
8130Sstevel@tonic-gate 	arm = B_TRUE;
8140Sstevel@tonic-gate 	for (i = 0; squeue_states[i].bit_name != NULL; i++) {
8150Sstevel@tonic-gate 		if (((squeue.sq_state) & (1 << i)) == 0)
8160Sstevel@tonic-gate 			continue;
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 		if (arm) {
8190Sstevel@tonic-gate 			mdb_printf("%*s|\n", SQUEUE_STATEDELT, "");
8200Sstevel@tonic-gate 			mdb_printf("%*s+-->  ", SQUEUE_STATEDELT, "");
8210Sstevel@tonic-gate 			arm = B_FALSE;
8220Sstevel@tonic-gate 		} else
8230Sstevel@tonic-gate 			mdb_printf("%*s      ", SQUEUE_STATEDELT, "");
8240Sstevel@tonic-gate 
8250Sstevel@tonic-gate 		mdb_printf("%-12s %s\n", squeue_states[i].bit_name,
8260Sstevel@tonic-gate 		    squeue_states[i].bit_descr);
8270Sstevel@tonic-gate 	}
8280Sstevel@tonic-gate 
8290Sstevel@tonic-gate 	return (DCMD_OK);
8300Sstevel@tonic-gate }
8310Sstevel@tonic-gate 
8320Sstevel@tonic-gate static void
8330Sstevel@tonic-gate ip_squeue_help(void)
8340Sstevel@tonic-gate {
8350Sstevel@tonic-gate 	mdb_printf("Print the core information for a given NCA squeue_t.\n\n");
8360Sstevel@tonic-gate 	mdb_printf("Options:\n");
8370Sstevel@tonic-gate 	mdb_printf("\t-v\tbe verbose (more descriptive)\n");
8380Sstevel@tonic-gate }
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate static const mdb_dcmd_t dcmds[] = {
8410Sstevel@tonic-gate 	{ "illif", "?[-P v4 | v6]",
8420Sstevel@tonic-gate 	    "display or filter IP Lower Level InterFace structures", illif,
8430Sstevel@tonic-gate 	    illif_help },
8440Sstevel@tonic-gate 	{ "iphdr", ":[-vf]", "display an IPv4 header", iphdr },
8450Sstevel@tonic-gate 	{ "ip6hdr", ":[-vf]", "display an IPv6 header", ip6hdr },
8460Sstevel@tonic-gate 	{ "ire", "?[-v]", "display Internet Route Entry structures", ire },
8470Sstevel@tonic-gate 	{ "squeue", ":[-v]", "print core squeue_t info", squeue,
8480Sstevel@tonic-gate 	    ip_squeue_help },
8490Sstevel@tonic-gate 	{ "tcphdr", ":", "display a TCP header", tcphdr },
8500Sstevel@tonic-gate 	{ "udphdr", ":", "display an UDP header", udphdr },
8510Sstevel@tonic-gate 	{ "sctphdr", ":", "display an SCTP header", sctphdr },
8520Sstevel@tonic-gate 	{ NULL }
8530Sstevel@tonic-gate };
8540Sstevel@tonic-gate 
8550Sstevel@tonic-gate static const mdb_walker_t walkers[] = {
8560Sstevel@tonic-gate 	{ "illif", "walk list of ill interface types",
8570Sstevel@tonic-gate 		illif_walk_init, illif_walk_step, illif_walk_fini },
8580Sstevel@tonic-gate 	{ "ire", "walk active ire_t structures",
8590Sstevel@tonic-gate 		ire_walk_init, ire_walk_step, NULL },
8600Sstevel@tonic-gate 	{ NULL }
8610Sstevel@tonic-gate };
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate static const mdb_qops_t ip_qops = { ip_qinfo, ip_rnext, ip_wnext };
8640Sstevel@tonic-gate static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate const mdb_modinfo_t *
8670Sstevel@tonic-gate _mdb_init(void)
8680Sstevel@tonic-gate {
8690Sstevel@tonic-gate 	GElf_Sym sym;
8700Sstevel@tonic-gate 
871*2546Scarlsonj 	if (mdb_lookup_by_obj("ip", "ipwinit", &sym) == 0)
8720Sstevel@tonic-gate 		mdb_qops_install(&ip_qops, (uintptr_t)sym.st_value);
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 	return (&modinfo);
8750Sstevel@tonic-gate }
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate void
8780Sstevel@tonic-gate _mdb_fini(void)
8790Sstevel@tonic-gate {
8800Sstevel@tonic-gate 	GElf_Sym sym;
8810Sstevel@tonic-gate 
882*2546Scarlsonj 	if (mdb_lookup_by_obj("ip", "ipwinit", &sym) == 0)
8830Sstevel@tonic-gate 		mdb_qops_remove(&ip_qops, (uintptr_t)sym.st_value);
8840Sstevel@tonic-gate }
885