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