1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  * Copyright (c) 2012, Joyent, Inc.  All rights reserved.
25  */
26 
27 #include <mdb/mdb_modapi.h>
28 #include <mdb/mdb_ks.h>
29 #include <mdb/mdb_ctf.h>
30 #include <sys/types.h>
31 #include <sys/netstack.h>
32 
33 int
netstack_walk_init(mdb_walk_state_t * wsp)34 netstack_walk_init(mdb_walk_state_t *wsp)
35 {
36 	GElf_Sym sym;
37 	uintptr_t addr;
38 
39 	if (mdb_lookup_by_name("netstack_head", &sym) == -1) {
40 		mdb_warn("couldn't find netstack_head");
41 		return (WALK_ERR);
42 	}
43 	addr = (uintptr_t)sym.st_value;
44 
45 	if (mdb_vread(&wsp->walk_addr, sizeof (wsp->walk_addr),	addr) == -1) {
46 		mdb_warn("failed to read address of initial netstack "
47 		    "at %p", addr);
48 		return (WALK_ERR);
49 	}
50 	return (WALK_NEXT);
51 }
52 
53 int
netstack_walk_step(mdb_walk_state_t * wsp)54 netstack_walk_step(mdb_walk_state_t *wsp)
55 {
56 	int status;
57 	netstack_t nss;
58 
59 	if (wsp->walk_addr == 0)
60 		return (WALK_DONE);
61 
62 	if (mdb_vread(&nss, sizeof (netstack_t), wsp->walk_addr) == -1) {
63 		mdb_warn("failed to read netstack at %p", wsp->walk_addr);
64 		return (WALK_ERR);
65 	}
66 
67 	status = wsp->walk_callback(wsp->walk_addr, &nss,
68 	    wsp->walk_cbdata);
69 
70 	if (status != WALK_NEXT)
71 		return (status);
72 
73 	wsp->walk_addr = (uintptr_t)nss.netstack_next;
74 	return (status);
75 }
76 
77 /*ARGSUSED*/
78 int
netstack(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)79 netstack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
80 {
81 	netstack_t nss;
82 	uint_t quiet = FALSE;
83 	uint_t verbose = FALSE;
84 
85 	if (!(flags & DCMD_ADDRSPEC)) {
86 		if (mdb_walk_dcmd("genunix`netstack", "genunix`netstack",
87 		    argc, argv) == -1) {
88 			mdb_warn("failed to walk netstack");
89 			return (DCMD_ERR);
90 		}
91 		return (DCMD_OK);
92 	}
93 	if (mdb_getopts(argc, argv,
94 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
95 	    'q', MDB_OPT_SETBITS, TRUE, &quiet,
96 	    NULL) != argc)
97 		return (DCMD_USAGE);
98 
99 	if (DCMD_HDRSPEC(flags) && !quiet) {
100 		mdb_printf("%?s %-7s %6s\n",
101 		    "ADDR", "STACKID", "FLAGS");
102 	}
103 
104 	if (mdb_vread(&nss, sizeof (nss), addr) == -1) {
105 		mdb_warn("couldn't read netstack at %p", addr);
106 		return (DCMD_ERR);
107 	}
108 
109 	/*
110 	 * Options are specified for filtering, so If any option is specified on
111 	 * the command line, just print address and exit.
112 	 */
113 	if (quiet) {
114 		mdb_printf("%0?p\n", addr);
115 		return (DCMD_OK);
116 	}
117 
118 	mdb_printf("%0?p %6d    %06x\n",
119 	    addr, nss.netstack_stackid, nss.netstack_flags);
120 
121 	return (DCMD_OK);
122 }
123 
124 static int
netstackid_lookup_cb(uintptr_t addr,const netstack_t * ns,void * arg)125 netstackid_lookup_cb(uintptr_t addr, const netstack_t *ns, void *arg)
126 {
127 	netstackid_t nid = *(uintptr_t *)arg;
128 	if (ns->netstack_stackid == nid)
129 		mdb_printf("%p\n", addr);
130 
131 	return (WALK_NEXT);
132 }
133 
134 /*ARGSUSED*/
135 int
netstackid2netstack(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)136 netstackid2netstack(uintptr_t addr, uint_t flags, int argc,
137     const mdb_arg_t *argv)
138 {
139 	if (!(flags & DCMD_ADDRSPEC) || argc != 0)
140 		return (DCMD_USAGE);
141 
142 	if (mdb_walk("netstack", (mdb_walk_cb_t)netstackid_lookup_cb, &addr) ==
143 	    -1) {
144 		mdb_warn("failed to walk zone");
145 		return (DCMD_ERR);
146 	}
147 
148 	return (DCMD_OK);
149 }
150