ip.c revision 5c0b7edee9bd9fad49038456b16972ff28fa4187
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/avl_impl.h>
#include <inet/ipclassifier.h>
#include <sys/squeue_impl.h>
#include <mdb/mdb_modapi.h>
#define ADDR_WIDTH 11
typedef struct {
const char *bit_name; /* name of bit */
const char *bit_descr; /* description of bit's purpose */
} bitname_t;
static const bitname_t squeue_states[] = {
{ "SQS_PROC", "being processed" },
{ "SQS_WORKER", "... by a worker thread" },
{ "SQS_ENTER", "... by an squeue_enter() thread" },
{ "SQS_FAST", "... in fast-path mode" },
{ "SQS_USER", "A non interrupt user" },
{ "SQS_BOUND", "worker thread bound to CPU" },
{ "SQS_PROFILE", "profiling enabled" },
{ "SQS_REENTER", "re-entered thred" },
{ NULL }
};
typedef struct illif_walk_data {
int ill_list;
/*
* Given the kernel address of an ip_stack_t, return the stackid
*/
static int
{
return (0);
}
return (0);
}
return (nss.netstack_stackid);
}
int
{
mdb_warn("can't walk 'netstack'");
return (WALK_ERR);
}
return (WALK_NEXT);
}
int
{
#ifdef DEBUG
#endif
return (WALK_ERR);
}
#ifdef DEBUG
#endif
}
/*
* Called with walk_addr being the address of ips_ill_g_heads
*/
int
{
mdb_warn("illif_stack supports only local walks\n");
return (WALK_ERR);
}
mdb_warn("failed to read 'ips_ill_g_heads' at %p",
return (WALK_ERR);
}
return (WALK_NEXT);
}
int
{
return (WALK_ERR);
}
if (++list >= MAX_G_HEADS)
return (WALK_DONE);
return (WALK_NEXT);
}
}
void
{
}
typedef struct illif_cbdata {
int ill_printlist; /* list to be printed (MAX_G_HEADS for all) */
static int
{
const char *version;
return (WALK_NEXT);
return (WALK_NEXT);
return (WALK_NEXT);
}
default: version = "??"; break;
}
mdb_printf("%?p %2s %?p %10d %?p %s\n",
return (WALK_NEXT);
}
int
{
mdb_warn("can't walk 'ip_stacks'");
return (WALK_ERR);
}
return (WALK_NEXT);
}
int
{
#ifdef DEBUG
#endif
return (WALK_ERR);
}
#ifdef DEBUG
#endif
mdb_warn("couldn't walk 'illif_stack' for ips_ill_g_heads %p",
kaddr);
return (WALK_ERR);
}
return (WALK_NEXT);
}
int
{
int printlist = MAX_G_HEADS;
return (DCMD_USAGE);
} else {
return (DCMD_USAGE);
}
}
mdb_printf("%<u>%?s %2s %?s %10s %?s %-10s%</u>\n",
"ADDR", "IP", "AVLADDR", "NUMNODES", "ARENA", "NAME");
}
mdb_warn("can't walk ill_if_t structures");
return (DCMD_ERR);
}
return (DCMD_OK);
/*
* If an address is specified and the walk doesn't find it,
* print it anyway.
*/
return (DCMD_ERR);
}
mdb_printf("%?p %2s %?p %10d %?p %s\n",
return (DCMD_OK);
}
static void
illif_help(void)
{
mdb_printf("Options:\n");
mdb_printf("\t-P v4 | v6"
"\tfilter interface structures for the specified protocol\n");
}
int
{
mdb_warn("can't walk 'ire_cache'");
return (WALK_ERR);
}
return (WALK_NEXT);
}
int
{
return (WALK_ERR);
}
}
int
{
mdb_warn("can't walk 'ip_stacks'");
return (WALK_ERR);
}
return (WALK_NEXT);
}
int
{
int verbose = 0;
int i;
#ifdef DEBUG
#endif
return (WALK_ERR);
}
#ifdef DEBUG
mdb_printf("DEBUG: ire_ctable_walk_step: ips_ip_cache_table_size %u\n",
#endif
return (WALK_ERR);
}
#ifdef DEBUG
mdb_printf("DEBUG: ire_ctable_walk_step: ips_ip_cache_table %p\n",
kaddr);
#endif
return (WALK_ERR);
}
for (i = 0; i < cache_table_size; i++) {
#ifdef DEBUG
mdb_printf("DEBUG: ire_ctable_walk_step: %d ire %p\n",
i, kaddr);
#endif
kaddr) == -1) {
return (WALK_ERR);
}
}
return (WALK_NEXT);
}
/* ARGSUSED */
int
{
#ifdef DEBUG
#endif
return (WALK_NEXT);
}
int
{
int status;
#ifdef DEBUG
#endif
return (WALK_DONE);
return (WALK_ERR);
}
wsp->walk_cbdata);
return (status);
#ifdef DEBUG
#endif
return (status);
}
static int
{
static const mdb_bitmask_t tmasks[] = {
{ NULL, 0, 0 }
};
static const mdb_bitmask_t mmasks[] = {
{ NULL, 0, 0 }
};
static const mdb_bitmask_t fmasks[] = {
{ NULL, 0, 0 }
};
mdb_printf("%<b>%?p%</b> %40N <%hb>\n"
"%?s %40N <%hb>\n"
"%?s %40d %4d <%hb>\n",
mdb_printf("%?p %30N %30N %5d %4d\n",
&irep->ire_addr_v6,
irep->ire_zoneid);
} else if (*verbose) {
mdb_printf("%<b>%?p%</b> %40I <%hb>\n"
"%?s %40I <%hb>\n"
"%?s %40d <%hb>\n",
} else {
irep->ire_zoneid);
}
return (WALK_NEXT);
}
/*
* There are faster ways to do this. Given the interactive nature of this
* use I don't think its worth much effort.
*/
static unsigned short
{
while (len > 1) {
/* alignment */
p = (char *)p + sizeof (uint16_t);
if (sum & 0x80000000)
len -= 2;
}
if (len)
while (sum >> 16)
return (~sum);
}
static const mdb_bitmask_t tcp_flags[] = {
{ NULL, 0, 0 }
};
static void
{
mdb_printf("%<b>TCP header%</b>\n");
mdb_printf("%<u>%6s %6s %10s %10s %4s %5s %5s %5s %-15s%</u>\n",
"SPORT", "DPORT", "SEQ", "ACK", "HLEN", "WIN", "CSUM", "URP",
"FLAGS");
mdb_printf("%6hu %6hu %10u %10u %4d %5hu %5hu %5hu <%b>\n",
mdb_printf("0x%04x 0x%04x 0x%08x 0x%08x\n\n",
}
/* ARGSUSED */
static int
{
if (!(flags & DCMD_ADDRSPEC))
return (DCMD_USAGE);
return (DCMD_ERR);
}
tcphdr_print(&tcph);
return (DCMD_OK);
}
static void
{
mdb_printf("%<b>UDP header%</b>\n");
mdb_printf("%<u>%14s %14s %5s %6s%</u>\n",
"SPORT", "DPORT", "LEN", "CSUM");
}
/* ARGSUSED */
static int
{
if (!(flags & DCMD_ADDRSPEC))
return (DCMD_USAGE);
return (DCMD_ERR);
}
udphdr_print(&udph);
return (DCMD_OK);
}
static void
{
mdb_printf("%<b>SCTP header%</b>\n");
mdb_printf("%<u>%14s %14s %10s %10s%</u>\n",
"SPORT", "DPORT", "VTAG", "CHKSUM");
}
/* ARGSUSED */
static int
{
if (!(flags & DCMD_ADDRSPEC))
return (DCMD_USAGE);
return (DCMD_ERR);
}
return (DCMD_OK);
}
static int
{
mdb_printf("\n");
switch (proto) {
case IPPROTO_TCP: {
return (DCMD_ERR);
}
tcphdr_print(&tcph);
break;
}
case IPPROTO_UDP: {
return (DCMD_ERR);
}
udphdr_print(&udph);
break;
}
case IPPROTO_SCTP: {
return (DCMD_ERR);
}
break;
}
default:
break;
}
return (DCMD_OK);
}
static const mdb_bitmask_t ip_flags[] = {
{ NULL, 0, 0 }
};
/* ARGSUSED */
static int
{
char exp_csum[8];
return (DCMD_USAGE);
return (DCMD_ERR);
}
if (ver != IPV4_VERSION) {
if (ver == IPV6_VERSION) {
} else if (!force) {
return (DCMD_ERR);
}
}
mdb_printf("%<b>IPv4 header%</b>\n");
mdb_printf("%-34s %-34s\n"
"%<u>%-4s %-4s %-5s %-5s %-6s %-5s %-5s %-6s %-8s %-6s%</u>\n",
"SRC", "DST",
"HLEN", "TOS", "LEN", "ID", "OFFSET", "TTL", "PROTO", "CHKSUM",
"EXP-CSUM", "FLGS");
if (hdrlen == IP_SIMPLE_HDR_LENGTH) {
else
} else {
}
mdb_printf("%-34I %-34I%\n"
"%-4d %-4d %-5hu %-5hu %-6hu %-5hu %-5hu %-6u %-8s <%5hb>\n",
if (verbose) {
} else {
return (DCMD_OK);
}
}
/* ARGSUSED */
static int
{
return (DCMD_USAGE);
return (DCMD_ERR);
}
if (ver != IPV6_VERSION) {
if (ver == IPV4_VERSION) {
} else if (!force) {
return (DCMD_ERR);
}
}
mdb_printf("%<b>IPv6 header%</b>\n");
mdb_printf("%<u>%-26s %-26s %4s %7s %5s %3s %3s%</u>\n",
"SRC", "DST", "TCLS", "FLOW-ID", "PLEN", "NXT", "HOP");
mdb_printf("%-26N %-26N %4d %7d %5hu %3d %3d\n",
if (verbose) {
} else {
return (DCMD_OK);
}
}
int
{
return (DCMD_USAGE);
if (verbose) {
mdb_printf("%?s %40s %-20s%\n"
"%?s %40s %-20s%\n"
"%<u>%?s %40s %4s %-20s%</u>\n",
"ADDR", "SRC", "TYPE",
"", "DST", "MARKS",
"", "STACK", "ZONE", "FLAGS");
} else {
mdb_printf("%<u>%?s %30s %30s %5s %4s%</u>\n",
"ADDR", "SRC", "DST", "STACK", "ZONE");
}
}
if (flags & DCMD_ADDRSPEC) {
mdb_warn("failed to walk ire table");
return (DCMD_ERR);
}
return (DCMD_OK);
}
static size_t
{
/*
* size of the allocation. An mi_o_s is thus a size_t plus an mi_o_s.
*/
struct mi_block {
} m;
sizeof (m)) == sizeof (m))
return (m.mi_nbytes - sizeof (m));
return (0);
}
static void
{
char name[32];
}
void
{
}
{
return (NULL);
}
{
return (NULL);
}
/*
* Print the core fields in an squeue_t. With the "-v" argument,
* provide more verbose output.
*/
static int
{
unsigned int i;
if (!(flags & DCMD_ADDRSPEC)) {
mdb_warn("failed to walk squeue cache");
return (DCMD_ERR);
}
return (DCMD_OK);
}
!= argc)
return (DCMD_USAGE);
mdb_printf("\n\n");
mdb_printf("%?s %-5s %-3s %?s %?s %?s\n",
"ADDR", "STATE", "CPU",
"FIRST", "LAST", "WORKER");
}
return (DCMD_ERR);
}
mdb_printf("%0?p %05x %3d %0?p %0?p %0?p\n",
if (!verbose)
return (DCMD_OK);
continue;
if (arm) {
} else
squeue_states[i].bit_descr);
}
return (DCMD_OK);
}
static void
ip_squeue_help(void)
{
mdb_printf("Print the core information for a given NCA squeue_t.\n\n");
mdb_printf("Options:\n");
mdb_printf("\t-v\tbe verbose (more descriptive)\n");
}
static const mdb_dcmd_t dcmds[] = {
{ "illif", "?[-P v4 | v6]",
"display or filter IP Lower Level InterFace structures", illif,
illif_help },
{ NULL }
};
static const mdb_walker_t walkers[] = {
{ "illif", "walk list of ill interface types for all stacks",
{ "illif_stack", "walk list of ill interface types",
{ "ire", "walk active ire_t structures",
{ "ire_ctable", "walk ire_t structures in the ctable",
{ "ire_next", "walk ire_t structures in the ctable",
{ "ip_stacks", "walk all the ip_stack_t",
{ NULL }
};
const mdb_modinfo_t *
_mdb_init(void)
{
return (&modinfo);
}
void
_mdb_fini(void)
{
}