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 (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
  23  */
  24 
  25 #include <sys/types.h>
  26 #include <sys/stropts.h>
  27 #include <sys/stream.h>
  28 #include <sys/socket.h>
  29 #include <sys/avl_impl.h>
  30 #include <net/if_types.h>
  31 #include <net/if.h>
  32 #include <net/route.h>
  33 #include <netinet/in.h>
  34 #include <netinet/ip6.h>
  35 #include <netinet/udp.h>
  36 #include <netinet/sctp.h>
  37 #include <inet/mib2.h>
  38 #include <inet/common.h>
  39 #include <inet/ip.h>
  40 #include <inet/ip_ire.h>
  41 #include <inet/ip6.h>
  42 #include <inet/ipclassifier.h>
  43 #include <inet/mi.h>
  44 #include <sys/squeue_impl.h>
  45 #include <sys/modhash_impl.h>
  46 #include <inet/ip_ndp.h>
  47 #include <inet/ip_if.h>
  48 #include <ilb.h>
  49 #include <ilb/ilb_impl.h>
  50 #include <ilb/ilb_stack.h>
  51 #include <ilb/ilb_nat.h>
  52 #include <ilb/ilb_conn.h>
  53 #include <sys/dlpi.h>
  54 #include <sys/zone.h>
  55 
  56 #include <mdb/mdb_modapi.h>
  57 #include <mdb/mdb_ks.h>
  58 
  59 #define ADDR_WIDTH 11
  60 #define L2MAXADDRSTRLEN 255
  61 #define MAX_SAP_LEN     255
  62 #define DEFCOLS         80
  63 
  64 typedef struct {
  65         const char *bit_name;   /* name of bit */
  66         const char *bit_descr;  /* description of bit's purpose */
  67 } bitname_t;
  68 
  69 static const bitname_t squeue_states[] = {
  70         { "SQS_PROC",           "being processed" },
  71         { "SQS_WORKER",         "... by a worker thread" },
  72         { "SQS_ENTER",          "... by an squeue_enter() thread" },
  73         { "SQS_FAST",           "... in fast-path mode" },
  74         { "SQS_USER",           "A non interrupt user" },
  75         { "SQS_BOUND",          "worker thread bound to CPU" },
  76         { "SQS_PROFILE",        "profiling enabled" },
  77         { "SQS_REENTER",        "re-entered thred" },
  78         { NULL }
  79 };
  80 
  81 typedef struct illif_walk_data {
  82         ill_g_head_t ill_g_heads[MAX_G_HEADS];
  83         int ill_list;
  84         ill_if_t ill_if;
  85 } illif_walk_data_t;
  86 
  87 typedef struct ncec_walk_data_s {
  88         struct ndp_g_s  ncec_ip_ndp;
  89         int             ncec_hash_tbl_index;
  90         ncec_t          ncec;
  91 } ncec_walk_data_t;
  92 
  93 typedef struct ncec_cbdata_s {
  94         uintptr_t ncec_addr;
  95         int       ncec_ipversion;
  96 } ncec_cbdata_t;
  97 
  98 typedef struct nce_cbdata_s {
  99         int             nce_ipversion;
 100         char            nce_ill_name[LIFNAMSIZ];
 101 } nce_cbdata_t;
 102 
 103 typedef struct ire_cbdata_s {
 104         int             ire_ipversion;
 105         boolean_t       verbose;
 106 } ire_cbdata_t;
 107 
 108 typedef struct zi_cbdata_s {
 109         const char      *zone_name;
 110         ip_stack_t      *ipst;
 111         boolean_t       shared_ip_zone;
 112 } zi_cbdata_t;
 113 
 114 typedef struct th_walk_data {
 115         uint_t          thw_non_zero_only;
 116         boolean_t       thw_match;
 117         uintptr_t       thw_matchkey;
 118         uintptr_t       thw_ipst;
 119         clock_t         thw_lbolt;
 120 } th_walk_data_t;
 121 
 122 typedef struct ipcl_hash_walk_data_s {
 123         conn_t          *conn;
 124         int             connf_tbl_index;
 125         uintptr_t       hash_tbl;
 126         int             hash_tbl_size;
 127 } ipcl_hash_walk_data_t;
 128 
 129 typedef struct ill_walk_data_s {
 130         ill_t           ill;
 131 } ill_walk_data_t;
 132 
 133 typedef struct ill_cbdata_s {
 134         uintptr_t ill_addr;
 135         int       ill_ipversion;
 136         ip_stack_t *ill_ipst;
 137         boolean_t verbose;
 138 } ill_cbdata_t;
 139 
 140 typedef struct ipif_walk_data_s {
 141         ipif_t          ipif;
 142 } ipif_walk_data_t;
 143 
 144 typedef struct ipif_cbdata_s {
 145         ill_t           ill;
 146         int             ipif_ipversion;
 147         boolean_t       verbose;
 148 } ipif_cbdata_t;
 149 
 150 typedef struct hash_walk_arg_s {
 151         off_t   tbl_off;
 152         off_t   size_off;
 153 } hash_walk_arg_t;
 154 
 155 static hash_walk_arg_t udp_hash_arg = {
 156         OFFSETOF(ip_stack_t, ips_ipcl_udp_fanout),
 157         OFFSETOF(ip_stack_t, ips_ipcl_udp_fanout_size)
 158 };
 159 
 160 static hash_walk_arg_t conn_hash_arg = {
 161         OFFSETOF(ip_stack_t, ips_ipcl_conn_fanout),
 162         OFFSETOF(ip_stack_t, ips_ipcl_conn_fanout_size)
 163 };
 164 
 165 static hash_walk_arg_t bind_hash_arg = {
 166         OFFSETOF(ip_stack_t, ips_ipcl_bind_fanout),
 167         OFFSETOF(ip_stack_t, ips_ipcl_bind_fanout_size)
 168 };
 169 
 170 static hash_walk_arg_t proto_hash_arg = {
 171         OFFSETOF(ip_stack_t, ips_ipcl_proto_fanout_v4),
 172         0
 173 };
 174 
 175 static hash_walk_arg_t proto_v6_hash_arg = {
 176         OFFSETOF(ip_stack_t, ips_ipcl_proto_fanout_v6),
 177         0
 178 };
 179 
 180 typedef struct ip_list_walk_data_s {
 181         off_t   nextoff;
 182 } ip_list_walk_data_t;
 183 
 184 typedef struct ip_list_walk_arg_s {
 185         off_t   off;
 186         size_t  size;
 187         off_t   nextp_off;
 188 } ip_list_walk_arg_t;
 189 
 190 static ip_list_walk_arg_t ipif_walk_arg = {
 191         OFFSETOF(ill_t, ill_ipif),
 192         sizeof (ipif_t),
 193         OFFSETOF(ipif_t, ipif_next)
 194 };
 195 
 196 static ip_list_walk_arg_t srcid_walk_arg = {
 197         OFFSETOF(ip_stack_t, ips_srcid_head),
 198         sizeof (srcid_map_t),
 199         OFFSETOF(srcid_map_t, sm_next)
 200 };
 201 
 202 static int iphdr(uintptr_t, uint_t, int, const mdb_arg_t *);
 203 static int ip6hdr(uintptr_t, uint_t, int, const mdb_arg_t *);
 204 
 205 static int ill(uintptr_t, uint_t, int, const mdb_arg_t *);
 206 static void ill_help(void);
 207 static int ill_walk_init(mdb_walk_state_t *);
 208 static int ill_walk_step(mdb_walk_state_t *);
 209 static int ill_format(uintptr_t, const void *, void *);
 210 static void ill_header(boolean_t);
 211 
 212 static int ipif(uintptr_t, uint_t, int, const mdb_arg_t *);
 213 static void ipif_help(void);
 214 static int ipif_walk_init(mdb_walk_state_t *);
 215 static int ipif_walk_step(mdb_walk_state_t *);
 216 static int ipif_format(uintptr_t, const void *, void *);
 217 static void ipif_header(boolean_t);
 218 
 219 static int ip_list_walk_init(mdb_walk_state_t *);
 220 static int ip_list_walk_step(mdb_walk_state_t *);
 221 static void ip_list_walk_fini(mdb_walk_state_t *);
 222 static int srcid_walk_step(mdb_walk_state_t *);
 223 
 224 static int ire_format(uintptr_t addr, const void *, void *);
 225 static int ncec_format(uintptr_t addr, const ncec_t *ncec, int ipversion);
 226 static int ncec(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv);
 227 static int ncec_walk_step(mdb_walk_state_t *wsp);
 228 static int ncec_stack_walk_init(mdb_walk_state_t *wsp);
 229 static int ncec_stack_walk_step(mdb_walk_state_t *wsp);
 230 static void ncec_stack_walk_fini(mdb_walk_state_t *wsp);
 231 static int ncec_cb(uintptr_t addr, const ncec_walk_data_t *iw,
 232     ncec_cbdata_t *id);
 233 static char *nce_l2_addr(const nce_t *, const ill_t *);
 234 
 235 static int ipcl_hash_walk_init(mdb_walk_state_t *);
 236 static int ipcl_hash_walk_step(mdb_walk_state_t *);
 237 static void ipcl_hash_walk_fini(mdb_walk_state_t *);
 238 
 239 static int conn_status_walk_step(mdb_walk_state_t *);
 240 static int conn_status(uintptr_t, uint_t, int, const mdb_arg_t *);
 241 static void conn_status_help(void);
 242 
 243 static int srcid_status(uintptr_t, uint_t, int, const mdb_arg_t *);
 244 
 245 static int ilb_stacks_walk_step(mdb_walk_state_t *);
 246 static int ilb_rules_walk_init(mdb_walk_state_t *);
 247 static int ilb_rules_walk_step(mdb_walk_state_t *);
 248 static int ilb_servers_walk_init(mdb_walk_state_t *);
 249 static int ilb_servers_walk_step(mdb_walk_state_t *);
 250 static int ilb_nat_src_walk_init(mdb_walk_state_t *);
 251 static int ilb_nat_src_walk_step(mdb_walk_state_t *);
 252 static int ilb_conn_walk_init(mdb_walk_state_t *);
 253 static int ilb_conn_walk_step(mdb_walk_state_t *);
 254 static int ilb_sticky_walk_init(mdb_walk_state_t *);
 255 static int ilb_sticky_walk_step(mdb_walk_state_t *);
 256 static void ilb_common_walk_fini(mdb_walk_state_t *);
 257 
 258 /*
 259  * Given the kernel address of an ip_stack_t, return the stackid
 260  */
 261 static int
 262 ips_to_stackid(uintptr_t kaddr)
 263 {
 264         ip_stack_t ipss;
 265         netstack_t nss;
 266 
 267         if (mdb_vread(&ipss, sizeof (ipss), kaddr) == -1) {
 268                 mdb_warn("failed to read ip_stack_t %p", kaddr);
 269                 return (0);
 270         }
 271         kaddr = (uintptr_t)ipss.ips_netstack;
 272         if (mdb_vread(&nss, sizeof (nss), kaddr) == -1) {
 273                 mdb_warn("failed to read netstack_t %p", kaddr);
 274                 return (0);
 275         }
 276         return (nss.netstack_stackid);
 277 }
 278 
 279 /* ARGSUSED */
 280 static int
 281 zone_to_ips_cb(uintptr_t addr, const void *zi_arg, void *zi_cb_arg)
 282 {
 283         zi_cbdata_t *zi_cb = zi_cb_arg;
 284         zone_t zone;
 285         char zone_name[ZONENAME_MAX];
 286         netstack_t ns;
 287 
 288         if (mdb_vread(&zone, sizeof (zone_t), addr) == -1) {
 289                 mdb_warn("can't read zone at %p", addr);
 290                 return (WALK_ERR);
 291         }
 292 
 293         (void) mdb_readstr(zone_name, ZONENAME_MAX, (uintptr_t)zone.zone_name);
 294 
 295         if (strcmp(zi_cb->zone_name, zone_name) != 0)
 296                 return (WALK_NEXT);
 297 
 298         zi_cb->shared_ip_zone = (!(zone.zone_flags & ZF_NET_EXCL) &&
 299             (strcmp(zone_name, "global") != 0));
 300 
 301         if (mdb_vread(&ns, sizeof (netstack_t), (uintptr_t)zone.zone_netstack)
 302             == -1) {
 303                 mdb_warn("can't read netstack at %p", zone.zone_netstack);
 304                 return (WALK_ERR);
 305         }
 306 
 307         zi_cb->ipst = ns.netstack_ip;
 308         return (WALK_DONE);
 309 }
 310 
 311 static ip_stack_t *
 312 zone_to_ips(const char *zone_name)
 313 {
 314         zi_cbdata_t zi_cb;
 315 
 316         if (zone_name == NULL)
 317                 return (NULL);
 318 
 319         zi_cb.zone_name = zone_name;
 320         zi_cb.ipst = NULL;
 321         zi_cb.shared_ip_zone = B_FALSE;
 322 
 323         if (mdb_walk("zone", (mdb_walk_cb_t)zone_to_ips_cb, &zi_cb) == -1) {
 324                 mdb_warn("failed to walk zone");
 325                 return (NULL);
 326         }
 327 
 328         if (zi_cb.shared_ip_zone) {
 329                 mdb_warn("%s is a Shared-IP zone, try '-s global' instead\n",
 330                     zone_name);
 331                 return (NULL);
 332         }
 333 
 334         if (zi_cb.ipst == NULL) {
 335                 mdb_warn("failed to find zone %s\n", zone_name);
 336                 return (NULL);
 337         }
 338 
 339         return (zi_cb.ipst);
 340 }
 341 
 342 /*
 343  * Generic network stack walker initialization function.  It is used by all
 344  * other network stack walkers.
 345  */
 346 int
 347 ns_walk_init(mdb_walk_state_t *wsp)
 348 {
 349         if (mdb_layered_walk("netstack", wsp) == -1) {
 350                 mdb_warn("can't walk 'netstack'");
 351                 return (WALK_ERR);
 352         }
 353         return (WALK_NEXT);
 354 }
 355 
 356 /*
 357  * Generic network stack walker stepping function.  It is used by all other
 358  * network stack walkers.  The which parameter differentiates the different
 359  * walkers.
 360  */
 361 int
 362 ns_walk_step(mdb_walk_state_t *wsp, int which)
 363 {
 364         uintptr_t kaddr;
 365         netstack_t nss;
 366 
 367         if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
 368                 mdb_warn("can't read netstack at %p", wsp->walk_addr);
 369                 return (WALK_ERR);
 370         }
 371         kaddr = (uintptr_t)nss.netstack_modules[which];
 372 
 373         return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
 374 }
 375 
 376 /*
 377  * DCCP network stack walker stepping function.
 378  */
 379 int
 380 dccp_stacks_walk_step(mdb_walk_state_t *wsp)
 381 {
 382         return (ns_walk_step(wsp, NS_DCCP));
 383 }
 384 
 385 /*
 386  * IP network stack walker stepping function.
 387  */
 388 int
 389 ip_stacks_walk_step(mdb_walk_state_t *wsp)
 390 {
 391         return (ns_walk_step(wsp, NS_IP));
 392 }
 393 
 394 /*
 395  * TCP network stack walker stepping function.
 396  */
 397 int
 398 tcp_stacks_walk_step(mdb_walk_state_t *wsp)
 399 {
 400         return (ns_walk_step(wsp, NS_TCP));
 401 }
 402 
 403 /*
 404  * SCTP network stack walker stepping function.
 405  */
 406 int
 407 sctp_stacks_walk_step(mdb_walk_state_t *wsp)
 408 {
 409         return (ns_walk_step(wsp, NS_SCTP));
 410 }
 411 
 412 /*
 413  * UDP network stack walker stepping function.
 414  */
 415 int
 416 udp_stacks_walk_step(mdb_walk_state_t *wsp)
 417 {
 418         return (ns_walk_step(wsp, NS_UDP));
 419 }
 420 
 421 /*
 422  * Initialization function for the per CPU TCP stats counter walker of a given
 423  * TCP stack.
 424  */
 425 int
 426 tcps_sc_walk_init(mdb_walk_state_t *wsp)
 427 {
 428         tcp_stack_t tcps;
 429 
 430         if (wsp->walk_addr == NULL)
 431                 return (WALK_ERR);
 432 
 433         if (mdb_vread(&tcps, sizeof (tcps), wsp->walk_addr) == -1) {
 434                 mdb_warn("failed to read tcp_stack_t at %p", wsp->walk_addr);
 435                 return (WALK_ERR);
 436         }
 437         if (tcps.tcps_sc_cnt == 0)
 438                 return (WALK_DONE);
 439 
 440         /*
 441          * Store the tcp_stack_t pointer in walk_data.  The stepping function
 442          * used it to calculate if the end of the counter has reached.
 443          */
 444         wsp->walk_data = (void *)wsp->walk_addr;
 445         wsp->walk_addr = (uintptr_t)tcps.tcps_sc;
 446         return (WALK_NEXT);
 447 }
 448 
 449 /*
 450  * Stepping function for the per CPU TCP stats counterwalker.
 451  */
 452 int
 453 tcps_sc_walk_step(mdb_walk_state_t *wsp)
 454 {
 455         int status;
 456         tcp_stack_t tcps;
 457         tcp_stats_cpu_t *stats;
 458         char *next, *end;
 459 
 460         if (mdb_vread(&tcps, sizeof (tcps), (uintptr_t)wsp->walk_data) == -1) {
 461                 mdb_warn("failed to read tcp_stack_t at %p", wsp->walk_addr);
 462                 return (WALK_ERR);
 463         }
 464         if (mdb_vread(&stats, sizeof (stats), wsp->walk_addr) == -1) {
 465                 mdb_warn("failed ot read tcp_stats_cpu_t at %p",
 466                     wsp->walk_addr);
 467                 return (WALK_ERR);
 468         }
 469         status = wsp->walk_callback((uintptr_t)stats, &stats, wsp->walk_cbdata);
 470         if (status != WALK_NEXT)
 471                 return (status);
 472 
 473         next = (char *)wsp->walk_addr + sizeof (tcp_stats_cpu_t *);
 474         end = (char *)tcps.tcps_sc + tcps.tcps_sc_cnt *
 475             sizeof (tcp_stats_cpu_t *);
 476         if (next >= end)
 477                 return (WALK_DONE);
 478         wsp->walk_addr = (uintptr_t)next;
 479         return (WALK_NEXT);
 480 }
 481 
 482 int
 483 th_hash_walk_init(mdb_walk_state_t *wsp)
 484 {
 485         GElf_Sym sym;
 486         list_node_t *next;
 487 
 488         if (wsp->walk_addr == NULL) {
 489                 if (mdb_lookup_by_obj("ip", "ip_thread_list", &sym) == 0) {
 490                         wsp->walk_addr = sym.st_value;
 491                 } else {
 492                         mdb_warn("unable to locate ip_thread_list\n");
 493                         return (WALK_ERR);
 494                 }
 495         }
 496 
 497         if (mdb_vread(&next, sizeof (next),
 498             wsp->walk_addr + offsetof(list_t, list_head) +
 499             offsetof(list_node_t, list_next)) == -1 ||
 500             next == NULL) {
 501                 mdb_warn("non-DEBUG image; cannot walk th_hash list\n");
 502                 return (WALK_ERR);
 503         }
 504 
 505         if (mdb_layered_walk("list", wsp) == -1) {
 506                 mdb_warn("can't walk 'list'");
 507                 return (WALK_ERR);
 508         } else {
 509                 return (WALK_NEXT);
 510         }
 511 }
 512 
 513 int
 514 th_hash_walk_step(mdb_walk_state_t *wsp)
 515 {
 516         return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer,
 517             wsp->walk_cbdata));
 518 }
 519 
 520 /*
 521  * Called with walk_addr being the address of ips_ill_g_heads
 522  */
 523 int
 524 illif_stack_walk_init(mdb_walk_state_t *wsp)
 525 {
 526         illif_walk_data_t *iw;
 527 
 528         if (wsp->walk_addr == NULL) {
 529                 mdb_warn("illif_stack supports only local walks\n");
 530                 return (WALK_ERR);
 531         }
 532 
 533         iw = mdb_alloc(sizeof (illif_walk_data_t), UM_SLEEP);
 534 
 535         if (mdb_vread(iw->ill_g_heads, MAX_G_HEADS * sizeof (ill_g_head_t),
 536             wsp->walk_addr) == -1) {
 537                 mdb_warn("failed to read 'ips_ill_g_heads' at %p",
 538                     wsp->walk_addr);
 539                 mdb_free(iw, sizeof (illif_walk_data_t));
 540                 return (WALK_ERR);
 541         }
 542 
 543         iw->ill_list = 0;
 544         wsp->walk_addr = (uintptr_t)iw->ill_g_heads[0].ill_g_list_head;
 545         wsp->walk_data = iw;
 546 
 547         return (WALK_NEXT);
 548 }
 549 
 550 int
 551 illif_stack_walk_step(mdb_walk_state_t *wsp)
 552 {
 553         uintptr_t addr = wsp->walk_addr;
 554         illif_walk_data_t *iw = wsp->walk_data;
 555         int list = iw->ill_list;
 556 
 557         if (mdb_vread(&iw->ill_if, sizeof (ill_if_t), addr) == -1) {
 558                 mdb_warn("failed to read ill_if_t at %p", addr);
 559                 return (WALK_ERR);
 560         }
 561 
 562         wsp->walk_addr = (uintptr_t)iw->ill_if.illif_next;
 563 
 564         if (wsp->walk_addr ==
 565             (uintptr_t)iw->ill_g_heads[list].ill_g_list_head) {
 566 
 567                 if (++list >= MAX_G_HEADS)
 568                         return (WALK_DONE);
 569 
 570                 iw->ill_list = list;
 571                 wsp->walk_addr =
 572                     (uintptr_t)iw->ill_g_heads[list].ill_g_list_head;
 573                 return (WALK_NEXT);
 574         }
 575 
 576         return (wsp->walk_callback(addr, iw, wsp->walk_cbdata));
 577 }
 578 
 579 void
 580 illif_stack_walk_fini(mdb_walk_state_t *wsp)
 581 {
 582         mdb_free(wsp->walk_data, sizeof (illif_walk_data_t));
 583 }
 584 
 585 typedef struct illif_cbdata {
 586         uint_t ill_flags;
 587         uintptr_t ill_addr;
 588         int ill_printlist;      /* list to be printed (MAX_G_HEADS for all) */
 589         boolean_t ill_printed;
 590 } illif_cbdata_t;
 591 
 592 static int
 593 illif_cb(uintptr_t addr, const illif_walk_data_t *iw, illif_cbdata_t *id)
 594 {
 595         const char *version;
 596 
 597         if (id->ill_printlist < MAX_G_HEADS &&
 598             id->ill_printlist != iw->ill_list)
 599                 return (WALK_NEXT);
 600 
 601         if (id->ill_flags & DCMD_ADDRSPEC && id->ill_addr != addr)
 602                 return (WALK_NEXT);
 603 
 604         if (id->ill_flags & DCMD_PIPE_OUT) {
 605                 mdb_printf("%p\n", addr);
 606                 return (WALK_NEXT);
 607         }
 608 
 609         switch (iw->ill_list) {
 610                 case IP_V4_G_HEAD:      version = "v4"; break;
 611                 case IP_V6_G_HEAD:      version = "v6"; break;
 612                 default:                version = "??"; break;
 613         }
 614 
 615         mdb_printf("%?p %2s %?p %10d %?p %s\n",
 616             addr, version, addr + offsetof(ill_if_t, illif_avl_by_ppa),
 617             iw->ill_if.illif_avl_by_ppa.avl_numnodes,
 618             iw->ill_if.illif_ppa_arena, iw->ill_if.illif_name);
 619 
 620         id->ill_printed = TRUE;
 621 
 622         return (WALK_NEXT);
 623 }
 624 
 625 int
 626 ip_stacks_common_walk_init(mdb_walk_state_t *wsp)
 627 {
 628         if (mdb_layered_walk("ip_stacks", wsp) == -1) {
 629                 mdb_warn("can't walk 'ip_stacks'");
 630                 return (WALK_ERR);
 631         }
 632 
 633         return (WALK_NEXT);
 634 }
 635 
 636 int
 637 illif_walk_step(mdb_walk_state_t *wsp)
 638 {
 639         uintptr_t kaddr;
 640 
 641         kaddr = wsp->walk_addr + OFFSETOF(ip_stack_t, ips_ill_g_heads);
 642 
 643         if (mdb_vread(&kaddr, sizeof (kaddr), kaddr) == -1) {
 644                 mdb_warn("can't read ips_ip_cache_table at %p", kaddr);
 645                 return (WALK_ERR);
 646         }
 647 
 648         if (mdb_pwalk("illif_stack", wsp->walk_callback,
 649             wsp->walk_cbdata, kaddr) == -1) {
 650                 mdb_warn("couldn't walk 'illif_stack' for ips_ill_g_heads %p",
 651                     kaddr);
 652                 return (WALK_ERR);
 653         }
 654         return (WALK_NEXT);
 655 }
 656 
 657 int
 658 illif(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 659 {
 660         illif_cbdata_t id;
 661         ill_if_t ill_if;
 662         const char *opt_P = NULL;
 663         int printlist = MAX_G_HEADS;
 664 
 665         if (mdb_getopts(argc, argv,
 666             'P', MDB_OPT_STR, &opt_P, NULL) != argc)
 667                 return (DCMD_USAGE);
 668 
 669         if (opt_P != NULL) {
 670                 if (strcmp("v4", opt_P) == 0) {
 671                         printlist = IP_V4_G_HEAD;
 672                 } else if (strcmp("v6", opt_P) == 0) {
 673                         printlist = IP_V6_G_HEAD;
 674                 } else {
 675                         mdb_warn("invalid protocol '%s'\n", opt_P);
 676                         return (DCMD_USAGE);
 677                 }
 678         }
 679 
 680         if (DCMD_HDRSPEC(flags) && (flags & DCMD_PIPE_OUT) == 0) {
 681                 mdb_printf("%<u>%?s %2s %?s %10s %?s %-10s%</u>\n",
 682                     "ADDR", "IP", "AVLADDR", "NUMNODES", "ARENA", "NAME");
 683         }
 684 
 685         id.ill_flags = flags;
 686         id.ill_addr = addr;
 687         id.ill_printlist = printlist;
 688         id.ill_printed = FALSE;
 689 
 690         if (mdb_walk("illif", (mdb_walk_cb_t)illif_cb, &id) == -1) {
 691                 mdb_warn("can't walk ill_if_t structures");
 692                 return (DCMD_ERR);
 693         }
 694 
 695         if (!(flags & DCMD_ADDRSPEC) || opt_P != NULL || id.ill_printed)
 696                 return (DCMD_OK);
 697 
 698         /*
 699          * If an address is specified and the walk doesn't find it,
 700          * print it anyway.
 701          */
 702         if (mdb_vread(&ill_if, sizeof (ill_if_t), addr) == -1) {
 703                 mdb_warn("failed to read ill_if_t at %p", addr);
 704                 return (DCMD_ERR);
 705         }
 706 
 707         mdb_printf("%?p %2s %?p %10d %?p %s\n",
 708             addr, "??", addr + offsetof(ill_if_t, illif_avl_by_ppa),
 709             ill_if.illif_avl_by_ppa.avl_numnodes,
 710             ill_if.illif_ppa_arena, ill_if.illif_name);
 711 
 712         return (DCMD_OK);
 713 }
 714 
 715 static void
 716 illif_help(void)
 717 {
 718         mdb_printf("Options:\n");
 719         mdb_printf("\t-P v4 | v6"
 720             "\tfilter interface structures for the specified protocol\n");
 721 }
 722 
 723 int
 724 nce_walk_init(mdb_walk_state_t *wsp)
 725 {
 726         if (mdb_layered_walk("nce_cache", wsp) == -1) {
 727                 mdb_warn("can't walk 'nce_cache'");
 728                 return (WALK_ERR);
 729         }
 730 
 731         return (WALK_NEXT);
 732 }
 733 
 734 int
 735 nce_walk_step(mdb_walk_state_t *wsp)
 736 {
 737         nce_t nce;
 738 
 739         if (mdb_vread(&nce, sizeof (nce), wsp->walk_addr) == -1) {
 740                 mdb_warn("can't read nce at %p", wsp->walk_addr);
 741                 return (WALK_ERR);
 742         }
 743 
 744         return (wsp->walk_callback(wsp->walk_addr, &nce, wsp->walk_cbdata));
 745 }
 746 
 747 static int
 748 nce_format(uintptr_t addr, const nce_t *ncep, void *nce_cb_arg)
 749 {
 750         nce_cbdata_t *nce_cb = nce_cb_arg;
 751         ill_t ill;
 752         char ill_name[LIFNAMSIZ];
 753         ncec_t ncec;
 754 
 755         if (mdb_vread(&ncec, sizeof (ncec),
 756             (uintptr_t)ncep->nce_common) == -1) {
 757                 mdb_warn("can't read ncec at %p", ncep->nce_common);
 758                 return (WALK_NEXT);
 759         }
 760         if (nce_cb->nce_ipversion != 0 &&
 761             ncec.ncec_ipversion != nce_cb->nce_ipversion)
 762                 return (WALK_NEXT);
 763 
 764         if (mdb_vread(&ill, sizeof (ill), (uintptr_t)ncep->nce_ill) == -1) {
 765                 mdb_snprintf(ill_name, sizeof (ill_name), "--");
 766         } else {
 767                 (void) mdb_readstr(ill_name,
 768                     MIN(LIFNAMSIZ, ill.ill_name_length),
 769                     (uintptr_t)ill.ill_name);
 770         }
 771 
 772         if (nce_cb->nce_ill_name[0] != '\0' &&
 773             strncmp(nce_cb->nce_ill_name, ill_name, LIFNAMSIZ) != 0)
 774                 return (WALK_NEXT);
 775 
 776         if (ncec.ncec_ipversion == IPV6_VERSION) {
 777 
 778                 mdb_printf("%?p %5s %-18s %?p %6d %N\n",
 779                     addr, ill_name,
 780                     nce_l2_addr(ncep, &ill),
 781                     ncep->nce_fp_mp,
 782                     ncep->nce_refcnt,
 783                     &ncep->nce_addr);
 784 
 785         } else {
 786                 struct in_addr nceaddr;
 787 
 788                 IN6_V4MAPPED_TO_INADDR(&ncep->nce_addr, &nceaddr);
 789                 mdb_printf("%?p %5s %-18s %?p %6d %I\n",
 790                     addr, ill_name,
 791                     nce_l2_addr(ncep, &ill),
 792                     ncep->nce_fp_mp,
 793                     ncep->nce_refcnt,
 794                     nceaddr.s_addr);
 795         }
 796 
 797         return (WALK_NEXT);
 798 }
 799 
 800 int
 801 dce_walk_init(mdb_walk_state_t *wsp)
 802 {
 803         wsp->walk_data = (void *)wsp->walk_addr;
 804 
 805         if (mdb_layered_walk("dce_cache", wsp) == -1) {
 806                 mdb_warn("can't walk 'dce_cache'");
 807                 return (WALK_ERR);
 808         }
 809 
 810         return (WALK_NEXT);
 811 }
 812 
 813 int
 814 dce_walk_step(mdb_walk_state_t *wsp)
 815 {
 816         dce_t dce;
 817 
 818         if (mdb_vread(&dce, sizeof (dce), wsp->walk_addr) == -1) {
 819                 mdb_warn("can't read dce at %p", wsp->walk_addr);
 820                 return (WALK_ERR);
 821         }
 822 
 823         /* If ip_stack_t is specified, skip DCEs that don't belong to it. */
 824         if ((wsp->walk_data != NULL) && (wsp->walk_data != dce.dce_ipst))
 825                 return (WALK_NEXT);
 826 
 827         return (wsp->walk_callback(wsp->walk_addr, &dce, wsp->walk_cbdata));
 828 }
 829 
 830 int
 831 ire_walk_init(mdb_walk_state_t *wsp)
 832 {
 833         wsp->walk_data = (void *)wsp->walk_addr;
 834 
 835         if (mdb_layered_walk("ire_cache", wsp) == -1) {
 836                 mdb_warn("can't walk 'ire_cache'");
 837                 return (WALK_ERR);
 838         }
 839 
 840         return (WALK_NEXT);
 841 }
 842 
 843 int
 844 ire_walk_step(mdb_walk_state_t *wsp)
 845 {
 846         ire_t ire;
 847 
 848         if (mdb_vread(&ire, sizeof (ire), wsp->walk_addr) == -1) {
 849                 mdb_warn("can't read ire at %p", wsp->walk_addr);
 850                 return (WALK_ERR);
 851         }
 852 
 853         /* If ip_stack_t is specified, skip IREs that don't belong to it. */
 854         if ((wsp->walk_data != NULL) && (wsp->walk_data != ire.ire_ipst))
 855                 return (WALK_NEXT);
 856 
 857         return (wsp->walk_callback(wsp->walk_addr, &ire, wsp->walk_cbdata));
 858 }
 859 
 860 /* ARGSUSED */
 861 int
 862 ire_next_walk_init(mdb_walk_state_t *wsp)
 863 {
 864         return (WALK_NEXT);
 865 }
 866 
 867 int
 868 ire_next_walk_step(mdb_walk_state_t *wsp)
 869 {
 870         ire_t ire;
 871         int status;
 872 
 873 
 874         if (wsp->walk_addr == NULL)
 875                 return (WALK_DONE);
 876 
 877         if (mdb_vread(&ire, sizeof (ire), wsp->walk_addr) == -1) {
 878                 mdb_warn("can't read ire at %p", wsp->walk_addr);
 879                 return (WALK_ERR);
 880         }
 881         status = wsp->walk_callback(wsp->walk_addr, &ire,
 882             wsp->walk_cbdata);
 883 
 884         if (status != WALK_NEXT)
 885                 return (status);
 886 
 887         wsp->walk_addr = (uintptr_t)ire.ire_next;
 888         return (status);
 889 }
 890 
 891 static int
 892 ire_format(uintptr_t addr, const void *ire_arg, void *ire_cb_arg)
 893 {
 894         const ire_t *irep = ire_arg;
 895         ire_cbdata_t *ire_cb = ire_cb_arg;
 896         boolean_t verbose = ire_cb->verbose;
 897         ill_t ill;
 898         char ill_name[LIFNAMSIZ];
 899         boolean_t condemned = irep->ire_generation == IRE_GENERATION_CONDEMNED;
 900 
 901         static const mdb_bitmask_t tmasks[] = {
 902                 { "BROADCAST",  IRE_BROADCAST,          IRE_BROADCAST   },
 903                 { "DEFAULT",    IRE_DEFAULT,            IRE_DEFAULT     },
 904                 { "LOCAL",      IRE_LOCAL,              IRE_LOCAL       },
 905                 { "LOOPBACK",   IRE_LOOPBACK,           IRE_LOOPBACK    },
 906                 { "PREFIX",     IRE_PREFIX,             IRE_PREFIX      },
 907                 { "MULTICAST",  IRE_MULTICAST,          IRE_MULTICAST   },
 908                 { "NOROUTE",    IRE_NOROUTE,            IRE_NOROUTE     },
 909                 { "IF_NORESOLVER", IRE_IF_NORESOLVER,   IRE_IF_NORESOLVER },
 910                 { "IF_RESOLVER", IRE_IF_RESOLVER,       IRE_IF_RESOLVER },
 911                 { "IF_CLONE",   IRE_IF_CLONE,           IRE_IF_CLONE    },
 912                 { "HOST",       IRE_HOST,               IRE_HOST        },
 913                 { NULL,         0,                      0               }
 914         };
 915 
 916         static const mdb_bitmask_t fmasks[] = {
 917                 { "UP",         RTF_UP,                 RTF_UP          },
 918                 { "GATEWAY",    RTF_GATEWAY,            RTF_GATEWAY     },
 919                 { "HOST",       RTF_HOST,               RTF_HOST        },
 920                 { "REJECT",     RTF_REJECT,             RTF_REJECT      },
 921                 { "DYNAMIC",    RTF_DYNAMIC,            RTF_DYNAMIC     },
 922                 { "MODIFIED",   RTF_MODIFIED,           RTF_MODIFIED    },
 923                 { "DONE",       RTF_DONE,               RTF_DONE        },
 924                 { "MASK",       RTF_MASK,               RTF_MASK        },
 925                 { "CLONING",    RTF_CLONING,            RTF_CLONING     },
 926                 { "XRESOLVE",   RTF_XRESOLVE,           RTF_XRESOLVE    },
 927                 { "LLINFO",     RTF_LLINFO,             RTF_LLINFO      },
 928                 { "STATIC",     RTF_STATIC,             RTF_STATIC      },
 929                 { "BLACKHOLE",  RTF_BLACKHOLE,          RTF_BLACKHOLE   },
 930                 { "PRIVATE",    RTF_PRIVATE,            RTF_PRIVATE     },
 931                 { "PROTO2",     RTF_PROTO2,             RTF_PROTO2      },
 932                 { "PROTO1",     RTF_PROTO1,             RTF_PROTO1      },
 933                 { "MULTIRT",    RTF_MULTIRT,            RTF_MULTIRT     },
 934                 { "SETSRC",     RTF_SETSRC,             RTF_SETSRC      },
 935                 { "INDIRECT",   RTF_INDIRECT,           RTF_INDIRECT    },
 936                 { NULL,         0,                      0               }
 937         };
 938 
 939         if (ire_cb->ire_ipversion != 0 &&
 940             irep->ire_ipversion != ire_cb->ire_ipversion)
 941                 return (WALK_NEXT);
 942 
 943         if (mdb_vread(&ill, sizeof (ill), (uintptr_t)irep->ire_ill) == -1) {
 944                 mdb_snprintf(ill_name, sizeof (ill_name), "--");
 945         } else {
 946                 (void) mdb_readstr(ill_name,
 947                     MIN(LIFNAMSIZ, ill.ill_name_length),
 948                     (uintptr_t)ill.ill_name);
 949         }
 950 
 951         if (irep->ire_ipversion == IPV6_VERSION && verbose) {
 952 
 953                 mdb_printf("%<b>%?p%</b>%3s %40N <%hb%s>\n"
 954                     "%?s %40N\n"
 955                     "%?s %40d %4d <%hb> %s\n",
 956                     addr, condemned ? "(C)" : "", &irep->ire_setsrc_addr_v6,
 957                     irep->ire_type, tmasks,
 958                     (irep->ire_testhidden ? ", HIDDEN" : ""),
 959                     "", &irep->ire_addr_v6,
 960                     "", ips_to_stackid((uintptr_t)irep->ire_ipst),
 961                     irep->ire_zoneid,
 962                     irep->ire_flags, fmasks, ill_name);
 963 
 964         } else if (irep->ire_ipversion == IPV6_VERSION) {
 965 
 966                 mdb_printf("%?p%3s %30N %30N %5d %4d %s\n",
 967                     addr, condemned ? "(C)" : "", &irep->ire_setsrc_addr_v6,
 968                     &irep->ire_addr_v6,
 969                     ips_to_stackid((uintptr_t)irep->ire_ipst),
 970                     irep->ire_zoneid, ill_name);
 971 
 972         } else if (verbose) {
 973 
 974                 mdb_printf("%<b>%?p%</b>%3s %40I <%hb%s>\n"
 975                     "%?s %40I\n"
 976                     "%?s %40d %4d <%hb> %s\n",
 977                     addr, condemned ? "(C)" : "", irep->ire_setsrc_addr,
 978                     irep->ire_type, tmasks,
 979                     (irep->ire_testhidden ? ", HIDDEN" : ""),
 980                     "", irep->ire_addr,
 981                     "", ips_to_stackid((uintptr_t)irep->ire_ipst),
 982                     irep->ire_zoneid, irep->ire_flags, fmasks, ill_name);
 983 
 984         } else {
 985 
 986                 mdb_printf("%?p%3s %30I %30I %5d %4d %s\n", addr,
 987                     condemned ? "(C)" : "", irep->ire_setsrc_addr,
 988                     irep->ire_addr, ips_to_stackid((uintptr_t)irep->ire_ipst),
 989                     irep->ire_zoneid, ill_name);
 990         }
 991 
 992         return (WALK_NEXT);
 993 }
 994 
 995 /*
 996  * There are faster ways to do this.  Given the interactive nature of this
 997  * use I don't think its worth much effort.
 998  */
 999 static unsigned short
1000 ipcksum(void *p, int len)
1001 {
1002         int32_t sum = 0;
1003 
1004         while (len > 1) {
1005                 /* alignment */
1006                 sum += *(uint16_t *)p;
1007                 p = (char *)p + sizeof (uint16_t);
1008                 if (sum & 0x80000000)
1009                         sum = (sum & 0xFFFF) + (sum >> 16);
1010                 len -= 2;
1011         }
1012 
1013         if (len)
1014                 sum += (uint16_t)*(unsigned char *)p;
1015 
1016         while (sum >> 16)
1017                 sum = (sum & 0xFFFF) + (sum >> 16);
1018 
1019         return (~sum);
1020 }
1021 
1022 static const mdb_bitmask_t tcp_flags[] = {
1023         { "SYN",        TH_SYN,         TH_SYN  },
1024         { "ACK",        TH_ACK,         TH_ACK  },
1025         { "FIN",        TH_FIN,         TH_FIN  },
1026         { "RST",        TH_RST,         TH_RST  },
1027         { "PSH",        TH_PUSH,        TH_PUSH },
1028         { "ECE",        TH_ECE,         TH_ECE  },
1029         { "CWR",        TH_CWR,         TH_CWR  },
1030         { NULL,         0,              0       }
1031 };
1032 
1033 /* TCP option length */
1034 #define TCPOPT_HEADER_LEN       2
1035 #define TCPOPT_MAXSEG_LEN       4
1036 #define TCPOPT_WS_LEN           3
1037 #define TCPOPT_TSTAMP_LEN       10
1038 #define TCPOPT_SACK_OK_LEN      2
1039 
1040 static void
1041 tcphdr_print_options(uint8_t *opts, uint32_t opts_len)
1042 {
1043         uint8_t *endp;
1044         uint32_t len, val;
1045 
1046         mdb_printf("%<b>Options:%</b>");
1047         endp = opts + opts_len;
1048         while (opts < endp) {
1049                 len = endp - opts;
1050                 switch (*opts) {
1051                 case TCPOPT_EOL:
1052                         mdb_printf(" EOL");
1053                         opts++;
1054                         break;
1055 
1056                 case TCPOPT_NOP:
1057                         mdb_printf(" NOP");
1058                         opts++;
1059                         break;
1060 
1061                 case TCPOPT_MAXSEG: {
1062                         uint16_t mss;
1063 
1064                         if (len < TCPOPT_MAXSEG_LEN ||
1065                             opts[1] != TCPOPT_MAXSEG_LEN) {
1066                                 mdb_printf(" <Truncated MSS>\n");
1067                                 return;
1068                         }
1069                         mdb_nhconvert(&mss, opts + TCPOPT_HEADER_LEN,
1070                             sizeof (mss));
1071                         mdb_printf(" MSS=%u", mss);
1072                         opts += TCPOPT_MAXSEG_LEN;
1073                         break;
1074                 }
1075 
1076                 case TCPOPT_WSCALE:
1077                         if (len < TCPOPT_WS_LEN || opts[1] != TCPOPT_WS_LEN) {
1078                                 mdb_printf(" <Truncated WS>\n");
1079                                 return;
1080                         }
1081                         mdb_printf(" WS=%u", opts[2]);
1082                         opts += TCPOPT_WS_LEN;
1083                         break;
1084 
1085                 case TCPOPT_TSTAMP: {
1086                         if (len < TCPOPT_TSTAMP_LEN ||
1087                             opts[1] != TCPOPT_TSTAMP_LEN) {
1088                                 mdb_printf(" <Truncated TS>\n");
1089                                 return;
1090                         }
1091 
1092                         opts += TCPOPT_HEADER_LEN;
1093                         mdb_nhconvert(&val, opts, sizeof (val));
1094                         mdb_printf(" TS_VAL=%u,", val);
1095 
1096                         opts += sizeof (val);
1097                         mdb_nhconvert(&val, opts, sizeof (val));
1098                         mdb_printf("TS_ECHO=%u", val);
1099 
1100                         opts += sizeof (val);
1101                         break;
1102                 }
1103 
1104                 case TCPOPT_SACK_PERMITTED:
1105                         if (len < TCPOPT_SACK_OK_LEN ||
1106                             opts[1] != TCPOPT_SACK_OK_LEN) {
1107                                 mdb_printf(" <Truncated SACK_OK>\n");
1108                                 return;
1109                         }
1110                         mdb_printf(" SACK_OK");
1111                         opts += TCPOPT_SACK_OK_LEN;
1112                         break;
1113 
1114                 case TCPOPT_SACK: {
1115                         uint32_t sack_len;
1116 
1117                         if (len <= TCPOPT_HEADER_LEN || len < opts[1] ||
1118                             opts[1] <= TCPOPT_HEADER_LEN) {
1119                                 mdb_printf(" <Truncated SACK>\n");
1120                                 return;
1121                         }
1122                         sack_len = opts[1] - TCPOPT_HEADER_LEN;
1123                         opts += TCPOPT_HEADER_LEN;
1124 
1125                         mdb_printf(" SACK=");
1126                         while (sack_len > 0) {
1127                                 if (opts + 2 * sizeof (val) > endp) {
1128                                         mdb_printf("<Truncated SACK>\n");
1129                                         opts = endp;
1130                                         break;
1131                                 }
1132 
1133                                 mdb_nhconvert(&val, opts, sizeof (val));
1134                                 mdb_printf("<%u,", val);
1135                                 opts += sizeof (val);
1136                                 mdb_nhconvert(&val, opts, sizeof (val));
1137                                 mdb_printf("%u>", val);
1138                                 opts += sizeof (val);
1139 
1140                                 sack_len -= 2 * sizeof (val);
1141                         }
1142                         break;
1143                 }
1144 
1145                 default:
1146                         mdb_printf(" Opts=<val=%u,len=%u>", *opts,
1147                             opts[1]);
1148                         opts += opts[1];
1149                         break;
1150                 }
1151         }
1152         mdb_printf("\n");
1153 }
1154 
1155 static void
1156 tcphdr_print(struct tcphdr *tcph)
1157 {
1158         in_port_t       sport, dport;
1159         tcp_seq         seq, ack;
1160         uint16_t        win, urp;
1161 
1162         mdb_printf("%<b>TCP header%</b>\n");
1163 
1164         mdb_nhconvert(&sport, &tcph->th_sport, sizeof (sport));
1165         mdb_nhconvert(&dport, &tcph->th_dport, sizeof (dport));
1166         mdb_nhconvert(&seq, &tcph->th_seq, sizeof (seq));
1167         mdb_nhconvert(&ack, &tcph->th_ack, sizeof (ack));
1168         mdb_nhconvert(&win, &tcph->th_win, sizeof (win));
1169         mdb_nhconvert(&urp, &tcph->th_urp, sizeof (urp));
1170 
1171         mdb_printf("%<u>%6s %6s %10s %10s %4s %5s %5s %5s %-15s%</u>\n",
1172             "SPORT", "DPORT", "SEQ", "ACK", "HLEN", "WIN", "CSUM", "URP",
1173             "FLAGS");
1174         mdb_printf("%6hu %6hu %10u %10u %4d %5hu %5hu %5hu <%b>\n",
1175             sport, dport, seq, ack, tcph->th_off << 2, win,
1176             tcph->th_sum, urp, tcph->th_flags, tcp_flags);
1177         mdb_printf("0x%04x 0x%04x 0x%08x 0x%08x\n\n",
1178             sport, dport, seq, ack);
1179 }
1180 
1181 /* ARGSUSED */
1182 static int
1183 tcphdr(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av)
1184 {
1185         struct tcphdr   tcph;
1186         uint32_t        opt_len;
1187 
1188         if (!(flags & DCMD_ADDRSPEC))
1189                 return (DCMD_USAGE);
1190 
1191         if (mdb_vread(&tcph, sizeof (tcph), addr) == -1) {
1192                 mdb_warn("failed to read TCP header at %p", addr);
1193                 return (DCMD_ERR);
1194         }
1195         tcphdr_print(&tcph);
1196 
1197         /* If there are options, print them out also. */
1198         opt_len = (tcph.th_off << 2) - TCP_MIN_HEADER_LENGTH;
1199         if (opt_len > 0) {
1200                 uint8_t *opts, *opt_buf;
1201 
1202                 opt_buf = mdb_alloc(opt_len, UM_SLEEP);
1203                 opts = (uint8_t *)addr + sizeof (tcph);
1204                 if (mdb_vread(opt_buf, opt_len, (uintptr_t)opts) == -1) {
1205                         mdb_warn("failed to read TCP options at %p", opts);
1206                         return (DCMD_ERR);
1207                 }
1208                 tcphdr_print_options(opt_buf, opt_len);
1209                 mdb_free(opt_buf, opt_len);
1210         }
1211 
1212         return (DCMD_OK);
1213 }
1214 
1215 static void
1216 udphdr_print(struct udphdr *udph)
1217 {
1218         in_port_t       sport, dport;
1219         uint16_t        hlen;
1220 
1221         mdb_printf("%<b>UDP header%</b>\n");
1222 
1223         mdb_nhconvert(&sport, &udph->uh_sport, sizeof (sport));
1224         mdb_nhconvert(&dport, &udph->uh_dport, sizeof (dport));
1225         mdb_nhconvert(&hlen, &udph->uh_ulen, sizeof (hlen));
1226 
1227         mdb_printf("%<u>%14s %14s %5s %6s%</u>\n",
1228             "SPORT", "DPORT", "LEN", "CSUM");
1229         mdb_printf("%5hu (0x%04x) %5hu (0x%04x) %5hu 0x%04hx\n\n", sport, sport,
1230             dport, dport, hlen, udph->uh_sum);
1231 }
1232 
1233 /* ARGSUSED */
1234 static int
1235 udphdr(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av)
1236 {
1237         struct udphdr   udph;
1238 
1239         if (!(flags & DCMD_ADDRSPEC))
1240                 return (DCMD_USAGE);
1241 
1242         if (mdb_vread(&udph, sizeof (udph), addr) == -1) {
1243                 mdb_warn("failed to read UDP header at %p", addr);
1244                 return (DCMD_ERR);
1245         }
1246         udphdr_print(&udph);
1247         return (DCMD_OK);
1248 }
1249 
1250 static void
1251 sctphdr_print(sctp_hdr_t *sctph)
1252 {
1253         in_port_t sport, dport;
1254 
1255         mdb_printf("%<b>SCTP header%</b>\n");
1256         mdb_nhconvert(&sport, &sctph->sh_sport, sizeof (sport));
1257         mdb_nhconvert(&dport, &sctph->sh_dport, sizeof (dport));
1258 
1259         mdb_printf("%<u>%14s %14s %10s %10s%</u>\n",
1260             "SPORT", "DPORT", "VTAG", "CHKSUM");
1261         mdb_printf("%5hu (0x%04x) %5hu (0x%04x) %10u 0x%08x\n\n", sport, sport,
1262             dport, dport, sctph->sh_verf, sctph->sh_chksum);
1263 }
1264 
1265 /* ARGSUSED */
1266 static int
1267 sctphdr(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av)
1268 {
1269         sctp_hdr_t sctph;
1270 
1271         if (!(flags & DCMD_ADDRSPEC))
1272                 return (DCMD_USAGE);
1273 
1274         if (mdb_vread(&sctph, sizeof (sctph), addr) == -1) {
1275                 mdb_warn("failed to read SCTP header at %p", addr);
1276                 return (DCMD_ERR);
1277         }
1278 
1279         sctphdr_print(&sctph);
1280         return (DCMD_OK);
1281 }
1282 
1283 static int
1284 transport_hdr(int proto, uintptr_t addr)
1285 {
1286         mdb_printf("\n");
1287         switch (proto) {
1288         case IPPROTO_TCP: {
1289                 struct tcphdr tcph;
1290 
1291                 if (mdb_vread(&tcph, sizeof (tcph), addr) == -1) {
1292                         mdb_warn("failed to read TCP header at %p", addr);
1293                         return (DCMD_ERR);
1294                 }
1295                 tcphdr_print(&tcph);
1296                 break;
1297         }
1298         case IPPROTO_UDP:  {
1299                 struct udphdr udph;
1300 
1301                 if (mdb_vread(&udph, sizeof (udph), addr) == -1) {
1302                         mdb_warn("failed to read UDP header at %p", addr);
1303                         return (DCMD_ERR);
1304                 }
1305                 udphdr_print(&udph);
1306                 break;
1307         }
1308         case IPPROTO_SCTP: {
1309                 sctp_hdr_t sctph;
1310 
1311                 if (mdb_vread(&sctph, sizeof (sctph), addr) == -1) {
1312                         mdb_warn("failed to read SCTP header at %p", addr);
1313                         return (DCMD_ERR);
1314                 }
1315                 sctphdr_print(&sctph);
1316                 break;
1317         }
1318         default:
1319                 break;
1320         }
1321 
1322         return (DCMD_OK);
1323 }
1324 
1325 static const mdb_bitmask_t ip_flags[] = {
1326         { "DF", IPH_DF, IPH_DF  },
1327         { "MF", IPH_MF, IPH_MF  },
1328         { NULL, 0,      0       }
1329 };
1330 
1331 /* ARGSUSED */
1332 static int
1333 iphdr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1334 {
1335         uint_t          verbose = FALSE, force = FALSE;
1336         ipha_t          iph[1];
1337         uint16_t        ver, totlen, hdrlen, ipid, off, csum;
1338         uintptr_t       nxt_proto;
1339         char            exp_csum[8];
1340 
1341         if (mdb_getopts(argc, argv,
1342             'v', MDB_OPT_SETBITS, TRUE, &verbose,
1343             'f', MDB_OPT_SETBITS, TRUE, &force, NULL) != argc)
1344                 return (DCMD_USAGE);
1345 
1346         if (mdb_vread(iph, sizeof (*iph), addr) == -1) {
1347                 mdb_warn("failed to read IPv4 header at %p", addr);
1348                 return (DCMD_ERR);
1349         }
1350 
1351         ver = (iph->ipha_version_and_hdr_length & 0xf0) >> 4;
1352         if (ver != IPV4_VERSION) {
1353                 if (ver == IPV6_VERSION) {
1354                         return (ip6hdr(addr, flags, argc, argv));
1355                 } else if (!force) {
1356                         mdb_warn("unknown IP version: %d\n", ver);
1357                         return (DCMD_ERR);
1358                 }
1359         }
1360 
1361         mdb_printf("%<b>IPv4 header%</b>\n");
1362         mdb_printf("%-34s %-34s\n"
1363             "%<u>%-4s %-4s %-5s %-5s %-6s %-5s %-5s %-6s %-8s %-6s%</u>\n",
1364             "SRC", "DST",
1365             "HLEN", "TOS", "LEN", "ID", "OFFSET", "TTL", "PROTO", "CHKSUM",
1366             "EXP-CSUM", "FLGS");
1367 
1368         hdrlen = (iph->ipha_version_and_hdr_length & 0x0f) << 2;
1369         mdb_nhconvert(&totlen, &iph->ipha_length, sizeof (totlen));
1370         mdb_nhconvert(&ipid, &iph->ipha_ident, sizeof (ipid));
1371         mdb_nhconvert(&off, &iph->ipha_fragment_offset_and_flags, sizeof (off));
1372         if (hdrlen == IP_SIMPLE_HDR_LENGTH) {
1373                 if ((csum = ipcksum(iph, sizeof (*iph))) != 0)
1374                         csum = ~(~csum + ~iph->ipha_hdr_checksum);
1375                 else
1376                         csum = iph->ipha_hdr_checksum;
1377                 mdb_snprintf(exp_csum, 8, "%u", csum);
1378         } else {
1379                 mdb_snprintf(exp_csum, 8, "<n/a>");
1380         }
1381 
1382         mdb_printf("%-34I %-34I%\n"
1383             "%-4d %-4d %-5hu %-5hu %-6hu %-5hu %-5hu %-6u %-8s <%5hb>\n",
1384             iph->ipha_src, iph->ipha_dst,
1385             hdrlen, iph->ipha_type_of_service, totlen, ipid,
1386             (off << 3) & 0xffff, iph->ipha_ttl, iph->ipha_protocol,
1387             iph->ipha_hdr_checksum, exp_csum, off, ip_flags);
1388 
1389         if (verbose) {
1390                 nxt_proto = addr + hdrlen;
1391                 return (transport_hdr(iph->ipha_protocol, nxt_proto));
1392         } else {
1393                 return (DCMD_OK);
1394         }
1395 }
1396 
1397 /* ARGSUSED */
1398 static int
1399 ip6hdr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1400 {
1401         uint_t          verbose = FALSE, force = FALSE;
1402         ip6_t           iph[1];
1403         int             ver, class, flow;
1404         uint16_t        plen;
1405         uintptr_t       nxt_proto;
1406 
1407         if (mdb_getopts(argc, argv,
1408             'v', MDB_OPT_SETBITS, TRUE, &verbose,
1409             'f', MDB_OPT_SETBITS, TRUE, &force, NULL) != argc)
1410                 return (DCMD_USAGE);
1411 
1412         if (mdb_vread(iph, sizeof (*iph), addr) == -1) {
1413                 mdb_warn("failed to read IPv6 header at %p", addr);
1414                 return (DCMD_ERR);
1415         }
1416 
1417         ver = (iph->ip6_vfc & 0xf0) >> 4;
1418         if (ver != IPV6_VERSION) {
1419                 if (ver == IPV4_VERSION) {
1420                         return (iphdr(addr, flags, argc, argv));
1421                 } else if (!force) {
1422                         mdb_warn("unknown IP version: %d\n", ver);
1423                         return (DCMD_ERR);
1424                 }
1425         }
1426 
1427         mdb_printf("%<b>IPv6 header%</b>\n");
1428         mdb_printf("%<u>%-26s %-26s %4s %7s %5s %3s %3s%</u>\n",
1429             "SRC", "DST", "TCLS", "FLOW-ID", "PLEN", "NXT", "HOP");
1430 
1431         class = (iph->ip6_vcf & IPV6_FLOWINFO_TCLASS) >> 20;
1432         mdb_nhconvert(&class, &class, sizeof (class));
1433         flow = iph->ip6_vcf & IPV6_FLOWINFO_FLOWLABEL;
1434         mdb_nhconvert(&flow, &flow, sizeof (flow));
1435         mdb_nhconvert(&plen, &iph->ip6_plen, sizeof (plen));
1436 
1437         mdb_printf("%-26N %-26N %4d %7d %5hu %3d %3d\n",
1438             &iph->ip6_src, &iph->ip6_dst,
1439             class, flow, plen, iph->ip6_nxt, iph->ip6_hlim);
1440 
1441         if (verbose) {
1442                 nxt_proto = addr + sizeof (ip6_t);
1443                 return (transport_hdr(iph->ip6_nxt, nxt_proto));
1444         } else {
1445                 return (DCMD_OK);
1446         }
1447 }
1448 
1449 int
1450 nce(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1451 {
1452         nce_t nce;
1453         nce_cbdata_t nce_cb;
1454         int ipversion = 0;
1455         const char *opt_P = NULL, *opt_ill;
1456 
1457         if (mdb_getopts(argc, argv,
1458             'i', MDB_OPT_STR, &opt_ill,
1459             'P', MDB_OPT_STR, &opt_P, NULL) != argc)
1460                 return (DCMD_USAGE);
1461 
1462         if (opt_P != NULL) {
1463                 if (strcmp("v4", opt_P) == 0) {
1464                         ipversion = IPV4_VERSION;
1465                 } else if (strcmp("v6", opt_P) == 0) {
1466                         ipversion = IPV6_VERSION;
1467                 } else {
1468                         mdb_warn("invalid protocol '%s'\n", opt_P);
1469                         return (DCMD_USAGE);
1470                 }
1471         }
1472 
1473         if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) {
1474                 mdb_printf("%<u>%?s %5s %18s %?s %s %s %</u>\n",
1475                     "ADDR", "INTF", "LLADDR", "FP_MP", "REFCNT",
1476                     "NCE_ADDR");
1477         }
1478 
1479         bzero(&nce_cb, sizeof (nce_cb));
1480         if (opt_ill != NULL) {
1481                 strcpy(nce_cb.nce_ill_name, opt_ill);
1482         }
1483         nce_cb.nce_ipversion = ipversion;
1484 
1485         if (flags & DCMD_ADDRSPEC) {
1486                 (void) mdb_vread(&nce, sizeof (nce_t), addr);
1487                 (void) nce_format(addr, &nce, &nce_cb);
1488         } else if (mdb_walk("nce", (mdb_walk_cb_t)nce_format, &nce_cb) == -1) {
1489                 mdb_warn("failed to walk ire table");
1490                 return (DCMD_ERR);
1491         }
1492 
1493         return (DCMD_OK);
1494 }
1495 
1496 /* ARGSUSED */
1497 static int
1498 dce_format(uintptr_t addr, const dce_t *dcep, void *dce_cb_arg)
1499 {
1500         static const mdb_bitmask_t dmasks[] = {
1501                 { "D",  DCEF_DEFAULT,           DCEF_DEFAULT },
1502                 { "P",  DCEF_PMTU,              DCEF_PMTU },
1503                 { "U",  DCEF_UINFO,             DCEF_UINFO },
1504                 { "S",  DCEF_TOO_SMALL_PMTU,    DCEF_TOO_SMALL_PMTU },
1505                 { NULL, 0,                      0               }
1506         };
1507         char flagsbuf[2 * A_CNT(dmasks)];
1508         int ipversion = *(int *)dce_cb_arg;
1509         boolean_t condemned = dcep->dce_generation == DCE_GENERATION_CONDEMNED;
1510 
1511         if (ipversion != 0 && ipversion != dcep->dce_ipversion)
1512                 return (WALK_NEXT);
1513 
1514         mdb_snprintf(flagsbuf, sizeof (flagsbuf), "%b", dcep->dce_flags,
1515             dmasks);
1516 
1517         switch (dcep->dce_ipversion) {
1518         case IPV4_VERSION:
1519                 mdb_printf("%<u>%?p%3s %8s %8d %30I %</u>\n", addr, condemned ?
1520                     "(C)" : "", flagsbuf, dcep->dce_pmtu, &dcep->dce_v4addr);
1521                 break;
1522         case IPV6_VERSION:
1523                 mdb_printf("%<u>%?p%3s %8s %8d %30N %</u>\n", addr, condemned ?
1524                     "(C)" : "", flagsbuf, dcep->dce_pmtu, &dcep->dce_v6addr);
1525                 break;
1526         default:
1527                 mdb_printf("%<u>%?p%3s %8s %8d %30s %</u>\n", addr, condemned ?
1528                     "(C)" : "", flagsbuf, dcep->dce_pmtu, "");
1529         }
1530 
1531         return (WALK_NEXT);
1532 }
1533 
1534 int
1535 dce(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1536 {
1537         dce_t dce;
1538         const char *opt_P = NULL;
1539         const char *zone_name = NULL;
1540         ip_stack_t *ipst = NULL;
1541         int ipversion = 0;
1542 
1543         if (mdb_getopts(argc, argv,
1544             's', MDB_OPT_STR, &zone_name,
1545             'P', MDB_OPT_STR, &opt_P, NULL) != argc)
1546                 return (DCMD_USAGE);
1547 
1548         /* Follow the specified zone name to find a ip_stack_t*. */
1549         if (zone_name != NULL) {
1550                 ipst = zone_to_ips(zone_name);
1551                 if (ipst == NULL)
1552                         return (DCMD_USAGE);
1553         }
1554 
1555         if (opt_P != NULL) {
1556                 if (strcmp("v4", opt_P) == 0) {
1557                         ipversion = IPV4_VERSION;
1558                 } else if (strcmp("v6", opt_P) == 0) {
1559                         ipversion = IPV6_VERSION;
1560                 } else {
1561                         mdb_warn("invalid protocol '%s'\n", opt_P);
1562                         return (DCMD_USAGE);
1563                 }
1564         }
1565 
1566         if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) {
1567                 mdb_printf("%<u>%?s%3s %8s %8s %30s %</u>\n",
1568                     "ADDR", "", "FLAGS", "PMTU", "DST_ADDR");
1569         }
1570 
1571         if (flags & DCMD_ADDRSPEC) {
1572                 (void) mdb_vread(&dce, sizeof (dce_t), addr);
1573                 (void) dce_format(addr, &dce, &ipversion);
1574         } else if (mdb_pwalk("dce", (mdb_walk_cb_t)dce_format, &ipversion,
1575             (uintptr_t)ipst) == -1) {
1576                 mdb_warn("failed to walk dce cache");
1577                 return (DCMD_ERR);
1578         }
1579 
1580         return (DCMD_OK);
1581 }
1582 
1583 int
1584 ire(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1585 {
1586         uint_t verbose = FALSE;
1587         ire_t ire;
1588         ire_cbdata_t ire_cb;
1589         int ipversion = 0;
1590         const char *opt_P = NULL;
1591         const char *zone_name = NULL;
1592         ip_stack_t *ipst = NULL;
1593 
1594         if (mdb_getopts(argc, argv,
1595             'v', MDB_OPT_SETBITS, TRUE, &verbose,
1596             's', MDB_OPT_STR, &zone_name,
1597             'P', MDB_OPT_STR, &opt_P, NULL) != argc)
1598                 return (DCMD_USAGE);
1599 
1600         /* Follow the specified zone name to find a ip_stack_t*. */
1601         if (zone_name != NULL) {
1602                 ipst = zone_to_ips(zone_name);
1603                 if (ipst == NULL)
1604                         return (DCMD_USAGE);
1605         }
1606 
1607         if (opt_P != NULL) {
1608                 if (strcmp("v4", opt_P) == 0) {
1609                         ipversion = IPV4_VERSION;
1610                 } else if (strcmp("v6", opt_P) == 0) {
1611                         ipversion = IPV6_VERSION;
1612                 } else {
1613                         mdb_warn("invalid protocol '%s'\n", opt_P);
1614                         return (DCMD_USAGE);
1615                 }
1616         }
1617 
1618         if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) {
1619 
1620                 if (verbose) {
1621                         mdb_printf("%?s %40s %-20s%\n"
1622                             "%?s %40s %-20s%\n"
1623                             "%<u>%?s %40s %4s %-20s %s%</u>\n",
1624                             "ADDR", "SRC", "TYPE",
1625                             "", "DST", "MARKS",
1626                             "", "STACK", "ZONE", "FLAGS", "INTF");
1627                 } else {
1628                         mdb_printf("%<u>%?s %30s %30s %5s %4s %s%</u>\n",
1629                             "ADDR", "SRC", "DST", "STACK", "ZONE", "INTF");
1630                 }
1631         }
1632 
1633         ire_cb.verbose = (verbose == TRUE);
1634         ire_cb.ire_ipversion = ipversion;
1635 
1636         if (flags & DCMD_ADDRSPEC) {
1637                 (void) mdb_vread(&ire, sizeof (ire_t), addr);
1638                 (void) ire_format(addr, &ire, &ire_cb);
1639         } else if (mdb_pwalk("ire", (mdb_walk_cb_t)ire_format, &ire_cb,
1640             (uintptr_t)ipst) == -1) {
1641                 mdb_warn("failed to walk ire table");
1642                 return (DCMD_ERR);
1643         }
1644 
1645         return (DCMD_OK);
1646 }
1647 
1648 static size_t
1649 mi_osize(const queue_t *q)
1650 {
1651         /*
1652          * The code in common/inet/mi.c allocates an extra word to store the
1653          * size of the allocation.  An mi_o_s is thus a size_t plus an mi_o_s.
1654          */
1655         struct mi_block {
1656                 size_t mi_nbytes;
1657                 struct mi_o_s mi_o;
1658         } m;
1659 
1660         if (mdb_vread(&m, sizeof (m), (uintptr_t)q->q_ptr -
1661             sizeof (m)) == sizeof (m))
1662                 return (m.mi_nbytes - sizeof (m));
1663 
1664         return (0);
1665 }
1666 
1667 static void
1668 ip_ill_qinfo(const queue_t *q, char *buf, size_t nbytes)
1669 {
1670         char name[32];
1671         ill_t ill;
1672 
1673         if (mdb_vread(&ill, sizeof (ill),
1674             (uintptr_t)q->q_ptr) == sizeof (ill) &&
1675             mdb_readstr(name, sizeof (name), (uintptr_t)ill.ill_name) > 0)
1676                 (void) mdb_snprintf(buf, nbytes, "if: %s", name);
1677 }
1678 
1679 void
1680 ip_qinfo(const queue_t *q, char *buf, size_t nbytes)
1681 {
1682         size_t size = mi_osize(q);
1683 
1684         if (size == sizeof (ill_t))
1685                 ip_ill_qinfo(q, buf, nbytes);
1686 }
1687 
1688 uintptr_t
1689 ip_rnext(const queue_t *q)
1690 {
1691         size_t size = mi_osize(q);
1692         ill_t ill;
1693 
1694         if (size == sizeof (ill_t) && mdb_vread(&ill, sizeof (ill),
1695             (uintptr_t)q->q_ptr) == sizeof (ill))
1696                 return ((uintptr_t)ill.ill_rq);
1697 
1698         return (NULL);
1699 }
1700 
1701 uintptr_t
1702 ip_wnext(const queue_t *q)
1703 {
1704         size_t size = mi_osize(q);
1705         ill_t ill;
1706 
1707         if (size == sizeof (ill_t) && mdb_vread(&ill, sizeof (ill),
1708             (uintptr_t)q->q_ptr) == sizeof (ill))
1709                 return ((uintptr_t)ill.ill_wq);
1710 
1711         return (NULL);
1712 }
1713 
1714 /*
1715  * Print the core fields in an squeue_t.  With the "-v" argument,
1716  * provide more verbose output.
1717  */
1718 static int
1719 squeue(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1720 {
1721         unsigned int    i;
1722         unsigned int    verbose = FALSE;
1723         const int       SQUEUE_STATEDELT = (int)(sizeof (uintptr_t) + 9);
1724         boolean_t       arm;
1725         squeue_t        squeue;
1726 
1727         if (!(flags & DCMD_ADDRSPEC)) {
1728                 if (mdb_walk_dcmd("genunix`squeue_cache", "ip`squeue",
1729                     argc, argv) == -1) {
1730                         mdb_warn("failed to walk squeue cache");
1731                         return (DCMD_ERR);
1732                 }
1733                 return (DCMD_OK);
1734         }
1735 
1736         if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL)
1737             != argc)
1738                 return (DCMD_USAGE);
1739 
1740         if (!DCMD_HDRSPEC(flags) && verbose)
1741                 mdb_printf("\n\n");
1742 
1743         if (DCMD_HDRSPEC(flags) || verbose) {
1744                 mdb_printf("%?s %-5s %-3s %?s %?s %?s\n",
1745                     "ADDR", "STATE", "CPU",
1746                     "FIRST", "LAST", "WORKER");
1747         }
1748 
1749         if (mdb_vread(&squeue, sizeof (squeue_t), addr) == -1) {
1750                 mdb_warn("cannot read squeue_t at %p", addr);
1751                 return (DCMD_ERR);
1752         }
1753 
1754         mdb_printf("%0?p %05x %3d %0?p %0?p %0?p\n",
1755             addr, squeue.sq_state, squeue.sq_bind,
1756             squeue.sq_first, squeue.sq_last, squeue.sq_worker);
1757 
1758         if (!verbose)
1759                 return (DCMD_OK);
1760 
1761         arm = B_TRUE;
1762         for (i = 0; squeue_states[i].bit_name != NULL; i++) {
1763                 if (((squeue.sq_state) & (1 << i)) == 0)
1764                         continue;
1765 
1766                 if (arm) {
1767                         mdb_printf("%*s|\n", SQUEUE_STATEDELT, "");
1768                         mdb_printf("%*s+-->  ", SQUEUE_STATEDELT, "");
1769                         arm = B_FALSE;
1770                 } else
1771                         mdb_printf("%*s      ", SQUEUE_STATEDELT, "");
1772 
1773                 mdb_printf("%-12s %s\n", squeue_states[i].bit_name,
1774                     squeue_states[i].bit_descr);
1775         }
1776 
1777         return (DCMD_OK);
1778 }
1779 
1780 static void
1781 ip_squeue_help(void)
1782 {
1783         mdb_printf("Print the core information for a given NCA squeue_t.\n\n");
1784         mdb_printf("Options:\n");
1785         mdb_printf("\t-v\tbe verbose (more descriptive)\n");
1786 }
1787 
1788 /*
1789  * This is called by ::th_trace (via a callback) when walking the th_hash
1790  * list.  It calls modent to find the entries.
1791  */
1792 /* ARGSUSED */
1793 static int
1794 modent_summary(uintptr_t addr, const void *data, void *private)
1795 {
1796         th_walk_data_t *thw = private;
1797         const struct mod_hash_entry *mhe = data;
1798         th_trace_t th;
1799 
1800         if (mdb_vread(&th, sizeof (th), (uintptr_t)mhe->mhe_val) == -1) {
1801                 mdb_warn("failed to read th_trace_t %p", mhe->mhe_val);
1802                 return (WALK_ERR);
1803         }
1804 
1805         if (th.th_refcnt == 0 && thw->thw_non_zero_only)
1806                 return (WALK_NEXT);
1807 
1808         if (!thw->thw_match) {
1809                 mdb_printf("%?p %?p %?p %8d %?p\n", thw->thw_ipst, mhe->mhe_key,
1810                     mhe->mhe_val, th.th_refcnt, th.th_id);
1811         } else if (thw->thw_matchkey == (uintptr_t)mhe->mhe_key) {
1812                 int i, j, k;
1813                 tr_buf_t *tr;
1814 
1815                 mdb_printf("Object %p in IP stack %p:\n", mhe->mhe_key,
1816                     thw->thw_ipst);
1817                 i = th.th_trace_lastref;
1818                 mdb_printf("\tThread %p refcnt %d:\n", th.th_id,
1819                     th.th_refcnt);
1820                 for (j = TR_BUF_MAX; j > 0; j--) {
1821                         tr = th.th_trbuf + i;
1822                         if (tr->tr_depth == 0 || tr->tr_depth > TR_STACK_DEPTH)
1823                                 break;
1824                         mdb_printf("\t  T%+ld:\n", tr->tr_time -
1825                             thw->thw_lbolt);
1826                         for (k = 0; k < tr->tr_depth; k++)
1827                                 mdb_printf("\t\t%a\n", tr->tr_stack[k]);
1828                         if (--i < 0)
1829                                 i = TR_BUF_MAX - 1;
1830                 }
1831         }
1832         return (WALK_NEXT);
1833 }
1834 
1835 /*
1836  * This is called by ::th_trace (via a callback) when walking the th_hash
1837  * list.  It calls modent to find the entries.
1838  */
1839 /* ARGSUSED */
1840 static int
1841 th_hash_summary(uintptr_t addr, const void *data, void *private)
1842 {
1843         const th_hash_t *thh = data;
1844         th_walk_data_t *thw = private;
1845 
1846         thw->thw_ipst = (uintptr_t)thh->thh_ipst;
1847         return (mdb_pwalk("modent", modent_summary, private,
1848             (uintptr_t)thh->thh_hash));
1849 }
1850 
1851 /*
1852  * Print or summarize the th_trace_t structures.
1853  */
1854 static int
1855 th_trace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1856 {
1857         th_walk_data_t thw;
1858 
1859         (void) memset(&thw, 0, sizeof (thw));
1860 
1861         if (mdb_getopts(argc, argv,
1862             'n', MDB_OPT_SETBITS, TRUE, &thw.thw_non_zero_only,
1863             NULL) != argc)
1864                 return (DCMD_USAGE);
1865 
1866         if (!(flags & DCMD_ADDRSPEC)) {
1867                 /*
1868                  * No address specified.  Walk all of the th_hash_t in the
1869                  * system, and summarize the th_trace_t entries in each.
1870                  */
1871                 mdb_printf("%?s %?s %?s %8s %?s\n",
1872                     "IPSTACK", "OBJECT", "TRACE", "REFCNT", "THREAD");
1873                 thw.thw_match = B_FALSE;
1874         } else {
1875                 thw.thw_match = B_TRUE;
1876                 thw.thw_matchkey = addr;
1877 
1878                 if ((thw.thw_lbolt = (clock_t)mdb_get_lbolt()) == -1) {
1879                         mdb_warn("failed to read lbolt");
1880                         return (DCMD_ERR);
1881                 }
1882         }
1883         if (mdb_pwalk("th_hash", th_hash_summary, &thw, NULL) == -1) {
1884                 mdb_warn("can't walk th_hash entries");
1885                 return (DCMD_ERR);
1886         }
1887         return (DCMD_OK);
1888 }
1889 
1890 static void
1891 th_trace_help(void)
1892 {
1893         mdb_printf("If given an address of an ill_t, ipif_t, ire_t, or ncec_t, "
1894             "print the\n"
1895             "corresponding th_trace_t structure in detail.  Otherwise, if no "
1896             "address is\n"
1897             "given, then summarize all th_trace_t structures.\n\n");
1898         mdb_printf("Options:\n"
1899             "\t-n\tdisplay only entries with non-zero th_refcnt\n");
1900 }
1901 
1902 static const mdb_dcmd_t dcmds[] = {
1903         { "conn_status", ":",
1904             "display connection structures from ipcl hash tables",
1905             conn_status, conn_status_help },
1906         { "srcid_status", ":",
1907             "display connection structures from ipcl hash tables",
1908             srcid_status },
1909         { "ill", "?[-v] [-P v4 | v6] [-s exclusive-ip-zone-name]",
1910             "display ill_t structures", ill, ill_help },
1911         { "illif", "?[-P v4 | v6]",
1912             "display or filter IP Lower Level InterFace structures", illif,
1913             illif_help },
1914         { "iphdr", ":[-vf]", "display an IPv4 header", iphdr },
1915         { "ip6hdr", ":[-vf]", "display an IPv6 header", ip6hdr },
1916         { "ipif", "?[-v] [-P v4 | v6]", "display ipif structures",
1917             ipif, ipif_help },
1918         { "ire", "?[-v] [-P v4|v6] [-s exclusive-ip-zone-name]",
1919             "display Internet Route Entry structures", ire },
1920         { "nce", "?[-P v4|v6] [-i <interface>]",
1921             "display interface-specific Neighbor Cache structures", nce },
1922         { "ncec", "?[-P v4 | v6]", "display Neighbor Cache Entry structures",
1923             ncec },
1924         { "dce", "?[-P v4|v6] [-s exclusive-ip-zone-name]",
1925             "display Destination Cache Entry structures", dce },
1926         { "squeue", ":[-v]", "print core squeue_t info", squeue,
1927             ip_squeue_help },
1928         { "tcphdr", ":", "display a TCP header", tcphdr },
1929         { "udphdr", ":", "display an UDP header", udphdr },
1930         { "sctphdr", ":", "display an SCTP header", sctphdr },
1931         { "th_trace", "?[-n]", "display th_trace_t structures", th_trace,
1932             th_trace_help },
1933         { NULL }
1934 };
1935 
1936 static const mdb_walker_t walkers[] = {
1937         { "conn_status", "walk list of conn_t structures",
1938                 ip_stacks_common_walk_init, conn_status_walk_step, NULL },
1939         { "illif", "walk list of ill interface types for all stacks",
1940                 ip_stacks_common_walk_init, illif_walk_step, NULL },
1941         { "illif_stack", "walk list of ill interface types",
1942                 illif_stack_walk_init, illif_stack_walk_step,
1943                 illif_stack_walk_fini },
1944         { "ill", "walk active ill_t structures for all stacks",
1945                 ill_walk_init, ill_walk_step, NULL },
1946         { "ipif", "walk list of ipif structures for all stacks",
1947                 ipif_walk_init, ipif_walk_step, NULL },
1948         { "ipif_list", "walk the linked list of ipif structures "
1949                 "for a given ill",
1950                 ip_list_walk_init, ip_list_walk_step,
1951                 ip_list_walk_fini, &ipif_walk_arg },
1952         { "srcid", "walk list of srcid_map structures for all stacks",
1953                 ip_stacks_common_walk_init, srcid_walk_step, NULL },
1954         { "srcid_list", "walk list of srcid_map structures for a stack",
1955                 ip_list_walk_init, ip_list_walk_step, ip_list_walk_fini,
1956                 &srcid_walk_arg },
1957         { "ire", "walk active ire_t structures",
1958                 ire_walk_init, ire_walk_step, NULL },
1959         { "ire_next", "walk ire_t structures in the ctable",
1960                 ire_next_walk_init, ire_next_walk_step, NULL },
1961         { "nce", "walk active nce_t structures",
1962                 nce_walk_init, nce_walk_step, NULL },
1963         { "dce", "walk active dce_t structures",
1964                 dce_walk_init, dce_walk_step, NULL },
1965         { "dccp_stacks", "walk all the dccp_stack_t",
1966                 ns_walk_init, dccp_stacks_walk_step, NULL },
1967         { "ip_stacks", "walk all the ip_stack_t",
1968                 ns_walk_init, ip_stacks_walk_step, NULL },
1969         { "tcp_stacks", "walk all the tcp_stack_t",
1970                 ns_walk_init, tcp_stacks_walk_step, NULL },
1971         { "sctp_stacks", "walk all the sctp_stack_t",
1972                 ns_walk_init, sctp_stacks_walk_step, NULL },
1973         { "udp_stacks", "walk all the udp_stack_t",
1974                 ns_walk_init, udp_stacks_walk_step, NULL },
1975         { "th_hash", "walk all the th_hash_t entries",
1976                 th_hash_walk_init, th_hash_walk_step, NULL },
1977         { "ncec", "walk list of ncec structures for all stacks",
1978                 ip_stacks_common_walk_init, ncec_walk_step, NULL },
1979         { "ncec_stack", "walk list of ncec structures",
1980                 ncec_stack_walk_init, ncec_stack_walk_step,
1981                 ncec_stack_walk_fini},
1982         { "udp_hash", "walk list of conn_t structures in ips_ipcl_udp_fanout",
1983                 ipcl_hash_walk_init, ipcl_hash_walk_step,
1984                 ipcl_hash_walk_fini, &udp_hash_arg},
1985         { "conn_hash", "walk list of conn_t structures in ips_ipcl_conn_fanout",
1986                 ipcl_hash_walk_init, ipcl_hash_walk_step,
1987                 ipcl_hash_walk_fini, &conn_hash_arg},
1988         { "bind_hash", "walk list of conn_t structures in ips_ipcl_bind_fanout",
1989                 ipcl_hash_walk_init, ipcl_hash_walk_step,
1990                 ipcl_hash_walk_fini, &bind_hash_arg},
1991         { "proto_hash", "walk list of conn_t structures in "
1992             "ips_ipcl_proto_fanout",
1993                 ipcl_hash_walk_init, ipcl_hash_walk_step,
1994                 ipcl_hash_walk_fini, &proto_hash_arg},
1995         { "proto_v6_hash", "walk list of conn_t structures in "
1996             "ips_ipcl_proto_fanout_v6",
1997                 ipcl_hash_walk_init, ipcl_hash_walk_step,
1998                 ipcl_hash_walk_fini, &proto_v6_hash_arg},
1999         { "ilb_stacks", "walk all ilb_stack_t",
2000                 ns_walk_init, ilb_stacks_walk_step, NULL },
2001         { "ilb_rules", "walk ilb rules in a given ilb_stack_t",
2002                 ilb_rules_walk_init, ilb_rules_walk_step, NULL },
2003         { "ilb_servers", "walk server in a given ilb_rule_t",
2004                 ilb_servers_walk_init, ilb_servers_walk_step, NULL },
2005         { "ilb_nat_src", "walk NAT source table of a given ilb_stack_t",
2006                 ilb_nat_src_walk_init, ilb_nat_src_walk_step,
2007                 ilb_common_walk_fini },
2008         { "ilb_conns", "walk NAT table of a given ilb_stack_t",
2009                 ilb_conn_walk_init, ilb_conn_walk_step, ilb_common_walk_fini },
2010         { "ilb_stickys", "walk sticky table of a given ilb_stack_t",
2011                 ilb_sticky_walk_init, ilb_sticky_walk_step,
2012                 ilb_common_walk_fini },
2013         { "tcps_sc", "walk all the per CPU stats counters of a tcp_stack_t",
2014                 tcps_sc_walk_init, tcps_sc_walk_step, NULL },
2015         { NULL }
2016 };
2017 
2018 static const mdb_qops_t ip_qops = { ip_qinfo, ip_rnext, ip_wnext };
2019 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
2020 
2021 const mdb_modinfo_t *
2022 _mdb_init(void)
2023 {
2024         GElf_Sym sym;
2025 
2026         if (mdb_lookup_by_obj("ip", "ipwinit", &sym) == 0)
2027                 mdb_qops_install(&ip_qops, (uintptr_t)sym.st_value);
2028 
2029         return (&modinfo);
2030 }
2031 
2032 void
2033 _mdb_fini(void)
2034 {
2035         GElf_Sym sym;
2036 
2037         if (mdb_lookup_by_obj("ip", "ipwinit", &sym) == 0)
2038                 mdb_qops_remove(&ip_qops, (uintptr_t)sym.st_value);
2039 }
2040 
2041 static char *
2042 ncec_state(int ncec_state)
2043 {
2044         switch (ncec_state) {
2045         case ND_UNCHANGED:
2046                 return ("unchanged");
2047         case ND_INCOMPLETE:
2048                 return ("incomplete");
2049         case ND_REACHABLE:
2050                 return ("reachable");
2051         case ND_STALE:
2052                 return ("stale");
2053         case ND_DELAY:
2054                 return ("delay");
2055         case ND_PROBE:
2056                 return ("probe");
2057         case ND_UNREACHABLE:
2058                 return ("unreach");
2059         case ND_INITIAL:
2060                 return ("initial");
2061         default:
2062                 return ("??");
2063         }
2064 }
2065 
2066 static char *
2067 ncec_l2_addr(const ncec_t *ncec, const ill_t *ill)
2068 {
2069         uchar_t *h;
2070         static char addr_buf[L2MAXADDRSTRLEN];
2071 
2072         if (ncec->ncec_lladdr == NULL) {
2073                 return ("None");
2074         }
2075 
2076         if (ill->ill_net_type == IRE_IF_RESOLVER) {
2077 
2078                 if (ill->ill_phys_addr_length == 0)
2079                         return ("None");
2080                 h = mdb_zalloc(ill->ill_phys_addr_length, UM_SLEEP);
2081                 if (mdb_vread(h, ill->ill_phys_addr_length,
2082                     (uintptr_t)ncec->ncec_lladdr) == -1) {
2083                         mdb_warn("failed to read hwaddr at %p",
2084                             ncec->ncec_lladdr);
2085                         return ("Unknown");
2086                 }
2087                 mdb_mac_addr(h, ill->ill_phys_addr_length,
2088                     addr_buf, sizeof (addr_buf));
2089         } else {
2090                 return ("None");
2091         }
2092         mdb_free(h, ill->ill_phys_addr_length);
2093         return (addr_buf);
2094 }
2095 
2096 static char *
2097 nce_l2_addr(const nce_t *nce, const ill_t *ill)
2098 {
2099         uchar_t *h;
2100         static char addr_buf[L2MAXADDRSTRLEN];
2101         mblk_t mp;
2102         size_t mblen;
2103 
2104         if (nce->nce_dlur_mp == NULL)
2105                 return ("None");
2106 
2107         if (ill->ill_net_type == IRE_IF_RESOLVER) {
2108                 if (mdb_vread(&mp, sizeof (mblk_t),
2109                     (uintptr_t)nce->nce_dlur_mp) == -1) {
2110                         mdb_warn("failed to read nce_dlur_mp at %p",
2111                             nce->nce_dlur_mp);
2112                         return ("None");
2113                 }
2114                 if (ill->ill_phys_addr_length == 0)
2115                         return ("None");
2116                 mblen = mp.b_wptr - mp.b_rptr;
2117                 if (mblen > (sizeof (dl_unitdata_req_t) + MAX_SAP_LEN) ||
2118                     ill->ill_phys_addr_length > MAX_SAP_LEN ||
2119                     (NCE_LL_ADDR_OFFSET(ill) +
2120                     ill->ill_phys_addr_length) > mblen) {
2121                         return ("Unknown");
2122                 }
2123                 h = mdb_zalloc(mblen, UM_SLEEP);
2124                 if (mdb_vread(h, mblen, (uintptr_t)(mp.b_rptr)) == -1) {
2125                         mdb_warn("failed to read hwaddr at %p",
2126                             mp.b_rptr + NCE_LL_ADDR_OFFSET(ill));
2127                         return ("Unknown");
2128                 }
2129                 mdb_mac_addr(h + NCE_LL_ADDR_OFFSET(ill),
2130                     ill->ill_phys_addr_length, addr_buf, sizeof (addr_buf));
2131         } else {
2132                 return ("None");
2133         }
2134         mdb_free(h, mblen);
2135         return (addr_buf);
2136 }
2137 
2138 static void
2139 ncec_header(uint_t flags)
2140 {
2141         if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) {
2142 
2143                 mdb_printf("%<u>%?s %-20s %-10s %-8s %-5s %s%</u>\n",
2144                     "ADDR", "HW_ADDR", "STATE", "FLAGS", "ILL", "IP ADDR");
2145         }
2146 }
2147 
2148 int
2149 ncec(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2150 {
2151         ncec_t ncec;
2152         ncec_cbdata_t id;
2153         int ipversion = 0;
2154         const char *opt_P = NULL;
2155 
2156         if (mdb_getopts(argc, argv,
2157             'P', MDB_OPT_STR, &opt_P, NULL) != argc)
2158                 return (DCMD_USAGE);
2159 
2160         if (opt_P != NULL) {
2161                 if (strcmp("v4", opt_P) == 0) {
2162                         ipversion = IPV4_VERSION;
2163                 } else if (strcmp("v6", opt_P) == 0) {
2164                         ipversion = IPV6_VERSION;
2165                 } else {
2166                         mdb_warn("invalid protocol '%s'\n", opt_P);
2167                         return (DCMD_USAGE);
2168                 }
2169         }
2170 
2171         if (flags & DCMD_ADDRSPEC) {
2172 
2173                 if (mdb_vread(&ncec, sizeof (ncec_t), addr) == -1) {
2174                         mdb_warn("failed to read ncec at %p\n", addr);
2175                         return (DCMD_ERR);
2176                 }
2177                 if (ipversion != 0 && ncec.ncec_ipversion != ipversion) {
2178                         mdb_printf("IP Version mismatch\n");
2179                         return (DCMD_ERR);
2180                 }
2181                 ncec_header(flags);
2182                 return (ncec_format(addr, &ncec, ipversion));
2183 
2184         } else {
2185                 id.ncec_addr = addr;
2186                 id.ncec_ipversion = ipversion;
2187                 ncec_header(flags);
2188                 if (mdb_walk("ncec", (mdb_walk_cb_t)ncec_cb, &id) == -1) {
2189                         mdb_warn("failed to walk ncec table\n");
2190                         return (DCMD_ERR);
2191                 }
2192         }
2193         return (DCMD_OK);
2194 }
2195 
2196 static int
2197 ncec_format(uintptr_t addr, const ncec_t *ncec, int ipversion)
2198 {
2199         static const mdb_bitmask_t ncec_flags[] = {
2200                 { "P",  NCE_F_NONUD,            NCE_F_NONUD },
2201                 { "R",  NCE_F_ISROUTER,         NCE_F_ISROUTER  },
2202                 { "N",  NCE_F_NONUD,            NCE_F_NONUD     },
2203                 { "A",  NCE_F_ANYCAST,          NCE_F_ANYCAST   },
2204                 { "C",  NCE_F_CONDEMNED,        NCE_F_CONDEMNED },
2205                 { "U",  NCE_F_UNSOL_ADV,        NCE_F_UNSOL_ADV },
2206                 { "B",  NCE_F_BCAST,            NCE_F_BCAST     },
2207                 { NULL, 0,                      0               }
2208         };
2209 #define NCE_MAX_FLAGS   (sizeof (ncec_flags) / sizeof (mdb_bitmask_t))
2210         struct in_addr nceaddr;
2211         ill_t ill;
2212         char ill_name[LIFNAMSIZ];
2213         char flagsbuf[NCE_MAX_FLAGS];
2214 
2215         if (mdb_vread(&ill, sizeof (ill), (uintptr_t)ncec->ncec_ill) == -1) {
2216                 mdb_warn("failed to read ncec_ill at %p",
2217                     ncec->ncec_ill);
2218                 return (DCMD_ERR);
2219         }
2220 
2221         (void) mdb_readstr(ill_name, MIN(LIFNAMSIZ, ill.ill_name_length),
2222             (uintptr_t)ill.ill_name);
2223 
2224         mdb_snprintf(flagsbuf, sizeof (flagsbuf), "%hb",
2225             ncec->ncec_flags, ncec_flags);
2226 
2227         if (ipversion != 0 && ncec->ncec_ipversion != ipversion)
2228                 return (DCMD_OK);
2229 
2230         if (ncec->ncec_ipversion == IPV4_VERSION) {
2231                 IN6_V4MAPPED_TO_INADDR(&ncec->ncec_addr, &nceaddr);
2232                 mdb_printf("%?p %-20s %-10s "
2233                     "%-8s "
2234                     "%-5s %I\n",
2235                     addr, ncec_l2_addr(ncec, &ill),
2236                     ncec_state(ncec->ncec_state),
2237                     flagsbuf,
2238                     ill_name, nceaddr.s_addr);
2239         } else {
2240                 mdb_printf("%?p %-20s %-10s %-8s %-5s %N\n",
2241                     addr,  ncec_l2_addr(ncec, &ill),
2242                     ncec_state(ncec->ncec_state),
2243                     flagsbuf,
2244                     ill_name, &ncec->ncec_addr);
2245         }
2246 
2247         return (DCMD_OK);
2248 }
2249 
2250 static uintptr_t
2251 ncec_get_next_hash_tbl(uintptr_t start, int *index, struct ndp_g_s ndp)
2252 {
2253         uintptr_t addr = start;
2254         int i = *index;
2255 
2256         while (addr == NULL) {
2257 
2258                 if (++i >= NCE_TABLE_SIZE)
2259                         break;
2260                 addr = (uintptr_t)ndp.nce_hash_tbl[i];
2261         }
2262         *index = i;
2263         return (addr);
2264 }
2265 
2266 static int
2267 ncec_walk_step(mdb_walk_state_t *wsp)
2268 {
2269         uintptr_t kaddr4, kaddr6;
2270 
2271         kaddr4 = wsp->walk_addr + OFFSETOF(ip_stack_t, ips_ndp4);
2272         kaddr6 = wsp->walk_addr + OFFSETOF(ip_stack_t, ips_ndp6);
2273 
2274         if (mdb_vread(&kaddr4, sizeof (kaddr4), kaddr4) == -1) {
2275                 mdb_warn("can't read ips_ip_cache_table at %p", kaddr4);
2276                 return (WALK_ERR);
2277         }
2278         if (mdb_vread(&kaddr6, sizeof (kaddr6), kaddr6) == -1) {
2279                 mdb_warn("can't read ips_ip_cache_table at %p", kaddr6);
2280                 return (WALK_ERR);
2281         }
2282         if (mdb_pwalk("ncec_stack", wsp->walk_callback, wsp->walk_cbdata,
2283             kaddr4) == -1) {
2284                 mdb_warn("couldn't walk 'ncec_stack' for ips_ndp4 %p",
2285                     kaddr4);
2286                 return (WALK_ERR);
2287         }
2288         if (mdb_pwalk("ncec_stack", wsp->walk_callback,
2289             wsp->walk_cbdata, kaddr6) == -1) {
2290                 mdb_warn("couldn't walk 'ncec_stack' for ips_ndp6 %p",
2291                     kaddr6);
2292                 return (WALK_ERR);
2293         }
2294         return (WALK_NEXT);
2295 }
2296 
2297 static uintptr_t
2298 ipcl_hash_get_next_connf_tbl(ipcl_hash_walk_data_t *iw)
2299 {
2300         struct connf_s connf;
2301         uintptr_t addr = NULL, next;
2302         int index = iw->connf_tbl_index;
2303 
2304         do {
2305                 next = iw->hash_tbl + index * sizeof (struct connf_s);
2306                 if (++index >= iw->hash_tbl_size) {
2307                         addr = NULL;
2308                         break;
2309                 }
2310                 if (mdb_vread(&connf, sizeof (struct connf_s), next) == -1)  {
2311                         mdb_warn("failed to read conn_t at %p", next);
2312                         return (NULL);
2313                 }
2314                 addr = (uintptr_t)connf.connf_head;
2315         } while (addr == NULL);
2316         iw->connf_tbl_index = index;
2317         return (addr);
2318 }
2319 
2320 static int
2321 ipcl_hash_walk_init(mdb_walk_state_t *wsp)
2322 {
2323         const hash_walk_arg_t *arg = wsp->walk_arg;
2324         ipcl_hash_walk_data_t *iw;
2325         uintptr_t tbladdr;
2326         uintptr_t sizeaddr;
2327 
2328         iw = mdb_alloc(sizeof (ipcl_hash_walk_data_t), UM_SLEEP);
2329         iw->conn = mdb_alloc(sizeof (conn_t), UM_SLEEP);
2330         tbladdr = wsp->walk_addr + arg->tbl_off;
2331         sizeaddr = wsp->walk_addr + arg->size_off;
2332 
2333         if (mdb_vread(&iw->hash_tbl, sizeof (uintptr_t), tbladdr) == -1) {
2334                 mdb_warn("can't read fanout table addr at %p", tbladdr);
2335                 mdb_free(iw->conn, sizeof (conn_t));
2336                 mdb_free(iw, sizeof (ipcl_hash_walk_data_t));
2337                 return (WALK_ERR);
2338         }
2339         if (arg->tbl_off == OFFSETOF(ip_stack_t, ips_ipcl_proto_fanout_v4) ||
2340             arg->tbl_off == OFFSETOF(ip_stack_t, ips_ipcl_proto_fanout_v6)) {
2341                 iw->hash_tbl_size = IPPROTO_MAX;
2342         } else {
2343                 if (mdb_vread(&iw->hash_tbl_size, sizeof (int),
2344                     sizeaddr) == -1) {
2345                         mdb_warn("can't read fanout table size addr at %p",
2346                             sizeaddr);
2347                         mdb_free(iw->conn, sizeof (conn_t));
2348                         mdb_free(iw, sizeof (ipcl_hash_walk_data_t));
2349                         return (WALK_ERR);
2350                 }
2351         }
2352         iw->connf_tbl_index = 0;
2353         wsp->walk_addr = ipcl_hash_get_next_connf_tbl(iw);
2354         wsp->walk_data = iw;
2355 
2356         if (wsp->walk_addr != NULL)
2357                 return (WALK_NEXT);
2358         else
2359                 return (WALK_DONE);
2360 }
2361 
2362 static int
2363 ipcl_hash_walk_step(mdb_walk_state_t *wsp)
2364 {
2365         uintptr_t addr = wsp->walk_addr;
2366         ipcl_hash_walk_data_t *iw = wsp->walk_data;
2367         conn_t *conn = iw->conn;
2368         int ret = WALK_DONE;
2369 
2370         while (addr != NULL) {
2371                 if (mdb_vread(conn, sizeof (conn_t), addr) == -1) {
2372                         mdb_warn("failed to read conn_t at %p", addr);
2373                         return (WALK_ERR);
2374                 }
2375                 ret = wsp->walk_callback(addr, iw, wsp->walk_cbdata);
2376                 if (ret != WALK_NEXT)
2377                         break;
2378                 addr = (uintptr_t)conn->conn_next;
2379         }
2380         if (ret == WALK_NEXT) {
2381                 wsp->walk_addr = ipcl_hash_get_next_connf_tbl(iw);
2382 
2383                 if (wsp->walk_addr != NULL)
2384                         return (WALK_NEXT);
2385                 else
2386                         return (WALK_DONE);
2387         }
2388 
2389         return (ret);
2390 }
2391 
2392 static void
2393 ipcl_hash_walk_fini(mdb_walk_state_t *wsp)
2394 {
2395         ipcl_hash_walk_data_t *iw = wsp->walk_data;
2396 
2397         mdb_free(iw->conn, sizeof (conn_t));
2398         mdb_free(iw, sizeof (ipcl_hash_walk_data_t));
2399 }
2400 
2401 /*
2402  * Called with walk_addr being the address of ips_ndp{4,6}
2403  */
2404 static int
2405 ncec_stack_walk_init(mdb_walk_state_t *wsp)
2406 {
2407         ncec_walk_data_t *nw;
2408 
2409         if (wsp->walk_addr == NULL) {
2410                 mdb_warn("ncec_stack requires ndp_g_s address\n");
2411                 return (WALK_ERR);
2412         }
2413 
2414         nw = mdb_alloc(sizeof (ncec_walk_data_t), UM_SLEEP);
2415 
2416         if (mdb_vread(&nw->ncec_ip_ndp, sizeof (struct ndp_g_s),
2417             wsp->walk_addr) == -1) {
2418                 mdb_warn("failed to read 'ip_ndp' at %p",
2419                     wsp->walk_addr);
2420                 mdb_free(nw, sizeof (ncec_walk_data_t));
2421                 return (WALK_ERR);
2422         }
2423 
2424         /*
2425          * ncec_get_next_hash_tbl() starts at ++i , so initialize index to -1
2426          */
2427         nw->ncec_hash_tbl_index = -1;
2428         wsp->walk_addr = ncec_get_next_hash_tbl(NULL,
2429             &nw->ncec_hash_tbl_index, nw->ncec_ip_ndp);
2430         wsp->walk_data = nw;
2431 
2432         return (WALK_NEXT);
2433 }
2434 
2435 static int
2436 ncec_stack_walk_step(mdb_walk_state_t *wsp)
2437 {
2438         uintptr_t addr = wsp->walk_addr;
2439         ncec_walk_data_t *nw = wsp->walk_data;
2440 
2441         if (addr == NULL)
2442                 return (WALK_DONE);
2443 
2444         if (mdb_vread(&nw->ncec, sizeof (ncec_t), addr) == -1) {
2445                 mdb_warn("failed to read ncec_t at %p", addr);
2446                 return (WALK_ERR);
2447         }
2448 
2449         wsp->walk_addr = (uintptr_t)nw->ncec.ncec_next;
2450 
2451         wsp->walk_addr = ncec_get_next_hash_tbl(wsp->walk_addr,
2452             &nw->ncec_hash_tbl_index, nw->ncec_ip_ndp);
2453 
2454         return (wsp->walk_callback(addr, nw, wsp->walk_cbdata));
2455 }
2456 
2457 static void
2458 ncec_stack_walk_fini(mdb_walk_state_t *wsp)
2459 {
2460         mdb_free(wsp->walk_data, sizeof (ncec_walk_data_t));
2461 }
2462 
2463 /* ARGSUSED */
2464 static int
2465 ncec_cb(uintptr_t addr, const ncec_walk_data_t *iw, ncec_cbdata_t *id)
2466 {
2467         ncec_t ncec;
2468 
2469         if (mdb_vread(&ncec, sizeof (ncec_t), addr) == -1) {
2470                 mdb_warn("failed to read ncec at %p", addr);
2471                 return (WALK_NEXT);
2472         }
2473         (void) ncec_format(addr, &ncec, id->ncec_ipversion);
2474         return (WALK_NEXT);
2475 }
2476 
2477 static int
2478 ill_walk_init(mdb_walk_state_t *wsp)
2479 {
2480         if (mdb_layered_walk("illif", wsp) == -1) {
2481                 mdb_warn("can't walk 'illif'");
2482                 return (WALK_ERR);
2483         }
2484         return (WALK_NEXT);
2485 }
2486 
2487 static int
2488 ill_walk_step(mdb_walk_state_t *wsp)
2489 {
2490         ill_if_t ill_if;
2491 
2492         if (mdb_vread(&ill_if, sizeof (ill_if_t), wsp->walk_addr) == -1) {
2493                 mdb_warn("can't read ill_if_t at %p", wsp->walk_addr);
2494                 return (WALK_ERR);
2495         }
2496         wsp->walk_addr = (uintptr_t)(wsp->walk_addr +
2497             offsetof(ill_if_t, illif_avl_by_ppa));
2498         if (mdb_pwalk("avl", wsp->walk_callback, wsp->walk_cbdata,
2499             wsp->walk_addr) == -1) {
2500                 mdb_warn("can't walk 'avl'");
2501                 return (WALK_ERR);
2502         }
2503 
2504         return (WALK_NEXT);
2505 }
2506 
2507 /* ARGSUSED */
2508 static int
2509 ill_cb(uintptr_t addr, const ill_walk_data_t *iw, ill_cbdata_t *id)
2510 {
2511         ill_t ill;
2512 
2513         if (mdb_vread(&ill, sizeof (ill_t), (uintptr_t)addr) == -1) {
2514                 mdb_warn("failed to read ill at %p", addr);
2515                 return (WALK_NEXT);
2516         }
2517 
2518         /* If ip_stack_t is specified, skip ILLs that don't belong to it. */
2519         if (id->ill_ipst != NULL && ill.ill_ipst != id->ill_ipst)
2520                 return (WALK_NEXT);
2521 
2522         return (ill_format((uintptr_t)addr, &ill, id));
2523 }
2524 
2525 static void
2526 ill_header(boolean_t verbose)
2527 {
2528         if (verbose) {
2529                 mdb_printf("%-?s %-8s %3s %-10s %-?s %-?s %-10s%</u>\n",
2530                     "ADDR", "NAME", "VER", "TYPE", "WQ", "IPST", "FLAGS");
2531                 mdb_printf("%-?s %4s%4s %-?s\n",
2532                     "PHYINT", "CNT", "", "GROUP");
2533                 mdb_printf("%<u>%80s%</u>\n", "");
2534         } else {
2535                 mdb_printf("%<u>%-?s %-8s %-3s %-10s %4s %-?s %-10s%</u>\n",
2536                     "ADDR", "NAME", "VER", "TYPE", "CNT", "WQ", "FLAGS");
2537         }
2538 }
2539 
2540 static int
2541 ill_format(uintptr_t addr, const void *illptr, void *ill_cb_arg)
2542 {
2543         ill_t *ill = (ill_t *)illptr;
2544         ill_cbdata_t *illcb = ill_cb_arg;
2545         boolean_t verbose = illcb->verbose;
2546         phyint_t phyi;
2547         static const mdb_bitmask_t fmasks[] = {
2548                 { "R",          PHYI_RUNNING,           PHYI_RUNNING    },
2549                 { "P",          PHYI_PROMISC,           PHYI_PROMISC    },
2550                 { "V",          PHYI_VIRTUAL,           PHYI_VIRTUAL    },
2551                 { "I",          PHYI_IPMP,              PHYI_IPMP       },
2552                 { "f",          PHYI_FAILED,            PHYI_FAILED     },
2553                 { "S",          PHYI_STANDBY,           PHYI_STANDBY    },
2554                 { "i",          PHYI_INACTIVE,          PHYI_INACTIVE   },
2555                 { "O",          PHYI_OFFLINE,           PHYI_OFFLINE    },
2556                 { "T",          ILLF_NOTRAILERS,        ILLF_NOTRAILERS },
2557                 { "A",          ILLF_NOARP,             ILLF_NOARP      },
2558                 { "M",          ILLF_MULTICAST,         ILLF_MULTICAST  },
2559                 { "F",          ILLF_ROUTER,            ILLF_ROUTER     },
2560                 { "D",          ILLF_NONUD,             ILLF_NONUD      },
2561                 { "X",          ILLF_NORTEXCH,          ILLF_NORTEXCH   },
2562                 { NULL,         0,                      0               }
2563         };
2564         static const mdb_bitmask_t v_fmasks[] = {
2565                 { "RUNNING",    PHYI_RUNNING,           PHYI_RUNNING    },
2566                 { "PROMISC",    PHYI_PROMISC,           PHYI_PROMISC    },
2567                 { "VIRTUAL",    PHYI_VIRTUAL,           PHYI_VIRTUAL    },
2568                 { "IPMP",       PHYI_IPMP,              PHYI_IPMP       },
2569                 { "FAILED",     PHYI_FAILED,            PHYI_FAILED     },
2570                 { "STANDBY",    PHYI_STANDBY,           PHYI_STANDBY    },
2571                 { "INACTIVE",   PHYI_INACTIVE,          PHYI_INACTIVE   },
2572                 { "OFFLINE",    PHYI_OFFLINE,           PHYI_OFFLINE    },
2573                 { "NOTRAILER",  ILLF_NOTRAILERS,        ILLF_NOTRAILERS },
2574                 { "NOARP",      ILLF_NOARP,             ILLF_NOARP      },
2575                 { "MULTICAST",  ILLF_MULTICAST,         ILLF_MULTICAST  },
2576                 { "ROUTER",     ILLF_ROUTER,            ILLF_ROUTER     },
2577                 { "NONUD",      ILLF_NONUD,             ILLF_NONUD      },
2578                 { "NORTEXCH",   ILLF_NORTEXCH,          ILLF_NORTEXCH   },
2579                 { NULL,         0,                      0               }
2580         };
2581         char ill_name[LIFNAMSIZ];
2582         int cnt;
2583         char *typebuf;
2584         char sbuf[DEFCOLS];
2585         int ipver = illcb->ill_ipversion;
2586 
2587         if (ipver != 0) {
2588                 if ((ipver == IPV4_VERSION && ill->ill_isv6) ||
2589                     (ipver == IPV6_VERSION && !ill->ill_isv6)) {
2590                         return (WALK_NEXT);
2591                 }
2592         }
2593         if (mdb_vread(&phyi, sizeof (phyint_t),
2594             (uintptr_t)ill->ill_phyint) == -1) {
2595                 mdb_warn("failed to read ill_phyint at %p",
2596                     (uintptr_t)ill->ill_phyint);
2597                 return (WALK_NEXT);
2598         }
2599         (void) mdb_readstr(ill_name, MIN(LIFNAMSIZ, ill->ill_name_length),
2600             (uintptr_t)ill->ill_name);
2601 
2602         switch (ill->ill_type) {
2603         case 0:
2604                 typebuf = "LOOPBACK";
2605                 break;
2606         case IFT_ETHER:
2607                 typebuf = "ETHER";
2608                 break;
2609         case IFT_OTHER:
2610                 typebuf = "OTHER";
2611                 break;
2612         default:
2613                 typebuf = NULL;
2614                 break;
2615         }
2616         cnt = ill->ill_refcnt + ill->ill_ire_cnt + ill->ill_nce_cnt +
2617             ill->ill_ilm_cnt + ill->ill_ncec_cnt;
2618         mdb_printf("%-?p %-8s %-3s ",
2619             addr, ill_name, ill->ill_isv6 ? "v6" : "v4");
2620         if (typebuf != NULL)
2621                 mdb_printf("%-10s ", typebuf);
2622         else
2623                 mdb_printf("%-10x ", ill->ill_type);
2624         if (verbose) {
2625                 mdb_printf("%-?p %-?p %-llb\n",
2626                     ill->ill_wq, ill->ill_ipst,
2627                     ill->ill_flags | phyi.phyint_flags, v_fmasks);
2628                 mdb_printf("%-?p %4d%4s %-?p\n",
2629                     ill->ill_phyint, cnt, "", ill->ill_grp);
2630                 mdb_snprintf(sbuf, sizeof (sbuf), "%*s %3s",
2631                     sizeof (uintptr_t) * 2, "", "");
2632                 mdb_printf("%s|\n%s+--> %3d %-18s "
2633                     "references from active threads\n",
2634                     sbuf, sbuf, ill->ill_refcnt, "ill_refcnt");
2635                 mdb_printf("%*s %7d %-18s ires referencing this ill\n",
2636                     strlen(sbuf), "", ill->ill_ire_cnt, "ill_ire_cnt");
2637                 mdb_printf("%*s %7d %-18s nces referencing this ill\n",
2638                     strlen(sbuf), "", ill->ill_nce_cnt, "ill_nce_cnt");
2639                 mdb_printf("%*s %7d %-18s ncecs referencing this ill\n",
2640                     strlen(sbuf), "", ill->ill_ncec_cnt, "ill_ncec_cnt");
2641                 mdb_printf("%*s %7d %-18s ilms referencing this ill\n",
2642                     strlen(sbuf), "", ill->ill_ilm_cnt, "ill_ilm_cnt");
2643         } else {
2644                 mdb_printf("%4d %-?p %-llb\n",
2645                     cnt, ill->ill_wq,
2646                     ill->ill_flags | phyi.phyint_flags, fmasks);
2647         }
2648         return (WALK_NEXT);
2649 }
2650 
2651 static int
2652 ill(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2653 {
2654         ill_t ill_data;
2655         ill_cbdata_t id;
2656         int ipversion = 0;
2657         const char *zone_name = NULL;
2658         const char *opt_P = NULL;
2659         uint_t verbose = FALSE;
2660         ip_stack_t *ipst = NULL;
2661 
2662         if (mdb_getopts(argc, argv,
2663             'v', MDB_OPT_SETBITS, TRUE, &verbose,
2664             's', MDB_OPT_STR, &zone_name,
2665             'P', MDB_OPT_STR, &opt_P, NULL) != argc)
2666                 return (DCMD_USAGE);
2667 
2668         /* Follow the specified zone name to find a ip_stack_t*. */
2669         if (zone_name != NULL) {
2670                 ipst = zone_to_ips(zone_name);
2671                 if (ipst == NULL)
2672                         return (DCMD_USAGE);
2673         }
2674 
2675         if (opt_P != NULL) {
2676                 if (strcmp("v4", opt_P) == 0) {
2677                         ipversion = IPV4_VERSION;
2678                 } else if (strcmp("v6", opt_P) == 0) {
2679                         ipversion = IPV6_VERSION;
2680                 } else {
2681                         mdb_warn("invalid protocol '%s'\n", opt_P);
2682                         return (DCMD_USAGE);
2683                 }
2684         }
2685 
2686         id.verbose = verbose;
2687         id.ill_addr = addr;
2688         id.ill_ipversion = ipversion;
2689         id.ill_ipst = ipst;
2690 
2691         ill_header(verbose);
2692         if (flags & DCMD_ADDRSPEC) {
2693                 if (mdb_vread(&ill_data, sizeof (ill_t), addr) == -1) {
2694                         mdb_warn("failed to read ill at %p\n", addr);
2695                         return (DCMD_ERR);
2696                 }
2697                 (void) ill_format(addr, &ill_data, &id);
2698         } else {
2699                 if (mdb_walk("ill", (mdb_walk_cb_t)ill_cb, &id) == -1) {
2700                         mdb_warn("failed to walk ills\n");
2701                         return (DCMD_ERR);
2702                 }
2703         }
2704         return (DCMD_OK);
2705 }
2706 
2707 static void
2708 ill_help(void)
2709 {
2710         mdb_printf("Prints the following fields: ill ptr, name, "
2711             "IP version, count, ill type and ill flags.\n"
2712             "The count field is a sum of individual refcnts and is expanded "
2713             "with the -v option.\n\n");
2714         mdb_printf("Options:\n");
2715         mdb_printf("\t-P v4 | v6"
2716             "\tfilter ill structures for the specified protocol\n");
2717 }
2718 
2719 static int
2720 ip_list_walk_init(mdb_walk_state_t *wsp)
2721 {
2722         const ip_list_walk_arg_t *arg = wsp->walk_arg;
2723         ip_list_walk_data_t *iw;
2724         uintptr_t addr = (uintptr_t)(wsp->walk_addr + arg->off);
2725 
2726         if (wsp->walk_addr == NULL) {
2727                 mdb_warn("only local walks supported\n");
2728                 return (WALK_ERR);
2729         }
2730         if (mdb_vread(&wsp->walk_addr, sizeof (uintptr_t),
2731             addr) == -1) {
2732                 mdb_warn("failed to read list head at %p", addr);
2733                 return (WALK_ERR);
2734         }
2735         iw = mdb_alloc(sizeof (ip_list_walk_data_t), UM_SLEEP);
2736         iw->nextoff = arg->nextp_off;
2737         wsp->walk_data = iw;
2738 
2739         return (WALK_NEXT);
2740 }
2741 
2742 static int
2743 ip_list_walk_step(mdb_walk_state_t *wsp)
2744 {
2745         ip_list_walk_data_t *iw = wsp->walk_data;
2746         uintptr_t addr = wsp->walk_addr;
2747 
2748         if (addr == NULL)
2749                 return (WALK_DONE);
2750         wsp->walk_addr = addr + iw->nextoff;
2751         if (mdb_vread(&wsp->walk_addr, sizeof (uintptr_t),
2752             wsp->walk_addr) == -1) {
2753                 mdb_warn("failed to read list node at %p", addr);
2754                 return (WALK_ERR);
2755         }
2756         return (wsp->walk_callback(addr, iw, wsp->walk_cbdata));
2757 }
2758 
2759 static void
2760 ip_list_walk_fini(mdb_walk_state_t *wsp)
2761 {
2762         mdb_free(wsp->walk_data, sizeof (ip_list_walk_data_t));
2763 }
2764 
2765 static int
2766 ipif_walk_init(mdb_walk_state_t *wsp)
2767 {
2768         if (mdb_layered_walk("ill", wsp) == -1) {
2769                 mdb_warn("can't walk 'ills'");
2770                 return (WALK_ERR);
2771         }
2772         return (WALK_NEXT);
2773 }
2774 
2775 static int
2776 ipif_walk_step(mdb_walk_state_t *wsp)
2777 {
2778         if (mdb_pwalk("ipif_list", wsp->walk_callback, wsp->walk_cbdata,
2779             wsp->walk_addr) == -1) {
2780                 mdb_warn("can't walk 'ipif_list'");
2781                 return (WALK_ERR);
2782         }
2783 
2784         return (WALK_NEXT);
2785 }
2786 
2787 /* ARGSUSED */
2788 static int
2789 ipif_cb(uintptr_t addr, const ipif_walk_data_t *iw, ipif_cbdata_t *id)
2790 {
2791         ipif_t ipif;
2792 
2793         if (mdb_vread(&ipif, sizeof (ipif_t), (uintptr_t)addr) == -1) {
2794                 mdb_warn("failed to read ipif at %p", addr);
2795                 return (WALK_NEXT);
2796         }
2797         if (mdb_vread(&id->ill, sizeof (ill_t),
2798             (uintptr_t)ipif.ipif_ill) == -1) {
2799                 mdb_warn("failed to read ill at %p", ipif.ipif_ill);
2800                 return (WALK_NEXT);
2801         }
2802         (void) ipif_format((uintptr_t)addr, &ipif, id);
2803         return (WALK_NEXT);
2804 }
2805 
2806 static void
2807 ipif_header(boolean_t verbose)
2808 {
2809         if (verbose) {
2810                 mdb_printf("%-?s %-10s %-3s %-?s %-8s %-30s\n",
2811                     "ADDR", "NAME", "CNT", "ILL", "STFLAGS", "FLAGS");
2812                 mdb_printf("%s\n%s\n",
2813                     "LCLADDR", "BROADCAST");
2814                 mdb_printf("%<u>%80s%</u>\n", "");
2815         } else {
2816                 mdb_printf("%-?s %-10s %6s %-?s %-8s %-30s\n",
2817                     "ADDR", "NAME", "CNT", "ILL", "STFLAGS", "FLAGS");
2818                 mdb_printf("%s\n%<u>%80s%</u>\n", "LCLADDR", "");
2819         }
2820 }
2821 
2822 #ifdef _BIG_ENDIAN
2823 #define ip_ntohl_32(x)  ((x) & 0xffffffff)
2824 #else
2825 #define ip_ntohl_32(x)  (((uint32_t)(x) << 24) | \
2826                         (((uint32_t)(x) << 8) & 0xff0000) | \
2827                         (((uint32_t)(x) >> 8) & 0xff00) | \
2828                         ((uint32_t)(x)  >> 24))
2829 #endif
2830 
2831 int
2832 mask_to_prefixlen(int af, const in6_addr_t *addr)
2833 {
2834         int len = 0;
2835         int i;
2836         uint_t mask = 0;
2837 
2838         if (af == AF_INET6) {
2839                 for (i = 0; i < 4; i++) {
2840                         if (addr->s6_addr32[i] == 0xffffffff) {
2841                                 len += 32;
2842                         } else {
2843                                 mask = addr->s6_addr32[i];
2844                                 break;
2845                         }
2846                 }
2847         } else {
2848                 mask = V4_PART_OF_V6((*addr));
2849         }
2850         if (mask > 0)
2851                 len += (33 - mdb_ffs(ip_ntohl_32(mask)));
2852         return (len);
2853 }
2854 
2855 static int
2856 ipif_format(uintptr_t addr, const void *ipifptr, void *ipif_cb_arg)
2857 {
2858         const ipif_t *ipif = ipifptr;
2859         ipif_cbdata_t *ipifcb = ipif_cb_arg;
2860         boolean_t verbose = ipifcb->verbose;
2861         char ill_name[LIFNAMSIZ];
2862         char buf[LIFNAMSIZ];
2863         int cnt;
2864         static const mdb_bitmask_t sfmasks[] = {
2865                 { "CO",         IPIF_CONDEMNED,         IPIF_CONDEMNED},
2866                 { "CH",         IPIF_CHANGING,          IPIF_CHANGING},
2867                 { "SL",         IPIF_SET_LINKLOCAL,     IPIF_SET_LINKLOCAL},
2868                 { NULL,         0,                      0               }
2869         };
2870         static const mdb_bitmask_t fmasks[] = {
2871                 { "UP",         IPIF_UP,                IPIF_UP         },
2872                 { "UNN",        IPIF_UNNUMBERED,        IPIF_UNNUMBERED},
2873                 { "DHCP",       IPIF_DHCPRUNNING,       IPIF_DHCPRUNNING},
2874                 { "PRIV",       IPIF_PRIVATE,           IPIF_PRIVATE},
2875                 { "NOXMT",      IPIF_NOXMIT,            IPIF_NOXMIT},
2876                 { "NOLCL",      IPIF_NOLOCAL,           IPIF_NOLOCAL},
2877                 { "DEPR",       IPIF_DEPRECATED,        IPIF_DEPRECATED},
2878                 { "PREF",       IPIF_PREFERRED,         IPIF_PREFERRED},
2879                 { "TEMP",       IPIF_TEMPORARY,         IPIF_TEMPORARY},
2880                 { "ACONF",      IPIF_ADDRCONF,          IPIF_ADDRCONF},
2881                 { "ANY",        IPIF_ANYCAST,           IPIF_ANYCAST},
2882                 { "NFAIL",      IPIF_NOFAILOVER,        IPIF_NOFAILOVER},
2883                 { NULL,         0,                      0               }
2884         };
2885         char flagsbuf[2 * A_CNT(fmasks)];
2886         char bitfields[A_CNT(fmasks)];
2887         char sflagsbuf[A_CNT(sfmasks)];
2888         char sbuf[DEFCOLS], addrstr[INET6_ADDRSTRLEN];
2889         int ipver = ipifcb->ipif_ipversion;
2890         int af;
2891 
2892         if (ipver != 0) {
2893                 if ((ipver == IPV4_VERSION && ipifcb->ill.ill_isv6) ||
2894                     (ipver == IPV6_VERSION && !ipifcb->ill.ill_isv6)) {
2895                         return (WALK_NEXT);
2896                 }
2897         }
2898         if ((mdb_readstr(ill_name, MIN(LIFNAMSIZ,
2899             ipifcb->ill.ill_name_length),
2900             (uintptr_t)ipifcb->ill.ill_name)) == -1) {
2901                 mdb_warn("failed to read ill_name of ill %p\n", ipifcb->ill);
2902                 return (WALK_NEXT);
2903         }
2904         if (ipif->ipif_id != 0) {
2905                 mdb_snprintf(buf, LIFNAMSIZ, "%s:%d",
2906                     ill_name, ipif->ipif_id);
2907         } else {
2908                 mdb_snprintf(buf, LIFNAMSIZ, "%s", ill_name);
2909         }
2910         mdb_snprintf(bitfields, sizeof (bitfields), "%s",
2911             ipif->ipif_addr_ready ? ",ADR" : "",
2912             ipif->ipif_was_up ? ",WU" : "",
2913             ipif->ipif_was_dup ? ",WD" : "");
2914         mdb_snprintf(flagsbuf, sizeof (flagsbuf), "%llb%s",
2915             ipif->ipif_flags, fmasks, bitfields);
2916         mdb_snprintf(sflagsbuf, sizeof (sflagsbuf), "%b",
2917             ipif->ipif_state_flags, sfmasks);
2918 
2919         cnt = ipif->ipif_refcnt;
2920 
2921         if (ipifcb->ill.ill_isv6) {
2922                 mdb_snprintf(addrstr, sizeof (addrstr), "%N",
2923                     &ipif->ipif_v6lcl_addr);
2924                 af = AF_INET6;
2925         } else {
2926                 mdb_snprintf(addrstr, sizeof (addrstr), "%I",
2927                     V4_PART_OF_V6((ipif->ipif_v6lcl_addr)));
2928                 af = AF_INET;
2929         }
2930 
2931         if (verbose) {
2932                 mdb_printf("%-?p %-10s %3d %-?p %-8s %-30s\n",
2933                     addr, buf, cnt, ipif->ipif_ill,
2934                     sflagsbuf, flagsbuf);
2935                 mdb_snprintf(sbuf, sizeof (sbuf), "%*s %12s",
2936                     sizeof (uintptr_t) * 2, "", "");
2937                 mdb_printf("%s |\n%s +---> %4d %-15s "
2938                     "Active consistent reader cnt\n",
2939                     sbuf, sbuf, ipif->ipif_refcnt, "ipif_refcnt");
2940                 mdb_printf("%-s/%d\n",
2941                     addrstr, mask_to_prefixlen(af, &ipif->ipif_v6net_mask));
2942                 if (ipifcb->ill.ill_isv6) {
2943                         mdb_printf("%-N\n", &ipif->ipif_v6brd_addr);
2944                 } else {
2945                         mdb_printf("%-I\n",
2946                             V4_PART_OF_V6((ipif->ipif_v6brd_addr)));
2947                 }
2948         } else {
2949                 mdb_printf("%-?p %-10s %6d %-?p %-8s %-30s\n",
2950                     addr, buf, cnt, ipif->ipif_ill,
2951                     sflagsbuf, flagsbuf);
2952                 mdb_printf("%-s/%d\n",
2953                     addrstr, mask_to_prefixlen(af, &ipif->ipif_v6net_mask));
2954         }
2955 
2956         return (WALK_NEXT);
2957 }
2958 
2959 static int
2960 ipif(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2961 {
2962         ipif_t ipif;
2963         ipif_cbdata_t id;
2964         int ipversion = 0;
2965         const char *opt_P = NULL;
2966         uint_t verbose = FALSE;
2967 
2968         if (mdb_getopts(argc, argv,
2969             'v', MDB_OPT_SETBITS, TRUE, &verbose,
2970             'P', MDB_OPT_STR, &opt_P, NULL) != argc)
2971                 return (DCMD_USAGE);
2972 
2973         if (opt_P != NULL) {
2974                 if (strcmp("v4", opt_P) == 0) {
2975                         ipversion = IPV4_VERSION;
2976                 } else if (strcmp("v6", opt_P) == 0) {
2977                         ipversion = IPV6_VERSION;
2978                 } else {
2979                         mdb_warn("invalid protocol '%s'\n", opt_P);
2980                         return (DCMD_USAGE);
2981                 }
2982         }
2983 
2984         id.verbose = verbose;
2985         id.ipif_ipversion = ipversion;
2986 
2987         if (flags & DCMD_ADDRSPEC) {
2988                 if (mdb_vread(&ipif, sizeof (ipif_t), addr) == -1) {
2989                         mdb_warn("failed to read ipif at %p\n", addr);
2990                         return (DCMD_ERR);
2991                 }
2992                 ipif_header(verbose);
2993                 if (mdb_vread(&id.ill, sizeof (ill_t),
2994                     (uintptr_t)ipif.ipif_ill) == -1) {
2995                         mdb_warn("failed to read ill at %p", ipif.ipif_ill);
2996                         return (WALK_NEXT);
2997                 }
2998                 return (ipif_format(addr, &ipif, &id));
2999         } else {
3000                 ipif_header(verbose);
3001                 if (mdb_walk("ipif", (mdb_walk_cb_t)ipif_cb, &id) == -1) {
3002                         mdb_warn("failed to walk ipifs\n");
3003                         return (DCMD_ERR);
3004                 }
3005         }
3006         return (DCMD_OK);
3007 }
3008 
3009 static void
3010 ipif_help(void)
3011 {
3012         mdb_printf("Prints the following fields: ipif ptr, name, "
3013             "count, ill ptr, state flags and ipif flags.\n"
3014             "The count field is a sum of individual refcnts and is expanded "
3015             "with the -v option.\n"
3016             "The flags field shows the following:"
3017             "\n\tUNN -> UNNUMBERED, DHCP -> DHCPRUNNING, PRIV -> PRIVATE, "
3018             "\n\tNOXMT -> NOXMIT, NOLCL -> NOLOCAL, DEPR -> DEPRECATED, "
3019             "\n\tPREF -> PREFERRED, TEMP -> TEMPORARY, ACONF -> ADDRCONF, "
3020             "\n\tANY -> ANYCAST, NFAIL -> NOFAILOVER, "
3021             "\n\tADR -> ipif_addr_ready, MU -> ipif_multicast_up, "
3022             "\n\tWU -> ipif_was_up, WD -> ipif_was_dup, "
3023             "JA -> ipif_joined_allhosts.\n\n");
3024         mdb_printf("Options:\n");
3025         mdb_printf("\t-P v4 | v6"
3026             "\tfilter ipif structures on ills for the specified protocol\n");
3027 }
3028 
3029 static int
3030 conn_status_walk_fanout(uintptr_t addr, mdb_walk_state_t *wsp,
3031     const char *walkname)
3032 {
3033         if (mdb_pwalk(walkname, wsp->walk_callback, wsp->walk_cbdata,
3034             addr) == -1) {
3035                 mdb_warn("couldn't walk '%s' at %p", walkname, addr);
3036                 return (WALK_ERR);
3037         }
3038         return (WALK_NEXT);
3039 }
3040 
3041 static int
3042 conn_status_walk_step(mdb_walk_state_t *wsp)
3043 {
3044         uintptr_t addr = wsp->walk_addr;
3045 
3046         (void) conn_status_walk_fanout(addr, wsp, "udp_hash");
3047         (void) conn_status_walk_fanout(addr, wsp, "conn_hash");
3048         (void) conn_status_walk_fanout(addr, wsp, "bind_hash");
3049         (void) conn_status_walk_fanout(addr, wsp, "proto_hash");
3050         (void) conn_status_walk_fanout(addr, wsp, "proto_v6_hash");
3051         return (WALK_NEXT);
3052 }
3053 
3054 /* ARGSUSED */
3055 static int
3056 conn_status_cb(uintptr_t addr, const void *walk_data,
3057     void *private)
3058 {
3059         netstack_t nss;
3060         char src_addrstr[INET6_ADDRSTRLEN];
3061         char rem_addrstr[INET6_ADDRSTRLEN];
3062         const ipcl_hash_walk_data_t *iw = walk_data;
3063         conn_t *conn = iw->conn;
3064 
3065         if (mdb_vread(conn, sizeof (conn_t), addr) == -1) {
3066                 mdb_warn("failed to read conn_t at %p", addr);
3067                 return (WALK_ERR);
3068         }
3069         if (mdb_vread(&nss, sizeof (nss),
3070             (uintptr_t)conn->conn_netstack) == -1) {
3071                 mdb_warn("failed to read netstack_t %p",
3072                     conn->conn_netstack);
3073                 return (WALK_ERR);
3074         }
3075         mdb_printf("%-?p %-?p %?d %?d\n", addr, conn->conn_wq,
3076             nss.netstack_stackid, conn->conn_zoneid);
3077 
3078         if (conn->conn_family == AF_INET6) {
3079                 mdb_snprintf(src_addrstr, sizeof (rem_addrstr), "%N",
3080                     &conn->conn_laddr_v6);
3081                 mdb_snprintf(rem_addrstr, sizeof (rem_addrstr), "%N",
3082                     &conn->conn_faddr_v6);
3083         } else {
3084                 mdb_snprintf(src_addrstr, sizeof (src_addrstr), "%I",
3085                     V4_PART_OF_V6((conn->conn_laddr_v6)));
3086                 mdb_snprintf(rem_addrstr, sizeof (rem_addrstr), "%I",
3087                     V4_PART_OF_V6((conn->conn_faddr_v6)));
3088         }
3089         mdb_printf("%s:%-5d\n%s:%-5d\n",
3090             src_addrstr, conn->conn_lport, rem_addrstr, conn->conn_fport);
3091         return (WALK_NEXT);
3092 }
3093 
3094 static void
3095 conn_header(void)
3096 {
3097         mdb_printf("%-?s %-?s %?s %?s\n%s\n%s\n",
3098             "ADDR", "WQ", "STACK", "ZONE", "SRC:PORT", "DEST:PORT");
3099         mdb_printf("%<u>%80s%</u>\n", "");
3100 }
3101 
3102 /*ARGSUSED*/
3103 static int
3104 conn_status(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3105 {
3106         conn_header();
3107         if (flags & DCMD_ADDRSPEC) {
3108                 (void) conn_status_cb(addr, NULL, NULL);
3109         } else {
3110                 if (mdb_walk("conn_status", (mdb_walk_cb_t)conn_status_cb,
3111                     NULL) == -1) {
3112                         mdb_warn("failed to walk conn_fanout");
3113                         return (DCMD_ERR);
3114                 }
3115         }
3116         return (DCMD_OK);
3117 }
3118 
3119 static void
3120 conn_status_help(void)
3121 {
3122         mdb_printf("Prints conn_t structures from the following hash tables: "
3123             "\n\tips_ipcl_udp_fanout\n\tips_ipcl_bind_fanout"
3124             "\n\tips_ipcl_conn_fanout\n\tips_ipcl_proto_fanout_v4"
3125             "\n\tips_ipcl_proto_fanout_v6\n");
3126 }
3127 
3128 static int
3129 srcid_walk_step(mdb_walk_state_t *wsp)
3130 {
3131         if (mdb_pwalk("srcid_list", wsp->walk_callback, wsp->walk_cbdata,
3132             wsp->walk_addr) == -1) {
3133                 mdb_warn("can't walk 'srcid_list'");
3134                 return (WALK_ERR);
3135         }
3136         return (WALK_NEXT);
3137 }
3138 
3139 /* ARGSUSED */
3140 static int
3141 srcid_status_cb(uintptr_t addr, const void *walk_data,
3142     void *private)
3143 {
3144         srcid_map_t smp;
3145 
3146         if (mdb_vread(&smp, sizeof (srcid_map_t), addr) == -1) {
3147                 mdb_warn("failed to read srcid_map at %p", addr);
3148                 return (WALK_ERR);
3149         }
3150         mdb_printf("%-?p %3d %4d %6d %N\n",
3151             addr, smp.sm_srcid, smp.sm_zoneid, smp.sm_refcnt,
3152             &smp.sm_addr);
3153         return (WALK_NEXT);
3154 }
3155 
3156 static void
3157 srcid_header(void)
3158 {
3159         mdb_printf("%-?s %3s %4s %6s %s\n",
3160             "ADDR", "ID", "ZONE", "REFCNT", "IPADDR");
3161         mdb_printf("%<u>%80s%</u>\n", "");
3162 }
3163 
3164 /*ARGSUSED*/
3165 static int
3166 srcid_status(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3167 {
3168         srcid_header();
3169         if (flags & DCMD_ADDRSPEC) {
3170                 (void) srcid_status_cb(addr, NULL, NULL);
3171         } else {
3172                 if (mdb_walk("srcid", (mdb_walk_cb_t)srcid_status_cb,
3173                     NULL) == -1) {
3174                         mdb_warn("failed to walk srcid_map");
3175                         return (DCMD_ERR);
3176                 }
3177         }
3178         return (DCMD_OK);
3179 }
3180 
3181 static int
3182 ilb_stacks_walk_step(mdb_walk_state_t *wsp)
3183 {
3184         return (ns_walk_step(wsp, NS_ILB));
3185 }
3186 
3187 static int
3188 ilb_rules_walk_init(mdb_walk_state_t *wsp)
3189 {
3190         ilb_stack_t ilbs;
3191 
3192         if (wsp->walk_addr == NULL)
3193                 return (WALK_ERR);
3194 
3195         if (mdb_vread(&ilbs, sizeof (ilbs), wsp->walk_addr) == -1) {
3196                 mdb_warn("failed to read ilb_stack_t at %p", wsp->walk_addr);
3197                 return (WALK_ERR);
3198         }
3199         if ((wsp->walk_addr = (uintptr_t)ilbs.ilbs_rule_head) != NULL)
3200                 return (WALK_NEXT);
3201         else
3202                 return (WALK_DONE);
3203 }
3204 
3205 static int
3206 ilb_rules_walk_step(mdb_walk_state_t *wsp)
3207 {
3208         ilb_rule_t rule;
3209         int status;
3210 
3211         if (mdb_vread(&rule, sizeof (rule), wsp->walk_addr) == -1) {
3212                 mdb_warn("failed to read ilb_rule_t at %p", wsp->walk_addr);
3213                 return (WALK_ERR);
3214         }
3215         status = wsp->walk_callback(wsp->walk_addr, &rule, wsp->walk_cbdata);
3216         if (status != WALK_NEXT)
3217                 return (status);
3218         if ((wsp->walk_addr = (uintptr_t)rule.ir_next) == NULL)
3219                 return (WALK_DONE);
3220         else
3221                 return (WALK_NEXT);
3222 }
3223 
3224 static int
3225 ilb_servers_walk_init(mdb_walk_state_t *wsp)
3226 {
3227         ilb_rule_t rule;
3228 
3229         if (wsp->walk_addr == NULL)
3230                 return (WALK_ERR);
3231 
3232         if (mdb_vread(&rule, sizeof (rule), wsp->walk_addr) == -1) {
3233                 mdb_warn("failed to read ilb_rule_t at %p", wsp->walk_addr);
3234                 return (WALK_ERR);
3235         }
3236         if ((wsp->walk_addr = (uintptr_t)rule.ir_servers) != NULL)
3237                 return (WALK_NEXT);
3238         else
3239                 return (WALK_DONE);
3240 }
3241 
3242 static int
3243 ilb_servers_walk_step(mdb_walk_state_t *wsp)
3244 {
3245         ilb_server_t server;
3246         int status;
3247 
3248         if (mdb_vread(&server, sizeof (server), wsp->walk_addr) == -1) {
3249                 mdb_warn("failed to read ilb_server_t at %p", wsp->walk_addr);
3250                 return (WALK_ERR);
3251         }
3252         status = wsp->walk_callback(wsp->walk_addr, &server, wsp->walk_cbdata);
3253         if (status != WALK_NEXT)
3254                 return (status);
3255         if ((wsp->walk_addr = (uintptr_t)server.iser_next) == NULL)
3256                 return (WALK_DONE);
3257         else
3258                 return (WALK_NEXT);
3259 }
3260 
3261 /*
3262  * Helper structure for ilb_nat_src walker.  It stores the current index of the
3263  * nat src table.
3264  */
3265 typedef struct {
3266         ilb_stack_t ilbs;
3267         int idx;
3268 } ilb_walk_t;
3269 
3270 /* Copy from list.c */
3271 #define list_object(a, node)    ((void *)(((char *)node) - (a)->list_offset))
3272 
3273 static int
3274 ilb_nat_src_walk_init(mdb_walk_state_t *wsp)
3275 {
3276         int i;
3277         ilb_walk_t *ns_walk;
3278         ilb_nat_src_entry_t *entry = NULL;
3279 
3280         if (wsp->walk_addr == NULL)
3281                 return (WALK_ERR);
3282 
3283         ns_walk = mdb_alloc(sizeof (ilb_walk_t), UM_SLEEP);
3284         if (mdb_vread(&ns_walk->ilbs, sizeof (ns_walk->ilbs),
3285             wsp->walk_addr) == -1) {
3286                 mdb_warn("failed to read ilb_stack_t at %p", wsp->walk_addr);
3287                 mdb_free(ns_walk, sizeof (ilb_walk_t));
3288                 return (WALK_ERR);
3289         }
3290 
3291         if (ns_walk->ilbs.ilbs_nat_src == NULL) {
3292                 mdb_free(ns_walk, sizeof (ilb_walk_t));
3293                 return (WALK_DONE);
3294         }
3295 
3296         wsp->walk_data = ns_walk;
3297         for (i = 0; i < ns_walk->ilbs.ilbs_nat_src_hash_size; i++) {
3298                 list_t head;
3299                 char  *khead;
3300 
3301                 /* Read in the nsh_head in the i-th element of the array. */
3302                 khead = (char *)ns_walk->ilbs.ilbs_nat_src + i *
3303                     sizeof (ilb_nat_src_hash_t);
3304                 if (mdb_vread(&head, sizeof (list_t), (uintptr_t)khead) == -1) {
3305                         mdb_warn("failed to read ilbs_nat_src at %p\n", khead);
3306                         return (WALK_ERR);
3307                 }
3308 
3309                 /*
3310                  * Note that list_next points to a kernel address and we need
3311                  * to compare list_next with the kernel address of the list
3312                  * head.  So we need to calculate the address manually.
3313                  */
3314                 if ((char *)head.list_head.list_next != khead +
3315                     offsetof(list_t, list_head)) {
3316                         entry = list_object(&head, head.list_head.list_next);
3317                         break;
3318                 }
3319         }
3320 
3321         if (entry == NULL)
3322                 return (WALK_DONE);
3323 
3324         wsp->walk_addr = (uintptr_t)entry;
3325         ns_walk->idx = i;
3326         return (WALK_NEXT);
3327 }
3328 
3329 static int
3330 ilb_nat_src_walk_step(mdb_walk_state_t *wsp)
3331 {
3332         int status;
3333         ilb_nat_src_entry_t entry, *next_entry;
3334         ilb_walk_t *ns_walk;
3335         ilb_stack_t *ilbs;
3336         list_t head;
3337         char *khead;
3338         int i;
3339 
3340         if (mdb_vread(&entry, sizeof (ilb_nat_src_entry_t),
3341             wsp->walk_addr) == -1) {
3342                 mdb_warn("failed to read ilb_nat_src_entry_t at %p",
3343                     wsp->walk_addr);
3344                 return (WALK_ERR);
3345         }
3346         status = wsp->walk_callback(wsp->walk_addr, &entry, wsp->walk_cbdata);
3347         if (status != WALK_NEXT)
3348                 return (status);
3349 
3350         ns_walk = (ilb_walk_t *)wsp->walk_data;
3351         ilbs = &ns_walk->ilbs;
3352         i = ns_walk->idx;
3353 
3354         /* Read in the nsh_head in the i-th element of the array. */
3355         khead = (char *)ilbs->ilbs_nat_src + i * sizeof (ilb_nat_src_hash_t);
3356         if (mdb_vread(&head, sizeof (list_t), (uintptr_t)khead) == -1) {
3357                 mdb_warn("failed to read ilbs_nat_src at %p\n", khead);
3358                 return (WALK_ERR);
3359         }
3360 
3361         /*
3362          * Check if there is still entry in the current list.
3363          *
3364          * Note that list_next points to a kernel address and we need to
3365          * compare list_next with the kernel address of the list head.
3366          * So we need to calculate the address manually.
3367          */
3368         if ((char *)entry.nse_link.list_next != khead + offsetof(list_t,
3369             list_head)) {
3370                 wsp->walk_addr = (uintptr_t)list_object(&head,
3371                     entry.nse_link.list_next);
3372                 return (WALK_NEXT);
3373         }
3374 
3375         /* Start with the next bucket in the array. */
3376         next_entry = NULL;
3377         for (i++; i < ilbs->ilbs_nat_src_hash_size; i++) {
3378                 khead = (char *)ilbs->ilbs_nat_src + i *
3379                     sizeof (ilb_nat_src_hash_t);
3380                 if (mdb_vread(&head, sizeof (list_t), (uintptr_t)khead) == -1) {
3381                         mdb_warn("failed to read ilbs_nat_src at %p\n", khead);
3382                         return (WALK_ERR);
3383                 }
3384 
3385                 if ((char *)head.list_head.list_next != khead +
3386                     offsetof(list_t, list_head)) {
3387                         next_entry = list_object(&head,
3388                             head.list_head.list_next);
3389                         break;
3390                 }
3391         }
3392 
3393         if (next_entry == NULL)
3394                 return (WALK_DONE);
3395 
3396         wsp->walk_addr = (uintptr_t)next_entry;
3397         ns_walk->idx = i;
3398         return (WALK_NEXT);
3399 }
3400 
3401 static void
3402 ilb_common_walk_fini(mdb_walk_state_t *wsp)
3403 {
3404         ilb_walk_t *walk;
3405 
3406         walk = (ilb_walk_t *)wsp->walk_data;
3407         if (walk == NULL)
3408                 return;
3409         mdb_free(walk, sizeof (ilb_walk_t *));
3410 }
3411 
3412 static int
3413 ilb_conn_walk_init(mdb_walk_state_t *wsp)
3414 {
3415         int i;
3416         ilb_walk_t *conn_walk;
3417         ilb_conn_hash_t head;
3418 
3419         if (wsp->walk_addr == NULL)
3420                 return (WALK_ERR);
3421 
3422         conn_walk = mdb_alloc(sizeof (ilb_walk_t), UM_SLEEP);
3423         if (mdb_vread(&conn_walk->ilbs, sizeof (conn_walk->ilbs),
3424             wsp->walk_addr) == -1) {
3425                 mdb_warn("failed to read ilb_stack_t at %p", wsp->walk_addr);
3426                 mdb_free(conn_walk, sizeof (ilb_walk_t));
3427                 return (WALK_ERR);
3428         }
3429 
3430         if (conn_walk->ilbs.ilbs_c2s_conn_hash == NULL) {
3431                 mdb_free(conn_walk, sizeof (ilb_walk_t));
3432                 return (WALK_DONE);
3433         }
3434 
3435         wsp->walk_data = conn_walk;
3436         for (i = 0; i < conn_walk->ilbs.ilbs_conn_hash_size; i++) {
3437                 char *khead;
3438 
3439                 /* Read in the nsh_head in the i-th element of the array. */
3440                 khead = (char *)conn_walk->ilbs.ilbs_c2s_conn_hash + i *
3441                     sizeof (ilb_conn_hash_t);
3442                 if (mdb_vread(&head, sizeof (ilb_conn_hash_t),
3443                     (uintptr_t)khead) == -1) {
3444                         mdb_warn("failed to read ilbs_c2s_conn_hash at %p\n",
3445                             khead);
3446                         return (WALK_ERR);
3447                 }
3448 
3449                 if (head.ilb_connp != NULL)
3450                         break;
3451         }
3452 
3453         if (head.ilb_connp == NULL)
3454                 return (WALK_DONE);
3455 
3456         wsp->walk_addr = (uintptr_t)head.ilb_connp;
3457         conn_walk->idx = i;
3458         return (WALK_NEXT);
3459 }
3460 
3461 static int
3462 ilb_conn_walk_step(mdb_walk_state_t *wsp)
3463 {
3464         int status;
3465         ilb_conn_t conn;
3466         ilb_walk_t *conn_walk;
3467         ilb_stack_t *ilbs;
3468         ilb_conn_hash_t head;
3469         char *khead;
3470         int i;
3471 
3472         if (mdb_vread(&conn, sizeof (ilb_conn_t), wsp->walk_addr) == -1) {
3473                 mdb_warn("failed to read ilb_conn_t at %p", wsp->walk_addr);
3474                 return (WALK_ERR);
3475         }
3476 
3477         status = wsp->walk_callback(wsp->walk_addr, &conn, wsp->walk_cbdata);
3478         if (status != WALK_NEXT)
3479                 return (status);
3480 
3481         conn_walk = (ilb_walk_t *)wsp->walk_data;
3482         ilbs = &conn_walk->ilbs;
3483         i = conn_walk->idx;
3484 
3485         /* Check if there is still entry in the current list. */
3486         if (conn.conn_c2s_next != NULL) {
3487                 wsp->walk_addr = (uintptr_t)conn.conn_c2s_next;
3488                 return (WALK_NEXT);
3489         }
3490 
3491         /* Start with the next bucket in the array. */
3492         for (i++; i < ilbs->ilbs_conn_hash_size; i++) {
3493                 khead = (char *)ilbs->ilbs_c2s_conn_hash + i *
3494                     sizeof (ilb_conn_hash_t);
3495                 if (mdb_vread(&head, sizeof (ilb_conn_hash_t),
3496                     (uintptr_t)khead) == -1) {
3497                         mdb_warn("failed to read ilbs_c2s_conn_hash at %p\n",
3498                             khead);
3499                         return (WALK_ERR);
3500                 }
3501 
3502                 if (head.ilb_connp != NULL)
3503                         break;
3504         }
3505 
3506         if (head.ilb_connp == NULL)
3507                 return (WALK_DONE);
3508 
3509         wsp->walk_addr = (uintptr_t)head.ilb_connp;
3510         conn_walk->idx = i;
3511         return (WALK_NEXT);
3512 }
3513 
3514 static int
3515 ilb_sticky_walk_init(mdb_walk_state_t *wsp)
3516 {
3517         int i;
3518         ilb_walk_t *sticky_walk;
3519         ilb_sticky_t *st = NULL;
3520 
3521         if (wsp->walk_addr == NULL)
3522                 return (WALK_ERR);
3523 
3524         sticky_walk = mdb_alloc(sizeof (ilb_walk_t), UM_SLEEP);
3525         if (mdb_vread(&sticky_walk->ilbs, sizeof (sticky_walk->ilbs),
3526             wsp->walk_addr) == -1) {
3527                 mdb_warn("failed to read ilb_stack_t at %p", wsp->walk_addr);
3528                 mdb_free(sticky_walk, sizeof (ilb_walk_t));
3529                 return (WALK_ERR);
3530         }
3531 
3532         if (sticky_walk->ilbs.ilbs_sticky_hash == NULL) {
3533                 mdb_free(sticky_walk, sizeof (ilb_walk_t));
3534                 return (WALK_DONE);
3535         }
3536 
3537         wsp->walk_data = sticky_walk;
3538         for (i = 0; i < sticky_walk->ilbs.ilbs_sticky_hash_size; i++) {
3539                 list_t head;
3540                 char *khead;
3541 
3542                 /* Read in the nsh_head in the i-th element of the array. */
3543                 khead = (char *)sticky_walk->ilbs.ilbs_sticky_hash + i *
3544                     sizeof (ilb_sticky_hash_t);
3545                 if (mdb_vread(&head, sizeof (list_t), (uintptr_t)khead) == -1) {
3546                         mdb_warn("failed to read ilbs_sticky_hash at %p\n",
3547                             khead);
3548                         return (WALK_ERR);
3549                 }
3550 
3551                 /*
3552                  * Note that list_next points to a kernel address and we need
3553                  * to compare list_next with the kernel address of the list
3554                  * head.  So we need to calculate the address manually.
3555                  */
3556                 if ((char *)head.list_head.list_next != khead +
3557                     offsetof(list_t, list_head)) {
3558                         st = list_object(&head, head.list_head.list_next);
3559                         break;
3560                 }
3561         }
3562 
3563         if (st == NULL)
3564                 return (WALK_DONE);
3565 
3566         wsp->walk_addr = (uintptr_t)st;
3567         sticky_walk->idx = i;
3568         return (WALK_NEXT);
3569 }
3570 
3571 static int
3572 ilb_sticky_walk_step(mdb_walk_state_t *wsp)
3573 {
3574         int status;
3575         ilb_sticky_t st, *st_next;
3576         ilb_walk_t *sticky_walk;
3577         ilb_stack_t *ilbs;
3578         list_t head;
3579         char *khead;
3580         int i;
3581 
3582         if (mdb_vread(&st, sizeof (ilb_sticky_t), wsp->walk_addr) == -1) {
3583                 mdb_warn("failed to read ilb_sticky_t at %p", wsp->walk_addr);
3584                 return (WALK_ERR);
3585         }
3586 
3587         status = wsp->walk_callback(wsp->walk_addr, &st, wsp->walk_cbdata);
3588         if (status != WALK_NEXT)
3589                 return (status);
3590 
3591         sticky_walk = (ilb_walk_t *)wsp->walk_data;
3592         ilbs = &sticky_walk->ilbs;
3593         i = sticky_walk->idx;
3594 
3595         /* Read in the nsh_head in the i-th element of the array. */
3596         khead = (char *)ilbs->ilbs_sticky_hash + i * sizeof (ilb_sticky_hash_t);
3597         if (mdb_vread(&head, sizeof (list_t), (uintptr_t)khead) == -1) {
3598                 mdb_warn("failed to read ilbs_sticky_hash at %p\n", khead);
3599                 return (WALK_ERR);
3600         }
3601 
3602         /*
3603          * Check if there is still entry in the current list.
3604          *
3605          * Note that list_next points to a kernel address and we need to
3606          * compare list_next with the kernel address of the list head.
3607          * So we need to calculate the address manually.
3608          */
3609         if ((char *)st.list.list_next != khead + offsetof(list_t,
3610             list_head)) {
3611                 wsp->walk_addr = (uintptr_t)list_object(&head,
3612                     st.list.list_next);
3613                 return (WALK_NEXT);
3614         }
3615 
3616         /* Start with the next bucket in the array. */
3617         st_next = NULL;
3618         for (i++; i < ilbs->ilbs_nat_src_hash_size; i++) {
3619                 khead = (char *)ilbs->ilbs_sticky_hash + i *
3620                     sizeof (ilb_sticky_hash_t);
3621                 if (mdb_vread(&head, sizeof (list_t), (uintptr_t)khead) == -1) {
3622                         mdb_warn("failed to read ilbs_sticky_hash at %p\n",
3623                             khead);
3624                         return (WALK_ERR);
3625                 }
3626 
3627                 if ((char *)head.list_head.list_next != khead +
3628                     offsetof(list_t, list_head)) {
3629                         st_next = list_object(&head,
3630                             head.list_head.list_next);
3631                         break;
3632                 }
3633         }
3634 
3635         if (st_next == NULL)
3636                 return (WALK_DONE);
3637 
3638         wsp->walk_addr = (uintptr_t)st_next;
3639         sticky_walk->idx = i;
3640         return (WALK_NEXT);
3641 }