Home | History | Annotate | Download | only in genunix
      1      0     stevel /*
      2      0     stevel  * CDDL HEADER START
      3      0     stevel  *
      4      0     stevel  * The contents of this file are subject to the terms of the
      5   1676        jpk  * Common Development and Distribution License (the "License").
      6   1676        jpk  * You may not use this file except in compliance with the License.
      7      0     stevel  *
      8      0     stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9      0     stevel  * or http://www.opensolaris.org/os/licensing.
     10      0     stevel  * See the License for the specific language governing permissions
     11      0     stevel  * and limitations under the License.
     12      0     stevel  *
     13      0     stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14      0     stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15      0     stevel  * If applicable, add the following below this CDDL HEADER, with the
     16      0     stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17      0     stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18      0     stevel  *
     19      0     stevel  * CDDL HEADER END
     20      0     stevel  */
     21      0     stevel /*
     22   9089  Vasumathi  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23      0     stevel  * Use is subject to license terms.
     24      0     stevel  */
     25      0     stevel 
     26      0     stevel #include <mdb/mdb_modapi.h>
     27      0     stevel #include <mdb/mdb_ks.h>
     28      0     stevel #include <mdb/mdb_ctf.h>
     29      0     stevel #include <sys/types.h>
     30      0     stevel #include <sys/tihdr.h>
     31      0     stevel #include <inet/led.h>
     32      0     stevel #include <inet/common.h>
     33      0     stevel #include <netinet/in.h>
     34      0     stevel #include <netinet/ip6.h>
     35      0     stevel #include <netinet/icmp6.h>
     36      0     stevel #include <inet/ip.h>
     37      0     stevel #include <inet/ip6.h>
     38      0     stevel #include <inet/ipclassifier.h>
     39      0     stevel #include <inet/tcp.h>
     40      0     stevel #include <sys/stream.h>
     41      0     stevel #include <sys/vfs.h>
     42      0     stevel #include <sys/stropts.h>
     43      0     stevel #include <sys/tpicommon.h>
     44      0     stevel #include <sys/socket.h>
     45      0     stevel #include <sys/socketvar.h>
     46      0     stevel #include <sys/cred_impl.h>
     47      0     stevel #include <inet/udp_impl.h>
     48      0     stevel #include <inet/rawip_impl.h>
     49      0     stevel #include <inet/mi.h>
     50   8348       Eric #include <fs/sockfs/socktpi_impl.h>
     51  10491      Rishi #include <net/bridge_impl.h>
     52  10491      Rishi #include <io/trill_impl.h>
     53  10491      Rishi #include <sys/mac_impl.h>
     54      0     stevel 
     55      0     stevel #define	ADDR_V6_WIDTH	23
     56      0     stevel #define	ADDR_V4_WIDTH	15
     57      0     stevel 
     58   1676        jpk #define	NETSTAT_ALL	0x01
     59   1676        jpk #define	NETSTAT_VERBOSE	0x02
     60   1676        jpk #define	NETSTAT_ROUTE	0x04
     61   1676        jpk #define	NETSTAT_V4	0x08
     62   1676        jpk #define	NETSTAT_V6	0x10
     63   1676        jpk #define	NETSTAT_UNIX	0x20
     64   1676        jpk 
     65   1676        jpk #define	NETSTAT_FIRST	0x80000000u
     66   3448   dh155122 
     67   9089  Vasumathi typedef struct netstat_cb_data_s {
     68   9089  Vasumathi 	uint_t	opts;
     69   9089  Vasumathi 	conn_t	conn;
     70   9089  Vasumathi 	int	af;
     71   9089  Vasumathi } netstat_cb_data_t;
     72   3448   dh155122 
     73   3448   dh155122 int
     74   3448   dh155122 icmp_stacks_walk_init(mdb_walk_state_t *wsp)
     75   3448   dh155122 {
     76   3448   dh155122 	if (mdb_layered_walk("netstack", wsp) == -1) {
     77   3448   dh155122 		mdb_warn("can't walk 'netstack'");
     78   3448   dh155122 		return (WALK_ERR);
     79   3448   dh155122 	}
     80   3448   dh155122 	return (WALK_NEXT);
     81   3448   dh155122 }
     82   3448   dh155122 
     83   3448   dh155122 int
     84   3448   dh155122 icmp_stacks_walk_step(mdb_walk_state_t *wsp)
     85   3448   dh155122 {
     86   3448   dh155122 	uintptr_t kaddr;
     87   3448   dh155122 	netstack_t nss;
     88   3448   dh155122 
     89   3448   dh155122 	if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
     90   3448   dh155122 		mdb_warn("can't read netstack at %p", wsp->walk_addr);
     91   3448   dh155122 		return (WALK_ERR);
     92   3448   dh155122 	}
     93   3448   dh155122 	kaddr = (uintptr_t)nss.netstack_modules[NS_ICMP];
     94   3448   dh155122 	return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
     95   3448   dh155122 }
     96   3448   dh155122 
     97   3448   dh155122 int
     98   3448   dh155122 tcp_stacks_walk_init(mdb_walk_state_t *wsp)
     99   3448   dh155122 {
    100   3448   dh155122 	if (mdb_layered_walk("netstack", wsp) == -1) {
    101   3448   dh155122 		mdb_warn("can't walk 'netstack'");
    102   3448   dh155122 		return (WALK_ERR);
    103   3448   dh155122 	}
    104   3448   dh155122 	return (WALK_NEXT);
    105   3448   dh155122 }
    106   3448   dh155122 
    107   3448   dh155122 int
    108   3448   dh155122 tcp_stacks_walk_step(mdb_walk_state_t *wsp)
    109   3448   dh155122 {
    110   3448   dh155122 	uintptr_t kaddr;
    111   3448   dh155122 	netstack_t nss;
    112   3448   dh155122 
    113   3448   dh155122 	if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
    114   3448   dh155122 		mdb_warn("can't read netstack at %p", wsp->walk_addr);
    115   3448   dh155122 		return (WALK_ERR);
    116   3448   dh155122 	}
    117   3448   dh155122 	kaddr = (uintptr_t)nss.netstack_modules[NS_TCP];
    118   3448   dh155122 	return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
    119   3448   dh155122 }
    120   3448   dh155122 
    121   3448   dh155122 int
    122   3448   dh155122 udp_stacks_walk_init(mdb_walk_state_t *wsp)
    123   3448   dh155122 {
    124   3448   dh155122 	if (mdb_layered_walk("netstack", wsp) == -1) {
    125   3448   dh155122 		mdb_warn("can't walk 'netstack'");
    126   3448   dh155122 		return (WALK_ERR);
    127   3448   dh155122 	}
    128   3448   dh155122 	return (WALK_NEXT);
    129   3448   dh155122 }
    130   3448   dh155122 
    131   3448   dh155122 int
    132   3448   dh155122 udp_stacks_walk_step(mdb_walk_state_t *wsp)
    133   3448   dh155122 {
    134   3448   dh155122 	uintptr_t kaddr;
    135   3448   dh155122 	netstack_t nss;
    136   3448   dh155122 
    137   3448   dh155122 	if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
    138   3448   dh155122 		mdb_warn("can't read netstack at %p", wsp->walk_addr);
    139   3448   dh155122 		return (WALK_ERR);
    140   3448   dh155122 	}
    141   3448   dh155122 	kaddr = (uintptr_t)nss.netstack_modules[NS_UDP];
    142   3448   dh155122 	return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
    143   3448   dh155122 }
    144      0     stevel 
    145      0     stevel /*
    146      0     stevel  * Print an IPv4 address and port number in a compact and easy to read format
    147      0     stevel  * The arguments are in network byte order
    148      0     stevel  */
    149      0     stevel static void
    150      0     stevel net_ipv4addrport_pr(const in6_addr_t *nipv6addr, in_port_t nport)
    151      0     stevel {
    152      0     stevel 	uint32_t naddr = V4_PART_OF_V6((*nipv6addr));
    153      0     stevel 
    154      0     stevel 	mdb_nhconvert(&nport, &nport, sizeof (nport));
    155      0     stevel 	mdb_printf("%*I.%-5hu", ADDR_V4_WIDTH, naddr, nport);
    156      0     stevel }
    157      0     stevel 
    158      0     stevel /*
    159      0     stevel  * Print an IPv6 address and port number in a compact and easy to read format
    160      0     stevel  * The arguments are in network byte order
    161      0     stevel  */
    162      0     stevel static void
    163      0     stevel net_ipv6addrport_pr(const in6_addr_t *naddr, in_port_t nport)
    164      0     stevel {
    165      0     stevel 	mdb_nhconvert(&nport, &nport, sizeof (nport));
    166      0     stevel 	mdb_printf("%*N.%-5hu", ADDR_V6_WIDTH, naddr, nport);
    167      0     stevel }
    168      0     stevel 
    169      0     stevel static int
    170      0     stevel net_tcp_active(const tcp_t *tcp)
    171      0     stevel {
    172      0     stevel 	return (tcp->tcp_state >= TCPS_ESTABLISHED);
    173      0     stevel }
    174      0     stevel 
    175      0     stevel static int
    176      0     stevel net_tcp_ipv4(const tcp_t *tcp)
    177      0     stevel {
    178  11042       Erik 	return ((tcp->tcp_connp->conn_ipversion == IPV4_VERSION) ||
    179  11042       Erik 	    (IN6_IS_ADDR_UNSPECIFIED(&tcp->tcp_connp->conn_laddr_v6) &&
    180      0     stevel 	    (tcp->tcp_state <= TCPS_LISTEN)));
    181      0     stevel }
    182      0     stevel 
    183      0     stevel static int
    184      0     stevel net_tcp_ipv6(const tcp_t *tcp)
    185      0     stevel {
    186  11042       Erik 	return (tcp->tcp_connp->conn_ipversion == IPV6_VERSION);
    187      0     stevel }
    188      0     stevel 
    189      0     stevel static int
    190      0     stevel net_udp_active(const udp_t *udp)
    191      0     stevel {
    192    741   masputra 	return ((udp->udp_state == TS_IDLE) ||
    193    741   masputra 	    (udp->udp_state == TS_DATA_XFER));
    194      0     stevel }
    195      0     stevel 
    196      0     stevel static int
    197      0     stevel net_udp_ipv4(const udp_t *udp)
    198      0     stevel {
    199  11042       Erik 	return ((udp->udp_connp->conn_ipversion == IPV4_VERSION) ||
    200  11042       Erik 	    (IN6_IS_ADDR_UNSPECIFIED(&udp->udp_connp->conn_laddr_v6) &&
    201      0     stevel 	    (udp->udp_state <= TS_IDLE)));
    202      0     stevel }
    203      0     stevel 
    204      0     stevel static int
    205      0     stevel net_udp_ipv6(const udp_t *udp)
    206      0     stevel {
    207  11042       Erik 	return (udp->udp_connp->conn_ipversion == IPV6_VERSION);
    208      0     stevel }
    209      0     stevel 
    210      0     stevel int
    211      0     stevel sonode_walk_init(mdb_walk_state_t *wsp)
    212      0     stevel {
    213      0     stevel 	if (wsp->walk_addr == NULL) {
    214      0     stevel 		GElf_Sym sym;
    215      0     stevel 		struct socklist *slp;
    216      0     stevel 
    217      0     stevel 		if (mdb_lookup_by_obj("sockfs", "socklist", &sym) == -1) {
    218      0     stevel 			mdb_warn("failed to lookup sockfs`socklist");
    219      0     stevel 			return (WALK_ERR);
    220      0     stevel 		}
    221      0     stevel 
    222      0     stevel 		slp = (struct socklist *)(uintptr_t)sym.st_value;
    223      0     stevel 
    224      0     stevel 		if (mdb_vread(&wsp->walk_addr, sizeof (wsp->walk_addr),
    225      0     stevel 		    (uintptr_t)&slp->sl_list) == -1) {
    226      0     stevel 			mdb_warn("failed to read address of initial sonode "
    227      0     stevel 			    "at %p", &slp->sl_list);
    228      0     stevel 			return (WALK_ERR);
    229      0     stevel 		}
    230      0     stevel 	}
    231      0     stevel 
    232   8348       Eric 	wsp->walk_data = mdb_alloc(sizeof (struct sotpi_sonode), UM_SLEEP);
    233      0     stevel 	return (WALK_NEXT);
    234      0     stevel }
    235      0     stevel 
    236      0     stevel int
    237      0     stevel sonode_walk_step(mdb_walk_state_t *wsp)
    238      0     stevel {
    239      0     stevel 	int status;
    240   8348       Eric 	struct sotpi_sonode *stp;
    241      0     stevel 
    242      0     stevel 	if (wsp->walk_addr == NULL)
    243      0     stevel 		return (WALK_DONE);
    244      0     stevel 
    245   8348       Eric 	if (mdb_vread(wsp->walk_data, sizeof (struct sotpi_sonode),
    246      0     stevel 	    wsp->walk_addr) == -1) {
    247      0     stevel 		mdb_warn("failed to read sonode at %p", wsp->walk_addr);
    248      0     stevel 		return (WALK_ERR);
    249      0     stevel 	}
    250      0     stevel 
    251      0     stevel 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
    252      0     stevel 	    wsp->walk_cbdata);
    253      0     stevel 
    254   8348       Eric 	stp = wsp->walk_data;
    255      0     stevel 
    256   8348       Eric 	wsp->walk_addr = (uintptr_t)stp->st_info.sti_next_so;
    257      0     stevel 	return (status);
    258      0     stevel }
    259      0     stevel 
    260      0     stevel void
    261      0     stevel sonode_walk_fini(mdb_walk_state_t *wsp)
    262      0     stevel {
    263   8348       Eric 	mdb_free(wsp->walk_data, sizeof (struct sotpi_sonode));
    264      0     stevel }
    265      0     stevel 
    266      0     stevel struct mi_walk_data {
    267      0     stevel 	uintptr_t mi_wd_miofirst;
    268      0     stevel 	MI_O mi_wd_miodata;
    269      0     stevel };
    270      0     stevel 
    271      0     stevel int
    272      0     stevel mi_walk_init(mdb_walk_state_t *wsp)
    273      0     stevel {
    274      0     stevel 	struct mi_walk_data *wdp;
    275      0     stevel 
    276      0     stevel 	if (wsp->walk_addr == NULL) {
    277      0     stevel 		mdb_warn("mi doesn't support global walks\n");
    278      0     stevel 		return (WALK_ERR);
    279      0     stevel 	}
    280      0     stevel 
    281      0     stevel 	wdp = mdb_alloc(sizeof (struct mi_walk_data), UM_SLEEP);
    282      0     stevel 
    283      0     stevel 	/* So that we do not immediately return WALK_DONE below */
    284      0     stevel 	wdp->mi_wd_miofirst = NULL;
    285      0     stevel 
    286      0     stevel 	wsp->walk_data = wdp;
    287      0     stevel 	return (WALK_NEXT);
    288      0     stevel }
    289      0     stevel 
    290      0     stevel int
    291      0     stevel mi_walk_step(mdb_walk_state_t *wsp)
    292      0     stevel {
    293      0     stevel 	struct mi_walk_data *wdp = wsp->walk_data;
    294      0     stevel 	MI_OP miop = &wdp->mi_wd_miodata;
    295      0     stevel 	int status;
    296      0     stevel 
    297      0     stevel 	/* Always false in the first iteration */
    298      0     stevel 	if ((wsp->walk_addr == (uintptr_t)NULL) ||
    299      0     stevel 	    (wsp->walk_addr == wdp->mi_wd_miofirst)) {
    300      0     stevel 		return (WALK_DONE);
    301      0     stevel 	}
    302      0     stevel 
    303      0     stevel 	if (mdb_vread(miop, sizeof (MI_O), wsp->walk_addr) == -1) {
    304      0     stevel 		mdb_warn("failed to read MI object at %p", wsp->walk_addr);
    305      0     stevel 		return (WALK_ERR);
    306      0     stevel 	}
    307      0     stevel 
    308      0     stevel 	/* Only true in the first iteration */
    309   3448   dh155122 	if (wdp->mi_wd_miofirst == NULL) {
    310      0     stevel 		wdp->mi_wd_miofirst = wsp->walk_addr;
    311   3448   dh155122 		status = WALK_NEXT;
    312   3448   dh155122 	} else {
    313   3448   dh155122 		status = wsp->walk_callback(wsp->walk_addr + sizeof (MI_O),
    314   3448   dh155122 		    &miop[1], wsp->walk_cbdata);
    315   3448   dh155122 	}
    316      0     stevel 
    317      0     stevel 	wsp->walk_addr = (uintptr_t)miop->mi_o_next;
    318      0     stevel 	return (status);
    319      0     stevel }
    320      0     stevel 
    321      0     stevel void
    322      0     stevel mi_walk_fini(mdb_walk_state_t *wsp)
    323      0     stevel {
    324      0     stevel 	mdb_free(wsp->walk_data, sizeof (struct mi_walk_data));
    325      0     stevel }
    326      0     stevel 
    327      0     stevel typedef struct mi_payload_walk_arg_s {
    328   3448   dh155122 	const char *mi_pwa_walker;	/* Underlying walker */
    329   3448   dh155122 	const off_t mi_pwa_head_off;	/* Offset for mi_o_head_t * in stack */
    330      0     stevel 	const size_t mi_pwa_size;	/* size of mi payload */
    331      0     stevel 	const uint_t mi_pwa_flags;	/* device and/or module */
    332      0     stevel } mi_payload_walk_arg_t;
    333      0     stevel 
    334      0     stevel #define	MI_PAYLOAD_DEVICE	0x1
    335      0     stevel #define	MI_PAYLOAD_MODULE	0x2
    336      0     stevel 
    337      0     stevel int
    338      0     stevel mi_payload_walk_init(mdb_walk_state_t *wsp)
    339      0     stevel {
    340      0     stevel 	const mi_payload_walk_arg_t *arg = wsp->walk_arg;
    341      0     stevel 
    342   3448   dh155122 	if (mdb_layered_walk(arg->mi_pwa_walker, wsp) == -1) {
    343   3448   dh155122 		mdb_warn("can't walk '%s'", arg->mi_pwa_walker);
    344      0     stevel 		return (WALK_ERR);
    345      0     stevel 	}
    346      0     stevel 	return (WALK_NEXT);
    347      0     stevel }
    348      0     stevel 
    349      0     stevel int
    350      0     stevel mi_payload_walk_step(mdb_walk_state_t *wsp)
    351      0     stevel {
    352      0     stevel 	const mi_payload_walk_arg_t *arg = wsp->walk_arg;
    353   3448   dh155122 	uintptr_t kaddr;
    354      0     stevel 
    355   3448   dh155122 	kaddr = wsp->walk_addr + arg->mi_pwa_head_off;
    356      0     stevel 
    357   3448   dh155122 	if (mdb_vread(&kaddr, sizeof (kaddr), kaddr) == -1) {
    358   3448   dh155122 		mdb_warn("can't read address of mi head at %p for %s",
    359   3448   dh155122 		    kaddr, arg->mi_pwa_walker);
    360      0     stevel 		return (WALK_ERR);
    361      0     stevel 	}
    362      0     stevel 
    363   3448   dh155122 	if (kaddr == 0) {
    364   3448   dh155122 		/* Empty list */
    365   3448   dh155122 		return (WALK_DONE);
    366   3448   dh155122 	}
    367      0     stevel 
    368   3448   dh155122 	if (mdb_pwalk("genunix`mi", wsp->walk_callback,
    369   3448   dh155122 	    wsp->walk_cbdata, kaddr) == -1) {
    370   3448   dh155122 		mdb_warn("failed to walk genunix`mi");
    371   3448   dh155122 		return (WALK_ERR);
    372   3448   dh155122 	}
    373   3448   dh155122 	return (WALK_NEXT);
    374      0     stevel }
    375      0     stevel 
    376      0     stevel const mi_payload_walk_arg_t mi_icmp_arg = {
    377   3448   dh155122 	"icmp_stacks", OFFSETOF(icmp_stack_t, is_head), sizeof (icmp_t),
    378      0     stevel 	MI_PAYLOAD_DEVICE | MI_PAYLOAD_MODULE
    379      0     stevel };
    380      0     stevel 
    381      0     stevel int
    382      0     stevel sonode(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
    383      0     stevel {
    384      0     stevel 	const char *optf = NULL;
    385      0     stevel 	const char *optt = NULL;
    386      0     stevel 	const char *optp = NULL;
    387      0     stevel 	int family, type, proto;
    388      0     stevel 	int filter = 0;
    389      0     stevel 	struct sonode so;
    390      0     stevel 
    391      0     stevel 	if (!(flags & DCMD_ADDRSPEC)) {
    392      0     stevel 		if (mdb_walk_dcmd("genunix`sonode", "genunix`sonode", argc,
    393      0     stevel 		    argv) == -1) {
    394      0     stevel 			mdb_warn("failed to walk sonode");
    395      0     stevel 			return (DCMD_ERR);
    396      0     stevel 		}
    397      0     stevel 
    398      0     stevel 		return (DCMD_OK);
    399      0     stevel 	}
    400      0     stevel 
    401      0     stevel 	if (mdb_getopts(argc, argv,
    402      0     stevel 	    'f', MDB_OPT_STR, &optf,
    403      0     stevel 	    't', MDB_OPT_STR, &optt,
    404      0     stevel 	    'p', MDB_OPT_STR, &optp,
    405      0     stevel 	    NULL) != argc)
    406      0     stevel 		return (DCMD_USAGE);
    407      0     stevel 
    408      0     stevel 	if (optf != NULL) {
    409      0     stevel 		if (strcmp("inet", optf) == 0)
    410      0     stevel 			family = AF_INET;
    411      0     stevel 		else if (strcmp("inet6", optf) == 0)
    412      0     stevel 			family = AF_INET6;
    413      0     stevel 		else if (strcmp("unix", optf) == 0)
    414      0     stevel 			family = AF_UNIX;
    415      0     stevel 		else
    416      0     stevel 			family = mdb_strtoull(optf);
    417      0     stevel 		filter = 1;
    418      0     stevel 	}
    419      0     stevel 
    420      0     stevel 	if (optt != NULL) {
    421      0     stevel 		if (strcmp("stream", optt) == 0)
    422      0     stevel 			type = SOCK_STREAM;
    423      0     stevel 		else if (strcmp("dgram", optt) == 0)
    424      0     stevel 			type = SOCK_DGRAM;
    425      0     stevel 		else if (strcmp("raw", optt) == 0)
    426      0     stevel 			type = SOCK_RAW;
    427      0     stevel 		else
    428      0     stevel 			type = mdb_strtoull(optt);
    429      0     stevel 		filter = 1;
    430      0     stevel 	}
    431      0     stevel 
    432      0     stevel 	if (optp != NULL) {
    433      0     stevel 		proto = mdb_strtoull(optp);
    434      0     stevel 		filter = 1;
    435      0     stevel 	}
    436      0     stevel 
    437      0     stevel 	if (DCMD_HDRSPEC(flags) && !filter) {
    438      0     stevel 		mdb_printf("%<u>%-?s Family Type Proto State Mode Flag "
    439      0     stevel 		    "AccessVP%</u>\n", "Sonode:");
    440      0     stevel 	}
    441      0     stevel 
    442      0     stevel 	if (mdb_vread(&so, sizeof (so), addr) == -1) {
    443      0     stevel 		mdb_warn("failed to read sonode at %p", addr);
    444      0     stevel 		return (DCMD_ERR);
    445      0     stevel 	}
    446      0     stevel 
    447      0     stevel 	if ((optf != NULL) && (so.so_family != family))
    448      0     stevel 		return (DCMD_OK);
    449      0     stevel 
    450      0     stevel 	if ((optt != NULL) && (so.so_type != type))
    451      0     stevel 		return (DCMD_OK);
    452      0     stevel 
    453      0     stevel 	if ((optp != NULL) && (so.so_protocol != proto))
    454      0     stevel 		return (DCMD_OK);
    455      0     stevel 
    456      0     stevel 	if (filter) {
    457      0     stevel 		mdb_printf("%0?p\n", addr);
    458      0     stevel 		return (DCMD_OK);
    459      0     stevel 	}
    460      0     stevel 
    461      0     stevel 	mdb_printf("%0?p ", addr);
    462      0     stevel 
    463      0     stevel 	switch (so.so_family) {
    464   5563   nordmark 	case AF_UNIX:
    465      0     stevel 		mdb_printf("unix  ");
    466      0     stevel 		break;
    467   5563   nordmark 	case AF_INET:
    468      0     stevel 		mdb_printf("inet  ");
    469      0     stevel 		break;
    470   5563   nordmark 	case AF_INET6:
    471      0     stevel 		mdb_printf("inet6 ");
    472      0     stevel 		break;
    473   5563   nordmark 	default:
    474      0     stevel 		mdb_printf("%6hi", so.so_family);
    475      0     stevel 	}
    476      0     stevel 
    477      0     stevel 	switch (so.so_type) {
    478   5563   nordmark 	case SOCK_STREAM:
    479      0     stevel 		mdb_printf(" strm");
    480      0     stevel 		break;
    481   5563   nordmark 	case SOCK_DGRAM:
    482      0     stevel 		mdb_printf(" dgrm");
    483      0     stevel 		break;
    484   5563   nordmark 	case SOCK_RAW:
    485      0     stevel 		mdb_printf(" raw ");
    486      0     stevel 		break;
    487   5563   nordmark 	default:
    488      0     stevel 		mdb_printf(" %4hi", so.so_type);
    489      0     stevel 	}
    490      0     stevel 
    491   8348       Eric 	mdb_printf(" %5hi %05x %04x %04hx\n",
    492      0     stevel 	    so.so_protocol, so.so_state, so.so_mode,
    493   8348       Eric 	    so.so_flag);
    494      0     stevel 
    495      0     stevel 	return (DCMD_OK);
    496      0     stevel }
    497      0     stevel 
    498      0     stevel #define	MI_PAYLOAD	0x1
    499      0     stevel #define	MI_DEVICE	0x2
    500      0     stevel #define	MI_MODULE	0x4
    501      0     stevel 
    502      0     stevel int
    503      0     stevel mi(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
    504      0     stevel {
    505      0     stevel 	uint_t opts = 0;
    506      0     stevel 	MI_O	mio;
    507      0     stevel 
    508      0     stevel 	if (!(flags & DCMD_ADDRSPEC))
    509      0     stevel 		return (DCMD_USAGE);
    510      0     stevel 
    511      0     stevel 	if (mdb_getopts(argc, argv,
    512      0     stevel 	    'p', MDB_OPT_SETBITS, MI_PAYLOAD, &opts,
    513      0     stevel 	    'd', MDB_OPT_SETBITS, MI_DEVICE, &opts,
    514      0     stevel 	    'm', MDB_OPT_SETBITS, MI_MODULE, &opts,
    515      0     stevel 	    NULL) != argc)
    516      0     stevel 		return (DCMD_USAGE);
    517      0     stevel 
    518      0     stevel 	if ((opts & (MI_DEVICE | MI_MODULE)) == (MI_DEVICE | MI_MODULE)) {
    519      0     stevel 		mdb_warn("at most one filter, d for devices or m "
    520      0     stevel 		    "for modules, may be specified\n");
    521      0     stevel 		return (DCMD_USAGE);
    522      0     stevel 	}
    523      0     stevel 
    524      0     stevel 	if ((opts == 0) && (DCMD_HDRSPEC(flags))) {
    525      0     stevel 		mdb_printf("%<u>%-?s %-?s %-?s IsDev Dev%</u>\n",
    526      0     stevel 		    "MI_O", "Next", "Prev");
    527      0     stevel 	}
    528      0     stevel 
    529      0     stevel 	if (mdb_vread(&mio, sizeof (mio), addr) == -1) {
    530      0     stevel 		mdb_warn("failed to read mi object MI_O at %p", addr);
    531      0     stevel 		return (DCMD_ERR);
    532      0     stevel 	}
    533      0     stevel 
    534      0     stevel 	if (opts != 0) {
    535      0     stevel 		if (mio.mi_o_isdev == B_FALSE) {
    536      0     stevel 			/* mio is a module */
    537      0     stevel 			if (!(opts & MI_MODULE) && (opts & MI_DEVICE))
    538      0     stevel 				return (DCMD_OK);
    539      0     stevel 		} else {
    540      0     stevel 			/* mio is a device */
    541      0     stevel 			if (!(opts & MI_DEVICE) && (opts & MI_MODULE))
    542      0     stevel 				return (DCMD_OK);
    543      0     stevel 		}
    544      0     stevel 
    545      0     stevel 		if (opts & MI_PAYLOAD)
    546      0     stevel 			mdb_printf("%p\n", addr + sizeof (MI_O));
    547      0     stevel 		else
    548      0     stevel 			mdb_printf("%p\n", addr);
    549      0     stevel 		return (DCMD_OK);
    550      0     stevel 	}
    551      0     stevel 
    552      0     stevel 	mdb_printf("%0?p %0?p %0?p ", addr, mio.mi_o_next, mio.mi_o_prev);
    553      0     stevel 
    554      0     stevel 	if (mio.mi_o_isdev == B_FALSE)
    555      0     stevel 		mdb_printf("FALSE");
    556      0     stevel 	else
    557      0     stevel 		mdb_printf("TRUE ");
    558      0     stevel 
    559      0     stevel 	mdb_printf(" %0?p\n", mio.mi_o_dev);
    560      0     stevel 
    561      0     stevel 	return (DCMD_OK);
    562      0     stevel }
    563      0     stevel 
    564   3448   dh155122 static int
    565   3448   dh155122 ns_to_stackid(uintptr_t kaddr)
    566   3448   dh155122 {
    567   3448   dh155122 	netstack_t nss;
    568   3448   dh155122 
    569   3448   dh155122 	if (mdb_vread(&nss, sizeof (nss), kaddr) == -1) {
    570   3448   dh155122 		mdb_warn("failed to read netstack_t %p", kaddr);
    571   3448   dh155122 		return (0);
    572   3448   dh155122 	}
    573   3448   dh155122 	return (nss.netstack_stackid);
    574   3448   dh155122 }
    575   3448   dh155122 
    576   3448   dh155122 
    577   3448   dh155122 
    578      0     stevel static void
    579      0     stevel netstat_tcp_verbose_pr(const tcp_t *tcp)
    580      0     stevel {
    581      0     stevel 	mdb_printf("       %5i %08x %08x %5i %08x %08x %5li %5i\n",
    582      0     stevel 	    tcp->tcp_swnd, tcp->tcp_snxt, tcp->tcp_suna, tcp->tcp_rwnd,
    583      0     stevel 	    tcp->tcp_rack, tcp->tcp_rnxt, tcp->tcp_rto, tcp->tcp_mss);
    584      0     stevel }
    585      0     stevel 
    586      0     stevel /*ARGSUSED*/
    587      0     stevel static int
    588   9089  Vasumathi netstat_tcp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
    589      0     stevel {
    590   9089  Vasumathi 	netstat_cb_data_t *ncb = cb_data;
    591   9089  Vasumathi 	uint_t opts = ncb->opts;
    592   9089  Vasumathi 	int af = ncb->af;
    593      0     stevel 	uintptr_t tcp_kaddr;
    594   9089  Vasumathi 	conn_t *connp = &ncb->conn;
    595   5563   nordmark 	tcp_t tcps, *tcp;
    596      0     stevel 
    597   9089  Vasumathi 	if (mdb_vread(connp, sizeof (conn_t), kaddr) == -1) {
    598   5563   nordmark 		mdb_warn("failed to read conn_t at %p", kaddr);
    599   5563   nordmark 		return (WALK_ERR);
    600   5563   nordmark 	}
    601      0     stevel 
    602   5563   nordmark 	tcp_kaddr = (uintptr_t)connp->conn_tcp;
    603   5563   nordmark 	if (mdb_vread(&tcps, sizeof (tcp_t), tcp_kaddr) == -1) {
    604  11042       Erik 		mdb_warn("failed to read tcp_t at %p", tcp_kaddr);
    605      0     stevel 		return (WALK_ERR);
    606      0     stevel 	}
    607      0     stevel 
    608   5563   nordmark 	tcp = &tcps;
    609      0     stevel 	connp->conn_tcp = tcp;
    610      0     stevel 	tcp->tcp_connp = connp;
    611      0     stevel 
    612    741   masputra 	if (!((opts & NETSTAT_ALL) || net_tcp_active(tcp)) ||
    613      0     stevel 	    (af == AF_INET && !net_tcp_ipv4(tcp)) ||
    614      0     stevel 	    (af == AF_INET6 && !net_tcp_ipv6(tcp))) {
    615      0     stevel 		return (WALK_NEXT);
    616      0     stevel 	}
    617      0     stevel 
    618      0     stevel 	mdb_printf("%0?p %2i ", tcp_kaddr, tcp->tcp_state);
    619      0     stevel 	if (af == AF_INET) {
    620  11042       Erik 		net_ipv4addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
    621      0     stevel 		mdb_printf(" ");
    622  11042       Erik 		net_ipv4addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
    623      0     stevel 	} else if (af == AF_INET6) {
    624  11042       Erik 		net_ipv6addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
    625      0     stevel 		mdb_printf(" ");
    626  11042       Erik 		net_ipv6addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
    627      0     stevel 	}
    628   9089  Vasumathi 	mdb_printf(" %5i", ns_to_stackid((uintptr_t)connp->conn_netstack));
    629      0     stevel 	mdb_printf(" %4i\n", connp->conn_zoneid);
    630      0     stevel 	if (opts & NETSTAT_VERBOSE)
    631      0     stevel 		netstat_tcp_verbose_pr(tcp);
    632      0     stevel 
    633      0     stevel 	return (WALK_NEXT);
    634      0     stevel }
    635      0     stevel 
    636    741   masputra /*ARGSUSED*/
    637      0     stevel static int
    638   9089  Vasumathi netstat_udp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
    639      0     stevel {
    640   9089  Vasumathi 	netstat_cb_data_t *ncb = cb_data;
    641   9089  Vasumathi 	uint_t opts = ncb->opts;
    642   9089  Vasumathi 	int af = ncb->af;
    643    741   masputra 	udp_t udp;
    644   9089  Vasumathi 	conn_t *connp = &ncb->conn;
    645   9089  Vasumathi 	char *state;
    646      0     stevel 
    647   9089  Vasumathi 	if (mdb_vread(connp, sizeof (conn_t), kaddr) == -1) {
    648   5563   nordmark 		mdb_warn("failed to read conn_t at %p", kaddr);
    649    741   masputra 		return (WALK_ERR);
    650    741   masputra 	}
    651    741   masputra 
    652   5563   nordmark 	if (mdb_vread(&udp, sizeof (udp_t),
    653   9089  Vasumathi 	    (uintptr_t)connp->conn_udp) == -1) {
    654   5563   nordmark 		mdb_warn("failed to read conn_udp at %p",
    655   9089  Vasumathi 		    (uintptr_t)connp->conn_udp);
    656    741   masputra 		return (WALK_ERR);
    657    741   masputra 	}
    658    741   masputra 
    659  11042       Erik 	connp->conn_udp = &udp;
    660  11042       Erik 	udp.udp_connp = connp;
    661  11042       Erik 
    662    741   masputra 	if (!((opts & NETSTAT_ALL) || net_udp_active(&udp)) ||
    663    741   masputra 	    (af == AF_INET && !net_udp_ipv4(&udp)) ||
    664    741   masputra 	    (af == AF_INET6 && !net_udp_ipv6(&udp))) {
    665      0     stevel 		return (WALK_NEXT);
    666    741   masputra 	}
    667      0     stevel 
    668   9089  Vasumathi 	if (udp.udp_state == TS_UNBND)
    669   9089  Vasumathi 		state = "UNBOUND";
    670   9089  Vasumathi 	else if (udp.udp_state == TS_IDLE)
    671   9089  Vasumathi 		state = "IDLE";
    672   9089  Vasumathi 	else if (udp.udp_state == TS_DATA_XFER)
    673   9089  Vasumathi 		state = "CONNECTED";
    674   9089  Vasumathi 	else
    675   9089  Vasumathi 		state = "UNKNOWN";
    676   9089  Vasumathi 
    677   9089  Vasumathi 	mdb_printf("%0?p %10s ", (uintptr_t)connp->conn_udp, state);
    678    741   masputra 	if (af == AF_INET) {
    679  11042       Erik 		net_ipv4addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
    680    741   masputra 		mdb_printf(" ");
    681  11042       Erik 		net_ipv4addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
    682    741   masputra 	} else if (af == AF_INET6) {
    683  11042       Erik 		net_ipv6addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
    684    741   masputra 		mdb_printf(" ");
    685  11042       Erik 		net_ipv6addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
    686    741   masputra 	}
    687   9089  Vasumathi 	mdb_printf(" %5i", ns_to_stackid((uintptr_t)connp->conn_netstack));
    688   9089  Vasumathi 	mdb_printf(" %4i\n", connp->conn_zoneid);
    689      0     stevel 
    690      0     stevel 	return (WALK_NEXT);
    691      0     stevel }
    692      0     stevel 
    693   9089  Vasumathi /*ARGSUSED*/
    694      0     stevel static int
    695   9089  Vasumathi netstat_icmp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
    696    741   masputra {
    697   9089  Vasumathi 	netstat_cb_data_t *ncb = cb_data;
    698   9089  Vasumathi 	int af = ncb->af;
    699   9089  Vasumathi 	icmp_t icmp;
    700   9089  Vasumathi 	conn_t *connp = &ncb->conn;
    701   9089  Vasumathi 	char *state;
    702    741   masputra 
    703   9089  Vasumathi 	if (mdb_vread(connp, sizeof (conn_t), kaddr) == -1) {
    704   9089  Vasumathi 		mdb_warn("failed to read conn_t at %p", kaddr);
    705   9089  Vasumathi 		return (WALK_ERR);
    706   9089  Vasumathi 	}
    707   9089  Vasumathi 
    708   9089  Vasumathi 	if (mdb_vread(&icmp, sizeof (icmp_t),
    709   9089  Vasumathi 	    (uintptr_t)connp->conn_icmp) == -1) {
    710   9089  Vasumathi 		mdb_warn("failed to read conn_icmp at %p",
    711   9089  Vasumathi 		    (uintptr_t)connp->conn_icmp);
    712   9089  Vasumathi 		return (WALK_ERR);
    713   9089  Vasumathi 	}
    714   9089  Vasumathi 
    715  11042       Erik 	connp->conn_icmp = &icmp;
    716  11042       Erik 	icmp.icmp_connp = connp;
    717  11042       Erik 
    718  11042       Erik 	if ((af == AF_INET && connp->conn_ipversion != IPV4_VERSION) ||
    719  11042       Erik 	    (af == AF_INET6 && connp->conn_ipversion != IPV6_VERSION)) {
    720   9089  Vasumathi 		return (WALK_NEXT);
    721   9089  Vasumathi 	}
    722   9089  Vasumathi 
    723   9089  Vasumathi 	if (icmp.icmp_state == TS_UNBND)
    724   9089  Vasumathi 		state = "UNBOUND";
    725   9089  Vasumathi 	else if (icmp.icmp_state == TS_IDLE)
    726   9089  Vasumathi 		state = "IDLE";
    727   9089  Vasumathi 	else if (icmp.icmp_state == TS_DATA_XFER)
    728   9089  Vasumathi 		state = "CONNECTED";
    729   9089  Vasumathi 	else
    730   9089  Vasumathi 		state = "UNKNOWN";
    731   9089  Vasumathi 
    732   9089  Vasumathi 	mdb_printf("%0?p %10s ", (uintptr_t)connp->conn_icmp, state);
    733   9089  Vasumathi 	if (af == AF_INET) {
    734  11042       Erik 		net_ipv4addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
    735  11042       Erik 		mdb_printf(" ");
    736  11042       Erik 		net_ipv4addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
    737   9089  Vasumathi 	} else if (af == AF_INET6) {
    738  11042       Erik 		net_ipv6addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
    739  11042       Erik 		mdb_printf(" ");
    740  11042       Erik 		net_ipv6addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
    741   9089  Vasumathi 	}
    742   9089  Vasumathi 	mdb_printf(" %5i", ns_to_stackid((uintptr_t)connp->conn_netstack));
    743  11042       Erik 	mdb_printf(" %4i\n", connp->conn_zoneid);
    744   9089  Vasumathi 
    745   9089  Vasumathi 	return (WALK_NEXT);
    746      0     stevel }
    747      0     stevel 
    748      0     stevel /*
    749      0     stevel  * print the address of a unix domain socket
    750      0     stevel  *
    751      0     stevel  * so is the address of a AF_UNIX struct sonode in mdb's address space
    752      0     stevel  * soa is the address of the struct soaddr to print
    753      0     stevel  *
    754      0     stevel  * returns 0 on success, -1 otherwise
    755      0     stevel  */
    756      0     stevel static int
    757   8348       Eric netstat_unix_name_pr(const struct sotpi_sonode *st, const struct soaddr *soa)
    758      0     stevel {
    759   8348       Eric 	const struct sonode *so = &st->st_sonode;
    760      0     stevel 	const char none[] = " (none)";
    761      0     stevel 
    762      0     stevel 	if ((so->so_state & SS_ISBOUND) && (soa->soa_len != 0)) {
    763   8348       Eric 		if (st->st_info.sti_faddr_noxlate) {
    764      0     stevel 			mdb_printf("%-14s ", " (socketpair)");
    765      0     stevel 		} else {
    766      0     stevel 			if (soa->soa_len > sizeof (sa_family_t)) {
    767      0     stevel 				char addr[MAXPATHLEN + 1];
    768      0     stevel 
    769      0     stevel 				if (mdb_readstr(addr, sizeof (addr),
    770      0     stevel 				    (uintptr_t)&soa->soa_sa->sa_data) == -1) {
    771      0     stevel 					mdb_warn("failed to read unix address "
    772      0     stevel 					    "at %p", &soa->soa_sa->sa_data);
    773      0     stevel 					return (-1);
    774      0     stevel 				}
    775      0     stevel 
    776      0     stevel 				mdb_printf("%-14s ", addr);
    777      0     stevel 			} else {
    778      0     stevel 				mdb_printf("%-14s ", none);
    779      0     stevel 			}
    780      0     stevel 		}
    781      0     stevel 	} else {
    782      0     stevel 		mdb_printf("%-14s ", none);
    783      0     stevel 	}
    784      0     stevel 
    785      0     stevel 	return (0);
    786      0     stevel }
    787      0     stevel 
    788      0     stevel /* based on sockfs_snapshot */
    789      0     stevel /*ARGSUSED*/
    790      0     stevel static int
    791      0     stevel netstat_unix_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
    792      0     stevel {
    793   8348       Eric 	const struct sotpi_sonode *st = walk_data;
    794   8348       Eric 	const struct sonode *so = &st->st_sonode;
    795   8348       Eric 	const struct sotpi_info *sti = &st->st_info;
    796      0     stevel 
    797   8348       Eric 	if (so->so_count == 0)
    798      0     stevel 		return (WALK_NEXT);
    799      0     stevel 
    800      0     stevel 	if (so->so_family != AF_UNIX) {
    801      0     stevel 		mdb_warn("sonode of family %hi at %p\n", so->so_family, kaddr);
    802      0     stevel 		return (WALK_ERR);
    803      0     stevel 	}
    804      0     stevel 
    805      0     stevel 	mdb_printf("%-?p ", kaddr);
    806      0     stevel 
    807   8348       Eric 	switch (sti->sti_serv_type) {
    808   5563   nordmark 	case T_CLTS:
    809      0     stevel 		mdb_printf("%-10s ", "dgram");
    810      0     stevel 		break;
    811   5563   nordmark 	case T_COTS:
    812      0     stevel 		mdb_printf("%-10s ", "stream");
    813      0     stevel 		break;
    814   5563   nordmark 	case T_COTS_ORD:
    815      0     stevel 		mdb_printf("%-10s ", "stream-ord");
    816      0     stevel 		break;
    817   5563   nordmark 	default:
    818   8348       Eric 		mdb_printf("%-10i ", sti->sti_serv_type);
    819      0     stevel 	}
    820      0     stevel 
    821      0     stevel 	if ((so->so_state & SS_ISBOUND) &&
    822   8348       Eric 	    (sti->sti_ux_laddr.soua_magic == SOU_MAGIC_EXPLICIT)) {
    823   8348       Eric 		mdb_printf("%0?p ", sti->sti_ux_laddr.soua_vp);
    824      0     stevel 	} else {
    825      0     stevel 		mdb_printf("%0?p ", NULL);
    826      0     stevel 	}
    827      0     stevel 
    828      0     stevel 	if ((so->so_state & SS_ISCONNECTED) &&
    829   8348       Eric 	    (sti->sti_ux_faddr.soua_magic == SOU_MAGIC_EXPLICIT)) {
    830   8348       Eric 		mdb_printf("%0?p ", sti->sti_ux_faddr.soua_vp);
    831      0     stevel 	} else {
    832      0     stevel 		mdb_printf("%0?p ", NULL);
    833      0     stevel 	}
    834      0     stevel 
    835   8348       Eric 	if (netstat_unix_name_pr(st, &sti->sti_laddr) == -1)
    836      0     stevel 		return (WALK_ERR);
    837      0     stevel 
    838   8348       Eric 	if (netstat_unix_name_pr(st, &sti->sti_faddr) == -1)
    839      0     stevel 		return (WALK_ERR);
    840      0     stevel 
    841      0     stevel 	mdb_printf("%4i\n", so->so_zoneid);
    842      0     stevel 
    843      0     stevel 	return (WALK_NEXT);
    844      0     stevel }
    845      0     stevel 
    846      0     stevel static void
    847      0     stevel netstat_tcp_verbose_header_pr(void)
    848      0     stevel {
    849      0     stevel 	mdb_printf("       %<u>%-5s %-8s %-8s %-5s %-8s %-8s %5s %5s%</u>\n",
    850      0     stevel 	    "Swind", "Snext", "Suna", "Rwind", "Rack", "Rnext", "Rto", "Mss");
    851      0     stevel }
    852      0     stevel 
    853   1676        jpk static void
    854   1676        jpk get_ifname(const ire_t *ire, char *intf)
    855   1676        jpk {
    856   1676        jpk 	ill_t ill;
    857   1676        jpk 
    858   1676        jpk 	*intf = '\0';
    859  11042       Erik 	if (ire->ire_ill != NULL) {
    860  11042       Erik 		if (mdb_vread(&ill, sizeof (ill),
    861  11042       Erik 		    (uintptr_t)ire->ire_ill) == -1)
    862   1676        jpk 			return;
    863   1676        jpk 		(void) mdb_readstr(intf, MIN(LIFNAMSIZ, ill.ill_name_length),
    864   1676        jpk 		    (uintptr_t)ill.ill_name);
    865   1676        jpk 	}
    866   1676        jpk }
    867   1676        jpk 
    868  11042       Erik const in6_addr_t ipv6_all_ones =
    869  11042       Erik 	{ 0xffffffffU, 0xffffffffU, 0xffffffffU, 0xffffffffU };
    870  11042       Erik 
    871   1676        jpk static void
    872  11042       Erik get_ireflags(const ire_t *ire, char *flags)
    873   1676        jpk {
    874   1676        jpk 	(void) strcpy(flags, "U");
    875  11042       Erik 	/* RTF_INDIRECT wins over RTF_GATEWAY - don't display both */
    876  11042       Erik 	if (ire->ire_flags & RTF_INDIRECT)
    877  11042       Erik 		(void) strcat(flags, "I");
    878  11042       Erik 	else if (ire->ire_type & IRE_OFFLINK)
    879   1676        jpk 		(void) strcat(flags, "G");
    880  11042       Erik 
    881  11042       Erik 	/* IRE_IF_CLONE wins over RTF_HOST - don't display both */
    882  11042       Erik 	if (ire->ire_type & IRE_IF_CLONE)
    883  11042       Erik 		(void) strcat(flags, "C");
    884  11042       Erik 	else if (ire->ire_ipversion == IPV4_VERSION) {
    885  11042       Erik 		if (ire->ire_mask == IP_HOST_MASK)
    886  11042       Erik 			(void) strcat(flags, "H");
    887  11042       Erik 	} else {
    888  11042       Erik 		if (IN6_ARE_ADDR_EQUAL(&ire->ire_mask_v6, &ipv6_all_ones))
    889  11042       Erik 			(void) strcat(flags, "H");
    890  11042       Erik 	}
    891  11042       Erik 
    892  11042       Erik 	if (ire->ire_flags & RTF_DYNAMIC)
    893   1676        jpk 		(void) strcat(flags, "D");
    894   1676        jpk 	if (ire->ire_type == IRE_BROADCAST)
    895  11042       Erik 		(void) strcat(flags, "b");
    896  11042       Erik 	if (ire->ire_type == IRE_MULTICAST)
    897  11042       Erik 		(void) strcat(flags, "m");
    898   1676        jpk 	if (ire->ire_type == IRE_LOCAL)
    899   1676        jpk 		(void) strcat(flags, "L");
    900  11042       Erik 	if (ire->ire_type == IRE_NOROUTE)
    901  11042       Erik 		(void) strcat(flags, "N");
    902   1676        jpk 	if (ire->ire_flags & RTF_MULTIRT)
    903   1676        jpk 		(void) strcat(flags, "M");
    904   1676        jpk 	if (ire->ire_flags & RTF_SETSRC)
    905   1676        jpk 		(void) strcat(flags, "S");
    906  11042       Erik 	if (ire->ire_flags & RTF_REJECT)
    907  11042       Erik 		(void) strcat(flags, "R");
    908  11042       Erik 	if (ire->ire_flags & RTF_BLACKHOLE)
    909  11042       Erik 		(void) strcat(flags, "B");
    910   1676        jpk }
    911   1676        jpk 
    912   1676        jpk static int
    913   1676        jpk netstat_irev4_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
    914   1676        jpk {
    915   1676        jpk 	const ire_t *ire = walk_data;
    916   1676        jpk 	uint_t *opts = cb_data;
    917   1676        jpk 	ipaddr_t gate;
    918   1676        jpk 	char flags[10], intf[LIFNAMSIZ + 1];
    919   1676        jpk 
    920   4823        seb 	if (ire->ire_ipversion != IPV4_VERSION)
    921   1676        jpk 		return (WALK_NEXT);
    922   1676        jpk 
    923  11042       Erik 	/* Skip certain IREs by default */
    924  11042       Erik 	if (!(*opts & NETSTAT_ALL) &&
    925  11042       Erik 	    (ire->ire_type &
    926  11042       Erik 	    (IRE_BROADCAST|IRE_LOCAL|IRE_MULTICAST|IRE_NOROUTE|IRE_IF_CLONE)))
    927   1676        jpk 		return (WALK_NEXT);
    928   1676        jpk 
    929   1676        jpk 	if (*opts & NETSTAT_FIRST) {
    930   1676        jpk 		*opts &= ~NETSTAT_FIRST;
    931   1676        jpk 		mdb_printf("%<u>%s Table: IPv4%</u>\n",
    932   1676        jpk 		    (*opts & NETSTAT_VERBOSE) ? "IRE" : "Routing");
    933   1676        jpk 		if (*opts & NETSTAT_VERBOSE) {
    934   1676        jpk 			mdb_printf("%<u>%-?s %-*s %-*s %-*s Device Mxfrg Rtt  "
    935   1676        jpk 			    " Ref Flg Out   In/Fwd%</u>\n",
    936   1676        jpk 			    "Address", ADDR_V4_WIDTH, "Destination",
    937   1676        jpk 			    ADDR_V4_WIDTH, "Mask", ADDR_V4_WIDTH, "Gateway");
    938   1676        jpk 		} else {
    939   1676        jpk 			mdb_printf("%<u>%-?s %-*s %-*s Flags Ref  Use   "
    940   1676        jpk 			    "Interface%</u>\n",
    941   1676        jpk 			    "Address", ADDR_V4_WIDTH, "Destination",
    942   1676        jpk 			    ADDR_V4_WIDTH, "Gateway");
    943   1676        jpk 		}
    944   1676        jpk 	}
    945   1676        jpk 
    946  11042       Erik 	gate = ire->ire_gateway_addr;
    947   1676        jpk 
    948  11042       Erik 	get_ireflags(ire, flags);
    949   1676        jpk 
    950   1676        jpk 	get_ifname(ire, intf);
    951   1676        jpk 
    952   1676        jpk 	if (*opts & NETSTAT_VERBOSE) {
    953   1676        jpk 		mdb_printf("%?p %-*I %-*I %-*I %-6s %5u%c %4u %3u %-3s %5u "
    954   1676        jpk 		    "%u\n", kaddr, ADDR_V4_WIDTH, ire->ire_addr, ADDR_V4_WIDTH,
    955   1676        jpk 		    ire->ire_mask, ADDR_V4_WIDTH, gate, intf,
    956  11042       Erik 		    0, ' ',
    957  11042       Erik 		    ire->ire_metrics.iulp_rtt, ire->ire_refcnt, flags,
    958   1676        jpk 		    ire->ire_ob_pkt_count, ire->ire_ib_pkt_count);
    959   1676        jpk 	} else {
    960   1676        jpk 		mdb_printf("%?p %-*I %-*I %-5s %4u %5u %s\n", kaddr,
    961   1676        jpk 		    ADDR_V4_WIDTH, ire->ire_addr, ADDR_V4_WIDTH, gate, flags,
    962   1676        jpk 		    ire->ire_refcnt,
    963   1676        jpk 		    ire->ire_ob_pkt_count + ire->ire_ib_pkt_count, intf);
    964   1676        jpk 	}
    965   1676        jpk 
    966   1676        jpk 	return (WALK_NEXT);
    967   1676        jpk }
    968   1676        jpk 
    969   1676        jpk int
    970   1676        jpk ip_mask_to_plen_v6(const in6_addr_t *v6mask)
    971   1676        jpk {
    972   1676        jpk 	int plen;
    973   1676        jpk 	int i;
    974   1676        jpk 	uint32_t val;
    975   1676        jpk 
    976   1676        jpk 	for (i = 3; i >= 0; i--)
    977   1676        jpk 		if (v6mask->s6_addr32[i] != 0)
    978   1676        jpk 			break;
    979   1676        jpk 	if (i < 0)
    980   1676        jpk 		return (0);
    981   1676        jpk 	plen = 32 + 32 * i;
    982   1676        jpk 	val = v6mask->s6_addr32[i];
    983   1676        jpk 	while (!(val & 1)) {
    984   1676        jpk 		val >>= 1;
    985   1676        jpk 		plen--;
    986   1676        jpk 	}
    987   1676        jpk 
    988   1676        jpk 	return (plen);
    989   1676        jpk }
    990   1676        jpk 
    991   1676        jpk static int
    992   1676        jpk netstat_irev6_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
    993   1676        jpk {
    994   1676        jpk 	const ire_t *ire = walk_data;
    995   1676        jpk 	uint_t *opts = cb_data;
    996   1676        jpk 	const in6_addr_t *gatep;
    997   1676        jpk 	char deststr[ADDR_V6_WIDTH + 5];
    998   1676        jpk 	char flags[10], intf[LIFNAMSIZ + 1];
    999   1676        jpk 	int masklen;
   1000   1676        jpk 
   1001   1676        jpk 	if (ire->ire_ipversion != IPV6_VERSION)
   1002   1676        jpk 		return (WALK_NEXT);
   1003   1676        jpk 
   1004  11042       Erik 	/* Skip certain IREs by default */
   1005  11042       Erik 	if (!(*opts & NETSTAT_ALL) &&
   1006  11042       Erik 	    (ire->ire_type &
   1007  11042       Erik 	    (IRE_BROADCAST|IRE_LOCAL|IRE_MULTICAST|IRE_NOROUTE|IRE_IF_CLONE)))
   1008   1676        jpk 		return (WALK_NEXT);
   1009   1676        jpk 
   1010   1676        jpk 	if (*opts & NETSTAT_FIRST) {
   1011   1676        jpk 		*opts &= ~NETSTAT_FIRST;
   1012   1676        jpk 		mdb_printf("\n%<u>%s Table: IPv6%</u>\n",
   1013   1676        jpk 		    (*opts & NETSTAT_VERBOSE) ? "IRE" : "Routing");
   1014   1676        jpk 		if (*opts & NETSTAT_VERBOSE) {
   1015   1676        jpk 			mdb_printf("%<u>%-?s %-*s %-*s If    PMTU   Rtt   Ref "
   1016   1676        jpk 			    "Flags Out    In/Fwd%</u>\n",
   1017   1676        jpk 			    "Address", ADDR_V6_WIDTH+4, "Destination/Mask",
   1018   1676        jpk 			    ADDR_V6_WIDTH, "Gateway");
   1019   1676        jpk 		} else {
   1020   1676        jpk 			mdb_printf("%<u>%-?s %-*s %-*s Flags Ref Use    If"
   1021   1676        jpk 			    "%</u>\n",
   1022   1676        jpk 			    "Address", ADDR_V6_WIDTH+4, "Destination/Mask",
   1023   1676        jpk 			    ADDR_V6_WIDTH, "Gateway");
   1024   1676        jpk 		}
   1025   1676        jpk 	}
   1026   1676        jpk 
   1027  11042       Erik 	gatep = &ire->ire_gateway_addr_v6;
   1028   1676        jpk 
   1029   1676        jpk 	masklen = ip_mask_to_plen_v6(&ire->ire_mask_v6);
   1030   1676        jpk 	(void) mdb_snprintf(deststr, sizeof (deststr), "%N/%d",
   1031   1676        jpk 	    &ire->ire_addr_v6, masklen);
   1032   1676        jpk 
   1033  11042       Erik 	get_ireflags(ire, flags);
   1034   1676        jpk 
   1035   1676        jpk 	get_ifname(ire, intf);
   1036   1676        jpk 
   1037   1676        jpk 	if (*opts & NETSTAT_VERBOSE) {
   1038   1676        jpk 		mdb_printf("%?p %-*s %-*N %-5s %5u%c %5u %3u %-5s %6u %u\n",
   1039   1676        jpk 		    kaddr, ADDR_V6_WIDTH+4, deststr, ADDR_V6_WIDTH, gatep,
   1040  11042       Erik 		    intf, 0, ' ',
   1041  11042       Erik 		    ire->ire_metrics.iulp_rtt, ire->ire_refcnt,
   1042   1676        jpk 		    flags, ire->ire_ob_pkt_count, ire->ire_ib_pkt_count);
   1043   1676        jpk 	} else {
   1044   1676        jpk 		mdb_printf("%?p %-*s %-*N %-5s %3u %6u %s\n", kaddr,
   1045   1676        jpk 		    ADDR_V6_WIDTH+4, deststr, ADDR_V6_WIDTH, gatep, flags,
   1046   1676        jpk 		    ire->ire_refcnt,
   1047   1676        jpk 		    ire->ire_ob_pkt_count + ire->ire_ib_pkt_count, intf);
   1048   1676        jpk 	}
   1049   1676        jpk 
   1050   1676        jpk 	return (WALK_NEXT);
   1051   1676        jpk }
   1052   1676        jpk 
   1053   9089  Vasumathi static void
   1054   9089  Vasumathi netstat_header_v4(int proto)
   1055   9089  Vasumathi {
   1056   9089  Vasumathi 	if (proto == IPPROTO_TCP)
   1057   9089  Vasumathi 		mdb_printf("%<u>%-?s ", "TCPv4");
   1058   9089  Vasumathi 	else if (proto == IPPROTO_UDP)
   1059   9089  Vasumathi 		mdb_printf("%<u>%-?s ", "UDPv4");
   1060   9089  Vasumathi 	else if (proto == IPPROTO_ICMP)
   1061   9089  Vasumathi 		mdb_printf("%<u>%-?s ", "ICMPv4");
   1062   9089  Vasumathi 	mdb_printf("State %6s%*s %6s%*s %-5s %-4s%</u>\n",
   1063   9089  Vasumathi 	    "", ADDR_V4_WIDTH, "Local Address",
   1064   9089  Vasumathi 	    "", ADDR_V4_WIDTH, "Remote Address", "Stack", "Zone");
   1065   9089  Vasumathi }
   1066   9089  Vasumathi 
   1067   9089  Vasumathi static void
   1068   9089  Vasumathi netstat_header_v6(int proto)
   1069   9089  Vasumathi {
   1070   9089  Vasumathi 	if (proto == IPPROTO_TCP)
   1071   9089  Vasumathi 		mdb_printf("%<u>%-?s ", "TCPv6");
   1072   9089  Vasumathi 	else if (proto == IPPROTO_UDP)
   1073   9089  Vasumathi 		mdb_printf("%<u>%-?s ", "UDPv6");
   1074   9089  Vasumathi 	else if (proto == IPPROTO_ICMP)
   1075   9089  Vasumathi 		mdb_printf("%<u>%-?s ", "ICMPv6");
   1076   9089  Vasumathi 	mdb_printf("State %6s%*s %6s%*s %-5s %-4s%</u>\n",
   1077   9089  Vasumathi 	    "", ADDR_V6_WIDTH, "Local Address",
   1078   9089  Vasumathi 	    "", ADDR_V6_WIDTH, "Remote Address", "Stack", "Zone");
   1079   9089  Vasumathi }
   1080   9089  Vasumathi 
   1081   9089  Vasumathi static int
   1082   9089  Vasumathi netstat_print_conn(const char *cache, int proto, mdb_walk_cb_t cbfunc,
   1083   9089  Vasumathi     void *cbdata)
   1084   9089  Vasumathi {
   1085   9089  Vasumathi 	netstat_cb_data_t *ncb = cbdata;
   1086   9089  Vasumathi 
   1087   9089  Vasumathi 	if ((ncb->opts & NETSTAT_VERBOSE) && proto == IPPROTO_TCP)
   1088   9089  Vasumathi 		netstat_tcp_verbose_header_pr();
   1089   9089  Vasumathi 	if (mdb_walk(cache, cbfunc, cbdata) == -1) {
   1090   9089  Vasumathi 		mdb_warn("failed to walk %s", cache);
   1091   9089  Vasumathi 		return (DCMD_ERR);
   1092   9089  Vasumathi 	}
   1093   9089  Vasumathi 	return (DCMD_OK);
   1094   9089  Vasumathi }
   1095   9089  Vasumathi 
   1096   9089  Vasumathi static int
   1097   9089  Vasumathi netstat_print_common(const char *cache, int proto, mdb_walk_cb_t cbfunc,
   1098   9089  Vasumathi     void *cbdata)
   1099   9089  Vasumathi {
   1100   9089  Vasumathi 	netstat_cb_data_t *ncb = cbdata;
   1101   9089  Vasumathi 	int af = ncb->af;
   1102   9089  Vasumathi 	int status = DCMD_OK;
   1103   9089  Vasumathi 
   1104   9089  Vasumathi 	if (af != AF_INET6) {
   1105   9089  Vasumathi 		ncb->af = AF_INET;
   1106   9089  Vasumathi 		netstat_header_v4(proto);
   1107   9089  Vasumathi 		status = netstat_print_conn(cache, proto, cbfunc, cbdata);
   1108   9089  Vasumathi 	}
   1109   9089  Vasumathi 	if (status == DCMD_OK && af != AF_INET) {
   1110   9089  Vasumathi 		ncb->af = AF_INET6;
   1111   9089  Vasumathi 		netstat_header_v6(proto);
   1112   9089  Vasumathi 		status = netstat_print_conn(cache, proto, cbfunc, cbdata);
   1113   9089  Vasumathi 	}
   1114   9089  Vasumathi 	ncb->af = af;
   1115   9089  Vasumathi 	return (status);
   1116   9089  Vasumathi }
   1117   9089  Vasumathi 
   1118      0     stevel /*ARGSUSED*/
   1119      0     stevel int
   1120      0     stevel netstat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
   1121      0     stevel {
   1122      0     stevel 	uint_t opts = 0;
   1123      0     stevel 	const char *optf = NULL;
   1124      0     stevel 	const char *optP = NULL;
   1125   9089  Vasumathi 	netstat_cb_data_t *cbdata;
   1126   9089  Vasumathi 	int status;
   1127   9089  Vasumathi 	int af = 0;
   1128      0     stevel 
   1129      0     stevel 	if (mdb_getopts(argc, argv,
   1130      0     stevel 	    'a', MDB_OPT_SETBITS, NETSTAT_ALL, &opts,
   1131      0     stevel 	    'f', MDB_OPT_STR, &optf,
   1132      0     stevel 	    'P', MDB_OPT_STR, &optP,
   1133   1676        jpk 	    'r', MDB_OPT_SETBITS, NETSTAT_ROUTE, &opts,
   1134   1676        jpk 	    'v', MDB_OPT_SETBITS, NETSTAT_VERBOSE, &opts,
   1135      0     stevel 	    NULL) != argc)
   1136      0     stevel 		return (DCMD_USAGE);
   1137      0     stevel 
   1138      0     stevel 	if (optP != NULL) {
   1139   9089  Vasumathi 		if ((strcmp("tcp", optP) != 0) && (strcmp("udp", optP) != 0) &&
   1140   9089  Vasumathi 		    (strcmp("icmp", optP) != 0))
   1141      0     stevel 			return (DCMD_USAGE);
   1142   1676        jpk 		if (opts & NETSTAT_ROUTE)
   1143   1676        jpk 			return (DCMD_USAGE);
   1144      0     stevel 	}
   1145      0     stevel 
   1146   1676        jpk 	if (optf == NULL)
   1147   1676        jpk 		opts |= NETSTAT_V4 | NETSTAT_V6 | NETSTAT_UNIX;
   1148   1676        jpk 	else if (strcmp("inet", optf) == 0)
   1149   1676        jpk 		opts |= NETSTAT_V4;
   1150   1676        jpk 	else if (strcmp("inet6", optf) == 0)
   1151   1676        jpk 		opts |= NETSTAT_V6;
   1152   1676        jpk 	else if (strcmp("unix", optf) == 0)
   1153   1676        jpk 		opts |= NETSTAT_UNIX;
   1154   1676        jpk 	else
   1155   1676        jpk 		return (DCMD_USAGE);
   1156   1676        jpk 
   1157   1676        jpk 	if (opts & NETSTAT_ROUTE) {
   1158   1676        jpk 		if (!(opts & (NETSTAT_V4|NETSTAT_V6)))
   1159      0     stevel 			return (DCMD_USAGE);
   1160   1676        jpk 		if (opts & NETSTAT_V4) {
   1161   1676        jpk 			opts |= NETSTAT_FIRST;
   1162   1676        jpk 			if (mdb_walk("ip`ire", netstat_irev4_cb, &opts) == -1) {
   1163   1676        jpk 				mdb_warn("failed to walk ip`ire");
   1164   1676        jpk 				return (DCMD_ERR);
   1165   1676        jpk 			}
   1166   1676        jpk 		}
   1167   1676        jpk 		if (opts & NETSTAT_V6) {
   1168   1676        jpk 			opts |= NETSTAT_FIRST;
   1169   1676        jpk 			if (mdb_walk("ip`ire", netstat_irev6_cb, &opts) == -1) {
   1170   1676        jpk 				mdb_warn("failed to walk ip`ire");
   1171   1676        jpk 				return (DCMD_ERR);
   1172   1676        jpk 			}
   1173   1676        jpk 		}
   1174   1676        jpk 		return (DCMD_OK);
   1175      0     stevel 	}
   1176      0     stevel 
   1177   9089  Vasumathi 	if ((opts & NETSTAT_UNIX) && (optP == NULL)) {
   1178      0     stevel 		/* Print Unix Domain Sockets */
   1179      0     stevel 		mdb_printf("%<u>%-?s %-10s %-?s %-?s %-14s %-14s %s%</u>\n",
   1180      0     stevel 		    "AF_UNIX", "Type", "Vnode", "Conn", "Local Addr",
   1181      0     stevel 		    "Remote Addr", "Zone");
   1182      0     stevel 
   1183      0     stevel 		if (mdb_walk("genunix`sonode", netstat_unix_cb, NULL) == -1) {
   1184      0     stevel 			mdb_warn("failed to walk genunix`sonode");
   1185      0     stevel 			return (DCMD_ERR);
   1186      0     stevel 		}
   1187   9089  Vasumathi 		if (!(opts & (NETSTAT_V4 | NETSTAT_V6)))
   1188   9089  Vasumathi 			return (DCMD_OK);
   1189      0     stevel 	}
   1190      0     stevel 
   1191   9089  Vasumathi 	cbdata = mdb_alloc(sizeof (netstat_cb_data_t), UM_SLEEP);
   1192   9089  Vasumathi 	cbdata->opts = opts;
   1193   9089  Vasumathi 	if ((optf != NULL) && (opts & NETSTAT_V4))
   1194   9089  Vasumathi 		af = AF_INET;
   1195   9089  Vasumathi 	else if ((optf != NULL) && (opts & NETSTAT_V6))
   1196   9089  Vasumathi 		af = AF_INET6;
   1197   9089  Vasumathi 
   1198   9089  Vasumathi 	cbdata->af = af;
   1199   9089  Vasumathi 	if ((optP == NULL) || (strcmp("tcp", optP) == 0)) {
   1200   9089  Vasumathi 		status = netstat_print_common("tcp_conn_cache", IPPROTO_TCP,
   1201   9089  Vasumathi 		    netstat_tcp_cb, cbdata);
   1202   9089  Vasumathi 		if (status != DCMD_OK)
   1203   9089  Vasumathi 			goto out;
   1204   9089  Vasumathi 	}
   1205   9089  Vasumathi 
   1206   9089  Vasumathi 	if ((optP == NULL) || (strcmp("udp", optP) == 0)) {
   1207   9089  Vasumathi 		status = netstat_print_common("udp_conn_cache", IPPROTO_UDP,
   1208   9089  Vasumathi 		    netstat_udp_cb, cbdata);
   1209   9089  Vasumathi 		if (status != DCMD_OK)
   1210   9089  Vasumathi 			goto out;
   1211   9089  Vasumathi 	}
   1212   9089  Vasumathi 
   1213   9089  Vasumathi 	if ((optP == NULL) || (strcmp("icmp", optP) == 0)) {
   1214   9089  Vasumathi 		status = netstat_print_common("rawip_conn_cache", IPPROTO_ICMP,
   1215   9089  Vasumathi 		    netstat_icmp_cb, cbdata);
   1216   9089  Vasumathi 		if (status != DCMD_OK)
   1217   9089  Vasumathi 			goto out;
   1218   9089  Vasumathi 	}
   1219   9089  Vasumathi out:
   1220   9089  Vasumathi 	mdb_free(cbdata, sizeof (netstat_cb_data_t));
   1221   9089  Vasumathi 	return (status);
   1222      0     stevel }
   1223  10491      Rishi 
   1224  10491      Rishi /*
   1225  10491      Rishi  * "::dladm show-bridge" support
   1226  10491      Rishi  */
   1227  10491      Rishi typedef struct {
   1228  10491      Rishi 	uint_t opt_l;
   1229  10491      Rishi 	uint_t opt_f;
   1230  10491      Rishi 	uint_t opt_t;
   1231  10491      Rishi 	const char *name;
   1232  10491      Rishi 	clock_t lbolt;
   1233  10491      Rishi 	boolean_t found;
   1234  10491      Rishi 	uint_t nlinks;
   1235  10491      Rishi 	uint_t nfwd;
   1236  10491      Rishi 
   1237  10491      Rishi 	/*
   1238  10491      Rishi 	 * These structures are kept inside the 'args' for allocation reasons.
   1239  10491      Rishi 	 * They're all large data structures (over 1K), and may cause the stack
   1240  10491      Rishi 	 * to explode.  mdb and kmdb will fail in these cases, and thus we
   1241  10491      Rishi 	 * allocate them from the heap.
   1242  10491      Rishi 	 */
   1243  10491      Rishi 	trill_inst_t ti;
   1244  10491      Rishi 	bridge_link_t bl;
   1245  10491      Rishi 	mac_impl_t mi;
   1246  10491      Rishi } show_bridge_args_t;
   1247  10491      Rishi 
   1248  10491      Rishi static void
   1249  10491      Rishi show_vlans(const uint8_t *vlans)
   1250  10491      Rishi {
   1251  10491      Rishi 	int i, bit;
   1252  10491      Rishi 	uint8_t val;
   1253  10491      Rishi 	int rstart = -1, rnext = -1;
   1254  10491      Rishi 
   1255  10491      Rishi 	for (i = 0; i < BRIDGE_VLAN_ARR_SIZE; i++) {
   1256  10491      Rishi 		val = vlans[i];
   1257  10491      Rishi 		if (i == 0)
   1258  10491      Rishi 			val &= ~1;
   1259  10491      Rishi 		while ((bit = mdb_ffs(val)) != 0) {
   1260  10491      Rishi 			bit--;
   1261  10491      Rishi 			val &= ~(1 << bit);
   1262  10491      Rishi 			bit += i * sizeof (*vlans) * NBBY;
   1263  10491      Rishi 			if (bit != rnext) {
   1264  10491      Rishi 				if (rnext != -1 && rstart + 1 != rnext)
   1265  10491      Rishi 					mdb_printf("-%d", rnext - 1);
   1266  10491      Rishi 				if (rstart != -1)
   1267  10491      Rishi 					mdb_printf(",");
   1268  10491      Rishi 				mdb_printf("%d", bit);
   1269  10491      Rishi 				rstart = bit;
   1270  10491      Rishi 			}
   1271  10491      Rishi 			rnext = bit + 1;
   1272  10491      Rishi 		}
   1273  10491      Rishi 	}
   1274  10491      Rishi 	if (rnext != -1 && rstart + 1 != rnext)
   1275  10491      Rishi 		mdb_printf("-%d", rnext - 1);
   1276  10491      Rishi 	mdb_printf("\n");
   1277  10491      Rishi }
   1278  10491      Rishi 
   1279  10491      Rishi /*
   1280  10491      Rishi  * This callback is invoked by a walk of the links attached to a bridge.  If
   1281  10491      Rishi  * we're showing link details, then they're printed here.  If not, then we just
   1282  10491      Rishi  * count up the links for the bridge summary.
   1283  10491      Rishi  */
   1284  10491      Rishi static int
   1285  10491      Rishi do_bridge_links(uintptr_t addr, const void *data, void *ptr)
   1286  10491      Rishi {
   1287  10491      Rishi 	show_bridge_args_t *args = ptr;
   1288  10491      Rishi 	const bridge_link_t *blp = data;
   1289  10491      Rishi 	char macaddr[ETHERADDRL * 3];
   1290  10491      Rishi 	const char *name;
   1291  10491      Rishi 
   1292  10491      Rishi 	args->nlinks++;
   1293  10491      Rishi 
   1294  10491      Rishi 	if (!args->opt_l)
   1295  10491      Rishi 		return (WALK_NEXT);
   1296  10491      Rishi 
   1297  10491      Rishi 	if (mdb_vread(&args->mi, sizeof (args->mi),
   1298  10491      Rishi 	    (uintptr_t)blp->bl_mh) == -1) {
   1299  10491      Rishi 		mdb_warn("cannot read mac data at %p", blp->bl_mh);
   1300  10491      Rishi 		name = "?";
   1301  10491      Rishi 	} else  {
   1302  10491      Rishi 		name = args->mi.mi_name;
   1303  10491      Rishi 	}
   1304  10491      Rishi 
   1305  10491      Rishi 	mdb_mac_addr(blp->bl_local_mac, ETHERADDRL, macaddr,
   1306  10491      Rishi 	    sizeof (macaddr));
   1307  10491      Rishi 
   1308  10491      Rishi 	mdb_printf("%-?p %-16s %-17s %03X %-4d ", addr, name, macaddr,
   1309  10491      Rishi 	    blp->bl_flags, blp->bl_pvid);
   1310  10491      Rishi 
   1311  10491      Rishi 	if (blp->bl_trilldata == NULL) {
   1312  10491      Rishi 		switch (blp->bl_state) {
   1313  10491      Rishi 		case BLS_BLOCKLISTEN:
   1314  10491      Rishi 			name = "BLOCK";
   1315  10491      Rishi 			break;
   1316  10491      Rishi 		case BLS_LEARNING:
   1317  10491      Rishi 			name = "LEARN";
   1318  10491      Rishi 			break;
   1319  10491      Rishi 		case BLS_FORWARDING:
   1320  10491      Rishi 			name = "FWD";
   1321  10491      Rishi 			break;
   1322  10491      Rishi 		default:
   1323  10491      Rishi 			name = "?";
   1324  10491      Rishi 		}
   1325  10491      Rishi 		mdb_printf("%-5s ", name);
   1326  10491      Rishi 		show_vlans(blp->bl_vlans);
   1327  10491      Rishi 	} else {
   1328  10491      Rishi 		show_vlans(blp->bl_afs);
   1329  10491      Rishi 	}
   1330  10491      Rishi 
   1331  10491      Rishi 	return (WALK_NEXT);
   1332  10491      Rishi }
   1333  10491      Rishi 
   1334  10491      Rishi /*
   1335  10491      Rishi  * It seems a shame to duplicate this code, but merging it with the link
   1336  10491      Rishi  * printing code above is more trouble than it would be worth.
   1337  10491      Rishi  */
   1338  10491      Rishi static void
   1339  10491      Rishi print_link_name(show_bridge_args_t *args, uintptr_t addr, char sep)
   1340  10491      Rishi {
   1341  10491      Rishi 	const char *name;
   1342  10491      Rishi 
   1343  10491      Rishi 	if (mdb_vread(&args->bl, sizeof (args->bl), addr) == -1) {
   1344  10491      Rishi 		mdb_warn("cannot read bridge link at %p", addr);
   1345  10491      Rishi 		return;
   1346  10491      Rishi 	}
   1347  10491      Rishi 
   1348  10491      Rishi 	if (mdb_vread(&args->mi, sizeof (args->mi),
   1349  10491      Rishi 	    (uintptr_t)args->bl.bl_mh) == -1) {
   1350  10491      Rishi 		name = "?";
   1351  10491      Rishi 	} else  {
   1352  10491      Rishi 		name = args->mi.mi_name;
   1353  10491      Rishi 	}
   1354  10491      Rishi 
   1355  10491      Rishi 	mdb_printf("%s%c", name, sep);
   1356  10491      Rishi }
   1357  10491      Rishi 
   1358  10491      Rishi static int
   1359  10491      Rishi do_bridge_fwd(uintptr_t addr, const void *data, void *ptr)
   1360  10491      Rishi {
   1361  10491      Rishi 	show_bridge_args_t *args = ptr;
   1362  10491      Rishi 	const bridge_fwd_t *bfp = data;
   1363  10491      Rishi 	char macaddr[ETHERADDRL * 3];
   1364  10491      Rishi 	int i;
   1365  10491      Rishi #define	MAX_FWD_LINKS	16
   1366  10491      Rishi 	bridge_link_t *links[MAX_FWD_LINKS];
   1367  10491      Rishi 	uint_t nlinks;
   1368  10491      Rishi 
   1369  10491      Rishi 	args->nfwd++;
   1370  10491      Rishi 
   1371  10491      Rishi 	if (!args->opt_f)
   1372  10491      Rishi 		return (WALK_NEXT);
   1373  10491      Rishi 
   1374  10491      Rishi 	if ((nlinks = bfp->bf_nlinks) > MAX_FWD_LINKS)
   1375  10491      Rishi 		nlinks = MAX_FWD_LINKS;
   1376  10491      Rishi 
   1377  10491      Rishi 	if (mdb_vread(links, sizeof (links[0]) * nlinks,
   1378  10491      Rishi 	    (uintptr_t)bfp->bf_links) == -1) {
   1379  10491      Rishi 		mdb_warn("cannot read bridge forwarding links at %p",
   1380  10491      Rishi 		    bfp->bf_links);
   1381  10491      Rishi 		return (WALK_ERR);
   1382  10491      Rishi 	}
   1383  10491      Rishi 
   1384  10491      Rishi 	mdb_mac_addr(bfp->bf_dest, ETHERADDRL, macaddr, sizeof (macaddr));
   1385  10491      Rishi 
   1386  10491      Rishi 	mdb_printf("%-?p %-17s ", addr, macaddr);
   1387  10491      Rishi 	if (bfp->bf_flags & BFF_LOCALADDR)
   1388  10491      Rishi 		mdb_printf("%-7s", "[self]");
   1389  10491      Rishi 	else
   1390  10491      Rishi 		mdb_printf("t-%-5d", args->lbolt - bfp->bf_lastheard);
   1391  10491      Rishi 	mdb_printf(" %-7u ", bfp->bf_refs);
   1392  10491      Rishi 
   1393  10491      Rishi 	if (bfp->bf_trill_nick != 0) {
   1394  10491      Rishi 		mdb_printf("%d\n", bfp->bf_trill_nick);
   1395  10491      Rishi 	} else {
   1396  10491      Rishi 		for (i = 0; i < bfp->bf_nlinks; i++) {
   1397  10491      Rishi 			print_link_name(args, (uintptr_t)links[i],
   1398  10491      Rishi 			    i == bfp->bf_nlinks - 1 ? '\n' : ' ');
   1399  10491      Rishi 		}
   1400  10491      Rishi 	}
   1401  10491      Rishi 
   1402  10491      Rishi 	return (WALK_NEXT);
   1403  10491      Rishi }
   1404  10491      Rishi 
   1405  10491      Rishi static int
   1406  10491      Rishi do_show_bridge(uintptr_t addr, const void *data, void *ptr)
   1407  10491      Rishi {
   1408  10491      Rishi 	show_bridge_args_t *args = ptr;
   1409  10491      Rishi 	bridge_inst_t bi;
   1410  10491      Rishi 	const bridge_inst_t *bip;
   1411  10491      Rishi 	trill_node_t tn;
   1412  10491      Rishi 	trill_sock_t tsp;
   1413  10491      Rishi 	trill_nickinfo_t tni;
   1414  10491      Rishi 	char bname[MAXLINKNAMELEN];
   1415  10491      Rishi 	char macaddr[ETHERADDRL * 3];
   1416  10491      Rishi 	char *cp;
   1417  10491      Rishi 	uint_t nnicks;
   1418  10491      Rishi 	int i;
   1419  10491      Rishi 
   1420  10491      Rishi 	if (data != NULL) {
   1421  10491      Rishi 		bip = data;
   1422  10491      Rishi 	} else {
   1423  10491      Rishi 		if (mdb_vread(&bi, sizeof (bi), addr) == -1) {
   1424  10491      Rishi 			mdb_warn("cannot read bridge instance at %p", addr);
   1425  10491      Rishi 			return (WALK_ERR);
   1426  10491      Rishi 		}
   1427  10491      Rishi 		bip = &bi;
   1428  10491      Rishi 	}
   1429  10491      Rishi 
   1430  10491      Rishi 	(void) strncpy(bname, bip->bi_name, sizeof (bname) - 1);
   1431  10491      Rishi 	bname[MAXLINKNAMELEN - 1] = '\0';
   1432  10491      Rishi 	cp = bname + strlen(bname);
   1433  10491      Rishi 	if (cp > bname && cp[-1] == '0')
   1434  10491      Rishi 		cp[-1] = '\0';
   1435  10491      Rishi 
   1436  10491      Rishi 	if (args->name != NULL && strcmp(args->name, bname) != 0)
   1437  10491      Rishi 		return (WALK_NEXT);
   1438  10491      Rishi 
   1439  10491      Rishi 	args->found = B_TRUE;
   1440  10491      Rishi 	args->nlinks = args->nfwd = 0;
   1441  10491      Rishi 
   1442  10491      Rishi 	if (args->opt_l) {
   1443  10491      Rishi 		mdb_printf("%-?s %-16s %-17s %3s %-4s ", "ADDR", "LINK",
   1444  10491      Rishi 		    "MAC-ADDR", "FLG", "PVID");
   1445  10491      Rishi 		if (bip->bi_trilldata == NULL)
   1446  10491      Rishi 			mdb_printf("%-5s %s\n", "STATE", "VLANS");
   1447  10491      Rishi 		else
   1448  10491      Rishi 			mdb_printf("%s\n", "FWD-VLANS");
   1449  10491      Rishi 	}
   1450  10491      Rishi 
   1451  10491      Rishi 	if (!args->opt_f && !args->opt_t &&
   1452  10491      Rishi 	    mdb_pwalk("list", do_bridge_links, args,
   1453  10491      Rishi 	    addr + offsetof(bridge_inst_t, bi_links)) != DCMD_OK)
   1454  10491      Rishi 		return (WALK_ERR);
   1455  10491      Rishi 
   1456  10491      Rishi 	if (args->opt_f)
   1457  10491      Rishi 		mdb_printf("%-?s %-17s %-7s %-7s %s\n", "ADDR", "DEST", "TIME",
   1458  10491      Rishi 		    "REFS", "OUTPUT");
   1459  10491      Rishi 
   1460  10491      Rishi 	if (!args->opt_l && !args->opt_t &&
   1461  10491      Rishi 	    mdb_pwalk("avl", do_bridge_fwd, args,
   1462  10491      Rishi 	    addr + offsetof(bridge_inst_t, bi_fwd)) != DCMD_OK)
   1463  10491      Rishi 		return (WALK_ERR);
   1464  10491      Rishi 
   1465  10491      Rishi 	nnicks = 0;
   1466  10491      Rishi 	if (bip->bi_trilldata != NULL && !args->opt_l && !args->opt_f) {
   1467  10491      Rishi 		if (mdb_vread(&args->ti, sizeof (args->ti),
   1468  10491      Rishi 		    (uintptr_t)bip->bi_trilldata) == -1) {
   1469  10491      Rishi 			mdb_warn("cannot read trill instance at %p",
   1470  10491      Rishi 			    bip->bi_trilldata);
   1471  10491      Rishi 			return (WALK_ERR);
   1472  10491      Rishi 		}
   1473  10491      Rishi 		if (args->opt_t)
   1474  10491      Rishi 			mdb_printf("%-?s %-5s %-17s %s\n", "ADDR",
   1475  10491      Rishi 			    "NICK", "NEXT-HOP", "LINK");
   1476  10491      Rishi 		for (i = 0; i < RBRIDGE_NICKNAME_MAX; i++) {
   1477  10491      Rishi 			if (args->ti.ti_nodes[i] == NULL)
   1478  10491      Rishi 				continue;
   1479  10491      Rishi 			if (args->opt_t) {
   1480  10491      Rishi 				if (mdb_vread(&tn, sizeof (tn),
   1481  10491      Rishi 				    (uintptr_t)args->ti.ti_nodes[i]) == -1) {
   1482  10491      Rishi 					mdb_warn("cannot read trill node %d at "
   1483  10491      Rishi 					    "%p", i, args->ti.ti_nodes[i]);
   1484  10491      Rishi 					return (WALK_ERR);
   1485  10491      Rishi 				}
   1486  10491      Rishi 				if (mdb_vread(&tni, sizeof (tni),
   1487  10491      Rishi 				    (uintptr_t)tn.tn_ni) == -1) {
   1488  10491      Rishi 					mdb_warn("cannot read trill node info "
   1489  10491      Rishi 					    "%d at %p", i, tn.tn_ni);
   1490  10491      Rishi 					return (WALK_ERR);
   1491  10491      Rishi 				}
   1492  10491      Rishi 				mdb_mac_addr(tni.tni_adjsnpa, ETHERADDRL,
   1493  10491      Rishi 				    macaddr, sizeof (macaddr));
   1494  10491      Rishi 				if (tni.tni_nick == args->ti.ti_nick) {
   1495  10491      Rishi 					(void) strcpy(macaddr, "[self]");
   1496  10491      Rishi 				}
   1497  10491      Rishi 				mdb_printf("%-?p %-5u %-17s ",
   1498  10491      Rishi 				    args->ti.ti_nodes[i], tni.tni_nick,
   1499  10491      Rishi 				    macaddr);
   1500  10491      Rishi 				if (tn.tn_tsp != NULL) {
   1501  10491      Rishi 					if (mdb_vread(&tsp, sizeof (tsp),
   1502  10491      Rishi 					    (uintptr_t)tn.tn_tsp) == -1) {
   1503  10491      Rishi 						mdb_warn("cannot read trill "
   1504  10491      Rishi 						    "socket info at %p",
   1505  10491      Rishi 						    tn.tn_tsp);
   1506  10491      Rishi 						return (WALK_ERR);
   1507  10491      Rishi 					}
   1508  10491      Rishi 					if (tsp.ts_link != NULL) {
   1509  10491      Rishi 						print_link_name(args,
   1510  10491      Rishi 						    (uintptr_t)tsp.ts_link,
   1511  10491      Rishi 						    '\n');
   1512  10491      Rishi 						continue;
   1513  10491      Rishi 					}
   1514  10491      Rishi 				}
   1515  10491      Rishi 				mdb_printf("--\n");
   1516  10491      Rishi 			} else {
   1517  10491      Rishi 				nnicks++;
   1518  10491      Rishi 			}
   1519  10491      Rishi 		}
   1520  10491      Rishi 	} else {
   1521  10491      Rishi 		if (args->opt_t)
   1522  10491      Rishi 			mdb_printf("bridge is not running TRILL\n");
   1523  10491      Rishi 	}
   1524  10491      Rishi 
   1525  10491      Rishi 	if (!args->opt_l && !args->opt_f && !args->opt_t) {
   1526  10491      Rishi 		mdb_printf("%-?p %-7s %-16s %-7u %-7u", addr,
   1527  10491      Rishi 		    bip->bi_trilldata == NULL ? "stp" : "trill", bname,
   1528  10491      Rishi 		    args->nlinks, args->nfwd);
   1529  10491      Rishi 		if (bip->bi_trilldata != NULL)
   1530  10491      Rishi 			mdb_printf(" %-7u %u\n", nnicks, args->ti.ti_nick);
   1531  10491      Rishi 		else
   1532  10491      Rishi 			mdb_printf(" %-7s %s\n", "--", "--");
   1533  10491      Rishi 	}
   1534  10491      Rishi 	return (WALK_NEXT);
   1535  10491      Rishi }
   1536  10491      Rishi 
   1537  10491      Rishi static int
   1538  10491      Rishi dladm_show_bridge(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
   1539  10491      Rishi {
   1540  10491      Rishi 	show_bridge_args_t *args;
   1541  10491      Rishi 	GElf_Sym sym;
   1542  10491      Rishi 	int i;
   1543  10491      Rishi 
   1544  10491      Rishi 	args = mdb_zalloc(sizeof (*args), UM_SLEEP);
   1545  10491      Rishi 
   1546  10491      Rishi 	i = mdb_getopts(argc, argv,
   1547  10491      Rishi 	    'l', MDB_OPT_SETBITS, 1, &args->opt_l,
   1548  10491      Rishi 	    'f', MDB_OPT_SETBITS, 1, &args->opt_f,
   1549  10491      Rishi 	    't', MDB_OPT_SETBITS, 1, &args->opt_t,
   1550  10491      Rishi 	    NULL);
   1551  10491      Rishi 
   1552  10491      Rishi 	argc -= i;
   1553  10491      Rishi 	argv += i;
   1554  10491      Rishi 
   1555  10491      Rishi 	if (argc > 1 || (argc == 1 && argv[0].a_type != MDB_TYPE_STRING)) {
   1556  10491      Rishi 		mdb_free(args, sizeof (*args));
   1557  10491      Rishi 		return (DCMD_USAGE);
   1558  10491      Rishi 	}
   1559  10491      Rishi 	if (argc == 1)
   1560  10491      Rishi 		args->name = argv[0].a_un.a_str;
   1561  10491      Rishi 
   1562  11066     rafael 	if ((args->lbolt = mdb_get_lbolt()) == -1) {
   1563  10491      Rishi 		mdb_warn("failed to read lbolt");
   1564  10491      Rishi 		goto err;
   1565  10491      Rishi 	}
   1566  10491      Rishi 
   1567  10491      Rishi 	if (flags & DCMD_ADDRSPEC) {
   1568  10491      Rishi 		if (args->name != NULL) {
   1569  10491      Rishi 			mdb_printf("bridge name and address are mutually "
   1570  10491      Rishi 			    "exclusive\n");
   1571  10491      Rishi 			goto err;
   1572  10491      Rishi 		}
   1573  10491      Rishi 		if (!args->opt_l && !args->opt_f && !args->opt_t)
   1574  10491      Rishi 			mdb_printf("%-?s %-7s %-16s %-7s %-7s\n", "ADDR",
   1575  10491      Rishi 			    "PROTECT", "NAME", "NLINKS", "NFWD");
   1576  10491      Rishi 		if (do_show_bridge(addr, NULL, args) != WALK_NEXT)
   1577  10491      Rishi 			goto err;
   1578  10491      Rishi 		mdb_free(args, sizeof (*args));
   1579  10491      Rishi 		return (DCMD_OK);
   1580  10491      Rishi 	} else {
   1581  10491      Rishi 		if ((args->opt_l || args->opt_f || args->opt_t) &&
   1582  10491      Rishi 		    args->name == NULL) {
   1583  10491      Rishi 			mdb_printf("need bridge name or address with -[lft]\n");
   1584  10491      Rishi 			goto err;
   1585  10491      Rishi 		}
   1586  10491      Rishi 		if (mdb_lookup_by_obj("bridge", "inst_list", &sym) == -1) {
   1587  10491      Rishi 			mdb_warn("failed to find 'bridge`inst_list'");
   1588  10491      Rishi 			goto err;
   1589  10491      Rishi 		}
   1590  10491      Rishi 		if (!args->opt_l && !args->opt_f && !args->opt_t)
   1591  10491      Rishi 			mdb_printf("%-?s %-7s %-16s %-7s %-7s %-7s %s\n",
   1592  10491      Rishi 			    "ADDR", "PROTECT", "NAME", "NLINKS", "NFWD",
   1593  10491      Rishi 			    "NNICKS", "NICK");
   1594  10491      Rishi 		if (mdb_pwalk("list", do_show_bridge, args,
   1595  10491      Rishi 		    (uintptr_t)sym.st_value) != DCMD_OK)
   1596  10491      Rishi 			goto err;
   1597  10491      Rishi 		if (!args->found && args->name != NULL) {
   1598  10491      Rishi 			mdb_printf("bridge instance %s not found\n",
   1599  10491      Rishi 			    args->name);
   1600  10491      Rishi 			goto err;
   1601  10491      Rishi 		}
   1602  10491      Rishi 		mdb_free(args, sizeof (*args));
   1603  10491      Rishi 		return (DCMD_OK);
   1604  10491      Rishi 	}
   1605  10491      Rishi 
   1606  10491      Rishi err:
   1607  10491      Rishi 	mdb_free(args, sizeof (*args));
   1608  10491      Rishi 	return (DCMD_ERR);
   1609  10491      Rishi }
   1610  10491      Rishi 
   1611  10491      Rishi /*
   1612  10491      Rishi  * Support for the "::dladm" dcmd
   1613  10491      Rishi  */
   1614  10491      Rishi int
   1615  10491      Rishi dladm(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
   1616  10491      Rishi {
   1617  10491      Rishi 	if (argc < 1 || argv[0].a_type != MDB_TYPE_STRING)
   1618  10491      Rishi 		return (DCMD_USAGE);
   1619  10491      Rishi 
   1620  10491      Rishi 	/*
   1621  10491      Rishi 	 * This could be a bit more elaborate, once we support more of the
   1622  10491      Rishi 	 * dladm show-* subcommands.
   1623  10491      Rishi 	 */
   1624  10491      Rishi 	argc--;
   1625  10491      Rishi 	argv++;
   1626  10491      Rishi 	if (strcmp(argv[-1].a_un.a_str, "show-bridge") == 0)
   1627  10491      Rishi 		return (dladm_show_bridge(addr, flags, argc, argv));
   1628  10491      Rishi 
   1629  10491      Rishi 	return (DCMD_USAGE);
   1630  10491      Rishi }
   1631  10491      Rishi 
   1632  10491      Rishi void
   1633  10491      Rishi dladm_help(void)
   1634  10491      Rishi {
   1635  10491      Rishi 	mdb_printf("Subcommands:\n"
   1636  10491      Rishi 	    "  show-bridge [-flt] [<name>]\n"
   1637  10491      Rishi 	    "\t     Show bridge information; -l for links and -f for "
   1638  10491      Rishi 	    "forwarding\n"
   1639  10491      Rishi 	    "\t     entries, and -t for TRILL nicknames.  Address is required "
   1640  10491      Rishi 	    "if name\n"
   1641  10491      Rishi 	    "\t     is not specified.\n");
   1642  10491      Rishi }
   1643