30 #include <sys/tihdr.h>
31 #include <inet/led.h>
32 #include <inet/common.h>
33 #include <netinet/in.h>
34 #include <netinet/ip6.h>
35 #include <netinet/icmp6.h>
36 #include <inet/ip.h>
37 #include <inet/ip6.h>
38 #include <inet/ipclassifier.h>
39 #include <inet/tcp.h>
40 #include <sys/stream.h>
41 #include <sys/vfs.h>
42 #include <sys/stropts.h>
43 #include <sys/tpicommon.h>
44 #include <sys/socket.h>
45 #include <sys/socketvar.h>
46 #include <sys/cred_impl.h>
47 #include <inet/udp_impl.h>
48 #include <inet/rawip_impl.h>
49 #include <inet/mi.h>
50 #include <fs/sockfs/socktpi_impl.h>
51 #include <net/bridge_impl.h>
52 #include <io/trill_impl.h>
53 #include <sys/mac_impl.h>
54
55 #define ADDR_V6_WIDTH 23
56 #define ADDR_V4_WIDTH 15
57
58 #define NETSTAT_ALL 0x01
59 #define NETSTAT_VERBOSE 0x02
60 #define NETSTAT_ROUTE 0x04
61 #define NETSTAT_V4 0x08
62 #define NETSTAT_V6 0x10
63 #define NETSTAT_UNIX 0x20
64
65 #define NETSTAT_FIRST 0x80000000u
66
67 typedef struct netstat_cb_data_s {
68 uint_t opts;
69 conn_t conn;
125 mdb_warn("can't walk 'netstack'");
126 return (WALK_ERR);
127 }
128 return (WALK_NEXT);
129 }
130
131 int
132 udp_stacks_walk_step(mdb_walk_state_t *wsp)
133 {
134 uintptr_t kaddr;
135 netstack_t nss;
136
137 if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
138 mdb_warn("can't read netstack at %p", wsp->walk_addr);
139 return (WALK_ERR);
140 }
141 kaddr = (uintptr_t)nss.netstack_modules[NS_UDP];
142 return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
143 }
144
145 /*
146 * Print an IPv4 address and port number in a compact and easy to read format
147 * The arguments are in network byte order
148 */
149 static void
150 net_ipv4addrport_pr(const in6_addr_t *nipv6addr, in_port_t nport)
151 {
152 uint32_t naddr = V4_PART_OF_V6((*nipv6addr));
153
154 mdb_nhconvert(&nport, &nport, sizeof (nport));
155 mdb_printf("%*I.%-5hu", ADDR_V4_WIDTH, naddr, nport);
156 }
157
158 /*
159 * Print an IPv6 address and port number in a compact and easy to read format
160 * The arguments are in network byte order
161 */
162 static void
163 net_ipv6addrport_pr(const in6_addr_t *naddr, in_port_t nport)
164 {
190 net_udp_active(const udp_t *udp)
191 {
192 return ((udp->udp_state == TS_IDLE) ||
193 (udp->udp_state == TS_DATA_XFER));
194 }
195
196 static int
197 net_udp_ipv4(const udp_t *udp)
198 {
199 return ((udp->udp_connp->conn_ipversion == IPV4_VERSION) ||
200 (IN6_IS_ADDR_UNSPECIFIED(&udp->udp_connp->conn_laddr_v6) &&
201 (udp->udp_state <= TS_IDLE)));
202 }
203
204 static int
205 net_udp_ipv6(const udp_t *udp)
206 {
207 return (udp->udp_connp->conn_ipversion == IPV6_VERSION);
208 }
209
210 int
211 sonode_walk_init(mdb_walk_state_t *wsp)
212 {
213 if (wsp->walk_addr == NULL) {
214 GElf_Sym sym;
215 struct socklist *slp;
216
217 if (mdb_lookup_by_obj("sockfs", "socklist", &sym) == -1) {
218 mdb_warn("failed to lookup sockfs`socklist");
219 return (WALK_ERR);
220 }
221
222 slp = (struct socklist *)(uintptr_t)sym.st_value;
223
224 if (mdb_vread(&wsp->walk_addr, sizeof (wsp->walk_addr),
225 (uintptr_t)&slp->sl_list) == -1) {
226 mdb_warn("failed to read address of initial sonode "
227 "at %p", &slp->sl_list);
228 return (WALK_ERR);
229 }
728 state = "CONNECTED";
729 else
730 state = "UNKNOWN";
731
732 mdb_printf("%0?p %10s ", (uintptr_t)connp->conn_icmp, state);
733 if (af == AF_INET) {
734 net_ipv4addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
735 mdb_printf(" ");
736 net_ipv4addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
737 } else if (af == AF_INET6) {
738 net_ipv6addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
739 mdb_printf(" ");
740 net_ipv6addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
741 }
742 mdb_printf(" %5i", ns_to_stackid((uintptr_t)connp->conn_netstack));
743 mdb_printf(" %4i\n", connp->conn_zoneid);
744
745 return (WALK_NEXT);
746 }
747
748 /*
749 * print the address of a unix domain socket
750 *
751 * so is the address of a AF_UNIX struct sonode in mdb's address space
752 * soa is the address of the struct soaddr to print
753 *
754 * returns 0 on success, -1 otherwise
755 */
756 static int
757 netstat_unix_name_pr(const struct sotpi_sonode *st, const struct soaddr *soa)
758 {
759 const struct sonode *so = &st->st_sonode;
760 const char none[] = " (none)";
761
762 if ((so->so_state & SS_ISBOUND) && (soa->soa_len != 0)) {
763 if (st->st_info.sti_faddr_noxlate) {
764 mdb_printf("%-14s ", " (socketpair)");
765 } else {
766 if (soa->soa_len > sizeof (sa_family_t)) {
767 char addr[MAXPATHLEN + 1];
1199 if ((optP == NULL) || (strcmp("tcp", optP) == 0)) {
1200 status = netstat_print_common("tcp_conn_cache", IPPROTO_TCP,
1201 netstat_tcp_cb, cbdata);
1202 if (status != DCMD_OK)
1203 goto out;
1204 }
1205
1206 if ((optP == NULL) || (strcmp("udp", optP) == 0)) {
1207 status = netstat_print_common("udp_conn_cache", IPPROTO_UDP,
1208 netstat_udp_cb, cbdata);
1209 if (status != DCMD_OK)
1210 goto out;
1211 }
1212
1213 if ((optP == NULL) || (strcmp("icmp", optP) == 0)) {
1214 status = netstat_print_common("rawip_conn_cache", IPPROTO_ICMP,
1215 netstat_icmp_cb, cbdata);
1216 if (status != DCMD_OK)
1217 goto out;
1218 }
1219 out:
1220 mdb_free(cbdata, sizeof (netstat_cb_data_t));
1221 return (status);
1222 }
1223
1224 /*
1225 * "::dladm show-bridge" support
1226 */
1227 typedef struct {
1228 uint_t opt_l;
1229 uint_t opt_f;
1230 uint_t opt_t;
1231 const char *name;
1232 clock_t lbolt;
1233 boolean_t found;
1234 uint_t nlinks;
1235 uint_t nfwd;
1236
1237 /*
1238 * These structures are kept inside the 'args' for allocation reasons.
|
30 #include <sys/tihdr.h>
31 #include <inet/led.h>
32 #include <inet/common.h>
33 #include <netinet/in.h>
34 #include <netinet/ip6.h>
35 #include <netinet/icmp6.h>
36 #include <inet/ip.h>
37 #include <inet/ip6.h>
38 #include <inet/ipclassifier.h>
39 #include <inet/tcp.h>
40 #include <sys/stream.h>
41 #include <sys/vfs.h>
42 #include <sys/stropts.h>
43 #include <sys/tpicommon.h>
44 #include <sys/socket.h>
45 #include <sys/socketvar.h>
46 #include <sys/cred_impl.h>
47 #include <inet/udp_impl.h>
48 #include <inet/rawip_impl.h>
49 #include <inet/mi.h>
50 #include <inet/dccp_impl.h>
51 #include <fs/sockfs/socktpi_impl.h>
52 #include <net/bridge_impl.h>
53 #include <io/trill_impl.h>
54 #include <sys/mac_impl.h>
55
56 #define ADDR_V6_WIDTH 23
57 #define ADDR_V4_WIDTH 15
58
59 #define NETSTAT_ALL 0x01
60 #define NETSTAT_VERBOSE 0x02
61 #define NETSTAT_ROUTE 0x04
62 #define NETSTAT_V4 0x08
63 #define NETSTAT_V6 0x10
64 #define NETSTAT_UNIX 0x20
65
66 #define NETSTAT_FIRST 0x80000000u
67
68 typedef struct netstat_cb_data_s {
69 uint_t opts;
70 conn_t conn;
126 mdb_warn("can't walk 'netstack'");
127 return (WALK_ERR);
128 }
129 return (WALK_NEXT);
130 }
131
132 int
133 udp_stacks_walk_step(mdb_walk_state_t *wsp)
134 {
135 uintptr_t kaddr;
136 netstack_t nss;
137
138 if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
139 mdb_warn("can't read netstack at %p", wsp->walk_addr);
140 return (WALK_ERR);
141 }
142 kaddr = (uintptr_t)nss.netstack_modules[NS_UDP];
143 return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
144 }
145
146 int
147 dccp_stacks_walk_init(mdb_walk_state_t *wsp)
148 {
149 if (mdb_layered_walk("netstack", wsp) == -1) {
150 mdb_warn("can't walk 'netstack'");
151 return (WALK_ERR);
152 }
153 return (WALK_NEXT);
154 }
155
156 int
157 dccp_stacks_walk_step(mdb_walk_state_t *wsp)
158 {
159 uintptr_t kaddr;
160 netstack_t nss;
161
162 if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
163 mdb_warn("can't read netstack at %p", wsp->walk_addr);
164 return (WALK_ERR);
165 }
166 kaddr = (uintptr_t)nss.netstack_modules[NS_DCCP];
167 return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
168 }
169
170 /*
171 * Print an IPv4 address and port number in a compact and easy to read format
172 * The arguments are in network byte order
173 */
174 static void
175 net_ipv4addrport_pr(const in6_addr_t *nipv6addr, in_port_t nport)
176 {
177 uint32_t naddr = V4_PART_OF_V6((*nipv6addr));
178
179 mdb_nhconvert(&nport, &nport, sizeof (nport));
180 mdb_printf("%*I.%-5hu", ADDR_V4_WIDTH, naddr, nport);
181 }
182
183 /*
184 * Print an IPv6 address and port number in a compact and easy to read format
185 * The arguments are in network byte order
186 */
187 static void
188 net_ipv6addrport_pr(const in6_addr_t *naddr, in_port_t nport)
189 {
215 net_udp_active(const udp_t *udp)
216 {
217 return ((udp->udp_state == TS_IDLE) ||
218 (udp->udp_state == TS_DATA_XFER));
219 }
220
221 static int
222 net_udp_ipv4(const udp_t *udp)
223 {
224 return ((udp->udp_connp->conn_ipversion == IPV4_VERSION) ||
225 (IN6_IS_ADDR_UNSPECIFIED(&udp->udp_connp->conn_laddr_v6) &&
226 (udp->udp_state <= TS_IDLE)));
227 }
228
229 static int
230 net_udp_ipv6(const udp_t *udp)
231 {
232 return (udp->udp_connp->conn_ipversion == IPV6_VERSION);
233 }
234
235 static int
236 net_dccp_active(const dccp_t *dccp)
237 {
238 return ((dccp->dccp_state == TS_IDLE) ||
239 (dccp->dccp_state == TS_DATA_XFER));
240 }
241
242 static int
243 net_dccp_ipv4(const dccp_t *dccp)
244 {
245 return ((dccp->dccp_connp->conn_ipversion == IPV4_VERSION) ||
246 (IN6_IS_ADDR_UNSPECIFIED(&dccp->dccp_connp->conn_laddr_v6) &&
247 (dccp->dccp_state <= DCCPS_LISTEN)));
248 }
249
250 static int
251 net_dccp_ipv6(const dccp_t *dccp)
252 {
253 return (dccp->dccp_connp->conn_ipversion == IPV6_VERSION);
254 }
255
256 int
257 sonode_walk_init(mdb_walk_state_t *wsp)
258 {
259 if (wsp->walk_addr == NULL) {
260 GElf_Sym sym;
261 struct socklist *slp;
262
263 if (mdb_lookup_by_obj("sockfs", "socklist", &sym) == -1) {
264 mdb_warn("failed to lookup sockfs`socklist");
265 return (WALK_ERR);
266 }
267
268 slp = (struct socklist *)(uintptr_t)sym.st_value;
269
270 if (mdb_vread(&wsp->walk_addr, sizeof (wsp->walk_addr),
271 (uintptr_t)&slp->sl_list) == -1) {
272 mdb_warn("failed to read address of initial sonode "
273 "at %p", &slp->sl_list);
274 return (WALK_ERR);
275 }
774 state = "CONNECTED";
775 else
776 state = "UNKNOWN";
777
778 mdb_printf("%0?p %10s ", (uintptr_t)connp->conn_icmp, state);
779 if (af == AF_INET) {
780 net_ipv4addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
781 mdb_printf(" ");
782 net_ipv4addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
783 } else if (af == AF_INET6) {
784 net_ipv6addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
785 mdb_printf(" ");
786 net_ipv6addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
787 }
788 mdb_printf(" %5i", ns_to_stackid((uintptr_t)connp->conn_netstack));
789 mdb_printf(" %4i\n", connp->conn_zoneid);
790
791 return (WALK_NEXT);
792 }
793
794 static void
795 netstat_dccp_verbose_pr(const dccp_t *dccp)
796 {
797 /* XXX:DCCP
798 mdb_printf(" %5i %08x %08x %5i %08x %08x %5li %5i\n",
799 tcp->tcp_swnd, tcp->tcp_snxt, tcp->tcp_suna, tcp->tcp_rwnd,
800 tcp->tcp_rack, tcp->tcp_rnxt, tcp->tcp_rto, tcp->tcp_mss);
801 */
802 }
803
804 /*ARGSUSED*/
805 static int
806 netstat_dccp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
807 {
808 netstat_cb_data_t *ncb = cb_data;
809 uint_t opts = ncb->opts;
810 int af = ncb->af;
811 uintptr_t dccp_kaddr;
812 conn_t *connp = &ncb->conn;
813 dccp_t dccps, *dccp;
814
815 if (mdb_vread(connp, sizeof (conn_t), kaddr) == -1) {
816 mdb_warn("failed to read conn_t at %p", kaddr);
817 return (WALK_ERR);
818 }
819
820 dccp_kaddr = (uintptr_t)connp->conn_dccp;
821 if (mdb_vread(&dccps, sizeof (dccp_t), dccp_kaddr) == -1) {
822 mdb_warn("failed to read tcp_t at %p", dccp_kaddr);
823 return (WALK_ERR);
824 }
825
826 dccp = &dccps;
827 connp->conn_dccp = dccp;
828 dccp->dccp_connp = connp;
829
830 if (!((opts & NETSTAT_ALL) || net_dccp_active(dccp)) ||
831 (af == AF_INET && !net_dccp_ipv4(dccp)) ||
832 (af == AF_INET6 && !net_dccp_ipv6(dccp))) {
833 return (WALK_NEXT);
834 }
835
836 mdb_printf("%0?p %2i ", dccp_kaddr, dccp->dccp_state);
837 if (af == AF_INET) {
838 net_ipv4addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
839 mdb_printf(" ");
840 net_ipv4addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
841 } else if (af == AF_INET6) {
842 net_ipv6addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
843 mdb_printf(" ");
844 net_ipv6addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
845 }
846 mdb_printf(" %5i", ns_to_stackid((uintptr_t)connp->conn_netstack));
847 mdb_printf(" %4i\n", connp->conn_zoneid);
848 if (opts & NETSTAT_VERBOSE)
849 netstat_dccp_verbose_pr(dccp);
850
851 return (WALK_NEXT);
852 }
853
854 /*
855 * print the address of a unix domain socket
856 *
857 * so is the address of a AF_UNIX struct sonode in mdb's address space
858 * soa is the address of the struct soaddr to print
859 *
860 * returns 0 on success, -1 otherwise
861 */
862 static int
863 netstat_unix_name_pr(const struct sotpi_sonode *st, const struct soaddr *soa)
864 {
865 const struct sonode *so = &st->st_sonode;
866 const char none[] = " (none)";
867
868 if ((so->so_state & SS_ISBOUND) && (soa->soa_len != 0)) {
869 if (st->st_info.sti_faddr_noxlate) {
870 mdb_printf("%-14s ", " (socketpair)");
871 } else {
872 if (soa->soa_len > sizeof (sa_family_t)) {
873 char addr[MAXPATHLEN + 1];
1305 if ((optP == NULL) || (strcmp("tcp", optP) == 0)) {
1306 status = netstat_print_common("tcp_conn_cache", IPPROTO_TCP,
1307 netstat_tcp_cb, cbdata);
1308 if (status != DCMD_OK)
1309 goto out;
1310 }
1311
1312 if ((optP == NULL) || (strcmp("udp", optP) == 0)) {
1313 status = netstat_print_common("udp_conn_cache", IPPROTO_UDP,
1314 netstat_udp_cb, cbdata);
1315 if (status != DCMD_OK)
1316 goto out;
1317 }
1318
1319 if ((optP == NULL) || (strcmp("icmp", optP) == 0)) {
1320 status = netstat_print_common("rawip_conn_cache", IPPROTO_ICMP,
1321 netstat_icmp_cb, cbdata);
1322 if (status != DCMD_OK)
1323 goto out;
1324 }
1325
1326 if ((optP == NULL) || (strcmp("dccp", optP) == 0)) {
1327 status = netstat_print_common("dccp_conn_cache", IPPROTO_DCCP,
1328 netstat_dccp_cb, cbdata);
1329 if (status != DCMD_OK)
1330 goto out;
1331 }
1332 out:
1333 mdb_free(cbdata, sizeof (netstat_cb_data_t));
1334 return (status);
1335 }
1336
1337 /*
1338 * "::dladm show-bridge" support
1339 */
1340 typedef struct {
1341 uint_t opt_l;
1342 uint_t opt_f;
1343 uint_t opt_t;
1344 const char *name;
1345 clock_t lbolt;
1346 boolean_t found;
1347 uint_t nlinks;
1348 uint_t nfwd;
1349
1350 /*
1351 * These structures are kept inside the 'args' for allocation reasons.
|