net.c revision bd670b35a010421b6e1a5536c34453a827007c81
/*
* 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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <mdb/mdb_modapi.h>
#include <inet/ipclassifier.h>
#include <sys/tpicommon.h>
#include <sys/socketvar.h>
#include <sys/cred_impl.h>
#include <inet/udp_impl.h>
#include <inet/rawip_impl.h>
#include <net/bridge_impl.h>
#include <io/trill_impl.h>
#include <sys/mac_impl.h>
#define ADDR_V6_WIDTH 23
#define ADDR_V4_WIDTH 15
#define NETSTAT_ALL 0x01
#define NETSTAT_VERBOSE 0x02
#define NETSTAT_ROUTE 0x04
#define NETSTAT_V4 0x08
#define NETSTAT_V6 0x10
#define NETSTAT_UNIX 0x20
#define NETSTAT_FIRST 0x80000000u
typedef struct netstat_cb_data_s {
int af;
int
{
mdb_warn("can't walk 'netstack'");
return (WALK_ERR);
}
return (WALK_NEXT);
}
int
{
return (WALK_ERR);
}
}
int
{
mdb_warn("can't walk 'netstack'");
return (WALK_ERR);
}
return (WALK_NEXT);
}
int
{
return (WALK_ERR);
}
}
int
{
mdb_warn("can't walk 'netstack'");
return (WALK_ERR);
}
return (WALK_NEXT);
}
int
{
return (WALK_ERR);
}
}
/*
* Print an IPv4 address and port number in a compact and easy to read format
* The arguments are in network byte order
*/
static void
{
}
/*
* Print an IPv6 address and port number in a compact and easy to read format
* The arguments are in network byte order
*/
static void
{
}
static int
{
}
static int
{
}
static int
{
}
static int
{
}
static int
{
}
static int
{
}
int
{
mdb_warn("failed to lookup sockfs`socklist");
return (WALK_ERR);
}
mdb_warn("failed to read address of initial sonode "
return (WALK_ERR);
}
}
return (WALK_NEXT);
}
int
{
int status;
struct sotpi_sonode *stp;
return (WALK_DONE);
return (WALK_ERR);
}
wsp->walk_cbdata);
return (status);
}
void
{
}
struct mi_walk_data {
};
int
{
struct mi_walk_data *wdp;
mdb_warn("mi doesn't support global walks\n");
return (WALK_ERR);
}
/* So that we do not immediately return WALK_DONE below */
return (WALK_NEXT);
}
int
{
int status;
/* Always false in the first iteration */
return (WALK_DONE);
}
return (WALK_ERR);
}
/* Only true in the first iteration */
} else {
}
return (status);
}
void
{
}
typedef struct mi_payload_walk_arg_s {
const char *mi_pwa_walker; /* Underlying walker */
#define MI_PAYLOAD_DEVICE 0x1
#define MI_PAYLOAD_MODULE 0x2
int
{
return (WALK_ERR);
}
return (WALK_NEXT);
}
int
{
mdb_warn("can't read address of mi head at %p for %s",
return (WALK_ERR);
}
if (kaddr == 0) {
/* Empty list */
return (WALK_DONE);
}
mdb_warn("failed to walk genunix`mi");
return (WALK_ERR);
}
return (WALK_NEXT);
}
const mi_payload_walk_arg_t mi_icmp_arg = {
};
int
{
int filter = 0;
if (!(flags & DCMD_ADDRSPEC)) {
argv) == -1) {
mdb_warn("failed to walk sonode");
return (DCMD_ERR);
}
return (DCMD_OK);
}
return (DCMD_USAGE);
else
filter = 1;
}
type = SOCK_STREAM;
type = SOCK_DGRAM;
else
filter = 1;
}
filter = 1;
}
mdb_printf("%<u>%-?s Family Type Proto State Mode Flag "
"AccessVP%</u>\n", "Sonode:");
}
return (DCMD_ERR);
}
return (DCMD_OK);
return (DCMD_OK);
return (DCMD_OK);
if (filter) {
return (DCMD_OK);
}
case AF_UNIX:
mdb_printf("unix ");
break;
case AF_INET:
mdb_printf("inet ");
break;
case AF_INET6:
mdb_printf("inet6 ");
break;
default:
}
case SOCK_STREAM:
mdb_printf(" strm");
break;
case SOCK_DGRAM:
mdb_printf(" dgrm");
break;
case SOCK_RAW:
mdb_printf(" raw ");
break;
default:
}
mdb_printf(" %5hi %05x %04x %04hx\n",
return (DCMD_OK);
}
#define MI_PAYLOAD 0x1
#define MI_DEVICE 0x2
#define MI_MODULE 0x4
int
{
if (!(flags & DCMD_ADDRSPEC))
return (DCMD_USAGE);
return (DCMD_USAGE);
mdb_warn("at most one filter, d for devices or m "
"for modules, may be specified\n");
return (DCMD_USAGE);
}
mdb_printf("%<u>%-?s %-?s %-?s IsDev Dev%</u>\n",
"MI_O", "Next", "Prev");
}
return (DCMD_ERR);
}
if (opts != 0) {
/* mio is a module */
return (DCMD_OK);
} else {
/* mio is a device */
return (DCMD_OK);
}
if (opts & MI_PAYLOAD)
else
return (DCMD_OK);
}
mdb_printf("FALSE");
else
mdb_printf("TRUE ");
return (DCMD_OK);
}
static int
{
return (0);
}
return (nss.netstack_stackid);
}
static void
{
mdb_printf(" %5i %08x %08x %5i %08x %08x %5li %5i\n",
}
/*ARGSUSED*/
static int
{
return (WALK_ERR);
}
return (WALK_ERR);
}
return (WALK_NEXT);
}
mdb_printf(" ");
mdb_printf(" ");
}
if (opts & NETSTAT_VERBOSE)
return (WALK_NEXT);
}
/*ARGSUSED*/
static int
{
char *state;
return (WALK_ERR);
}
mdb_warn("failed to read conn_udp at %p",
return (WALK_ERR);
}
return (WALK_NEXT);
}
state = "UNBOUND";
state = "IDLE";
state = "CONNECTED";
else
state = "UNKNOWN";
mdb_printf(" ");
mdb_printf(" ");
}
return (WALK_NEXT);
}
/*ARGSUSED*/
static int
{
char *state;
return (WALK_ERR);
}
mdb_warn("failed to read conn_icmp at %p",
return (WALK_ERR);
}
return (WALK_NEXT);
}
state = "UNBOUND";
state = "IDLE";
state = "CONNECTED";
else
state = "UNKNOWN";
mdb_printf(" ");
mdb_printf(" ");
}
return (WALK_NEXT);
}
/*
* print the address of a unix domain socket
*
* so is the address of a AF_UNIX struct sonode in mdb's address space
* soa is the address of the struct soaddr to print
*
* returns 0 on success, -1 otherwise
*/
static int
{
const char none[] = " (none)";
} else {
mdb_warn("failed to read unix address "
return (-1);
}
} else {
}
}
} else {
}
return (0);
}
/* based on sockfs_snapshot */
/*ARGSUSED*/
static int
{
return (WALK_NEXT);
return (WALK_ERR);
}
switch (sti->sti_serv_type) {
case T_CLTS:
break;
case T_COTS:
break;
case T_COTS_ORD:
break;
default:
}
} else {
}
} else {
}
return (WALK_ERR);
return (WALK_ERR);
return (WALK_NEXT);
}
static void
{
mdb_printf(" %<u>%-5s %-8s %-8s %-5s %-8s %-8s %5s %5s%</u>\n",
"Swind", "Snext", "Suna", "Rwind", "Rack", "Rnext", "Rto", "Mss");
}
static void
{
*intf = '\0';
return;
}
}
const in6_addr_t ipv6_all_ones =
{ 0xffffffffU, 0xffffffffU, 0xffffffffU, 0xffffffffU };
static void
{
/* RTF_INDIRECT wins over RTF_GATEWAY - don't display both */
/* IRE_IF_CLONE wins over RTF_HOST - don't display both */
} else {
}
}
static int
{
return (WALK_NEXT);
/* Skip certain IREs by default */
if (!(*opts & NETSTAT_ALL) &&
return (WALK_NEXT);
if (*opts & NETSTAT_FIRST) {
*opts &= ~NETSTAT_FIRST;
mdb_printf("%<u>%s Table: IPv4%</u>\n",
if (*opts & NETSTAT_VERBOSE) {
mdb_printf("%<u>%-?s %-*s %-*s %-*s Device Mxfrg Rtt "
} else {
mdb_printf("%<u>%-?s %-*s %-*s Flags Ref Use "
"Interface%</u>\n",
ADDR_V4_WIDTH, "Gateway");
}
}
if (*opts & NETSTAT_VERBOSE) {
mdb_printf("%?p %-*I %-*I %-*I %-6s %5u%c %4u %3u %-3s %5u "
0, ' ',
} else {
}
return (WALK_NEXT);
}
int
{
int plen;
int i;
for (i = 3; i >= 0; i--)
break;
if (i < 0)
return (0);
while (!(val & 1)) {
val >>= 1;
plen--;
}
return (plen);
}
static int
{
const in6_addr_t *gatep;
int masklen;
return (WALK_NEXT);
/* Skip certain IREs by default */
if (!(*opts & NETSTAT_ALL) &&
return (WALK_NEXT);
if (*opts & NETSTAT_FIRST) {
*opts &= ~NETSTAT_FIRST;
mdb_printf("\n%<u>%s Table: IPv6%</u>\n",
if (*opts & NETSTAT_VERBOSE) {
mdb_printf("%<u>%-?s %-*s %-*s If PMTU Rtt Ref "
ADDR_V6_WIDTH, "Gateway");
} else {
mdb_printf("%<u>%-?s %-*s %-*s Flags Ref Use If"
"%</u>\n",
ADDR_V6_WIDTH, "Gateway");
}
}
if (*opts & NETSTAT_VERBOSE) {
mdb_printf("%?p %-*s %-*N %-5s %5u%c %5u %3u %-5s %6u %u\n",
intf, 0, ' ',
} else {
}
return (WALK_NEXT);
}
static void
netstat_header_v4(int proto)
{
if (proto == IPPROTO_TCP)
else if (proto == IPPROTO_UDP)
else if (proto == IPPROTO_ICMP)
mdb_printf("State %6s%*s %6s%*s %-5s %-4s%</u>\n",
}
static void
netstat_header_v6(int proto)
{
if (proto == IPPROTO_TCP)
else if (proto == IPPROTO_UDP)
else if (proto == IPPROTO_ICMP)
mdb_printf("State %6s%*s %6s%*s %-5s %-4s%</u>\n",
}
static int
void *cbdata)
{
return (DCMD_ERR);
}
return (DCMD_OK);
}
static int
void *cbdata)
{
}
}
return (status);
}
/*ARGSUSED*/
int
{
int status;
int af = 0;
return (DCMD_USAGE);
return (DCMD_USAGE);
if (opts & NETSTAT_ROUTE)
return (DCMD_USAGE);
}
opts |= NETSTAT_V4;
opts |= NETSTAT_V6;
opts |= NETSTAT_UNIX;
else
return (DCMD_USAGE);
if (opts & NETSTAT_ROUTE) {
return (DCMD_USAGE);
if (opts & NETSTAT_V4) {
opts |= NETSTAT_FIRST;
mdb_warn("failed to walk ip`ire");
return (DCMD_ERR);
}
}
if (opts & NETSTAT_V6) {
opts |= NETSTAT_FIRST;
mdb_warn("failed to walk ip`ire");
return (DCMD_ERR);
}
}
return (DCMD_OK);
}
/* Print Unix Domain Sockets */
mdb_printf("%<u>%-?s %-10s %-?s %-?s %-14s %-14s %s%</u>\n",
"AF_UNIX", "Type", "Vnode", "Conn", "Local Addr",
"Remote Addr", "Zone");
mdb_warn("failed to walk genunix`sonode");
return (DCMD_ERR);
}
return (DCMD_OK);
}
goto out;
}
goto out;
}
goto out;
}
out:
return (status);
}
/*
* "::dladm show-bridge" support
*/
typedef struct {
const char *name;
/*
* These structures are kept inside the 'args' for allocation reasons.
* They're all large data structures (over 1K), and may cause the stack
* to explode. mdb and kmdb will fail in these cases, and thus we
* allocate them from the heap.
*/
static void
{
int i, bit;
for (i = 0; i < BRIDGE_VLAN_ARR_SIZE; i++) {
if (i == 0)
val &= ~1;
bit--;
if (rstart != -1)
mdb_printf(",");
}
}
}
mdb_printf("\n");
}
/*
* This callback is invoked by a walk of the links attached to a bridge. If
* we're showing link details, then they're printed here. If not, then we just
* count up the links for the bridge summary.
*/
static int
{
const char *name;
return (WALK_NEXT);
name = "?";
} else {
}
sizeof (macaddr));
case BLS_BLOCKLISTEN:
name = "BLOCK";
break;
case BLS_LEARNING:
name = "LEARN";
break;
case BLS_FORWARDING:
name = "FWD";
break;
default:
name = "?";
}
} else {
}
return (WALK_NEXT);
}
/*
* It seems a shame to duplicate this code, but merging it with the link
* printing code above is more trouble than it would be worth.
*/
static void
{
const char *name;
return;
}
name = "?";
} else {
}
}
static int
{
int i;
#define MAX_FWD_LINKS 16
return (WALK_NEXT);
mdb_warn("cannot read bridge forwarding links at %p",
return (WALK_ERR);
}
else
if (bfp->bf_trill_nick != 0) {
} else {
}
}
return (WALK_NEXT);
}
static int
{
const bridge_inst_t *bip;
char bname[MAXLINKNAMELEN];
char *cp;
int i;
} else {
return (WALK_ERR);
}
}
return (WALK_NEXT);
"MAC-ADDR", "FLG", "PVID");
else
}
return (WALK_ERR);
"REFS", "OUTPUT");
return (WALK_ERR);
nnicks = 0;
mdb_warn("cannot read trill instance at %p",
bip->bi_trilldata);
return (WALK_ERR);
}
"NICK", "NEXT-HOP", "LINK");
for (i = 0; i < RBRIDGE_NICKNAME_MAX; i++) {
continue;
mdb_warn("cannot read trill node %d at "
return (WALK_ERR);
}
mdb_warn("cannot read trill node info "
return (WALK_ERR);
}
}
mdb_printf("%-?p %-5u %-17s ",
macaddr);
mdb_warn("cannot read trill "
"socket info at %p",
return (WALK_ERR);
}
'\n');
continue;
}
}
mdb_printf("--\n");
} else {
nnicks++;
}
}
} else {
mdb_printf("bridge is not running TRILL\n");
}
else
}
return (WALK_NEXT);
}
static int
{
int i;
NULL);
argc -= i;
argv += i;
return (DCMD_USAGE);
}
if (argc == 1)
mdb_warn("failed to read lbolt");
goto err;
}
if (flags & DCMD_ADDRSPEC) {
mdb_printf("bridge name and address are mutually "
"exclusive\n");
goto err;
}
"PROTECT", "NAME", "NLINKS", "NFWD");
goto err;
return (DCMD_OK);
} else {
mdb_printf("need bridge name or address with -[lft]\n");
goto err;
}
mdb_warn("failed to find 'bridge`inst_list'");
goto err;
}
mdb_printf("%-?s %-7s %-16s %-7s %-7s %-7s %s\n",
"ADDR", "PROTECT", "NAME", "NLINKS", "NFWD",
"NNICKS", "NICK");
goto err;
mdb_printf("bridge instance %s not found\n",
goto err;
}
return (DCMD_OK);
}
err:
return (DCMD_ERR);
}
/*
* Support for the "::dladm" dcmd
*/
int
{
return (DCMD_USAGE);
/*
* This could be a bit more elaborate, once we support more of the
* dladm show-* subcommands.
*/
argc--;
argv++;
return (DCMD_USAGE);
}
void
dladm_help(void)
{
mdb_printf("Subcommands:\n"
" show-bridge [-flt] [<name>]\n"
"\t Show bridge information; -l for links and -f for "
"forwarding\n"
"\t entries, and -t for TRILL nicknames. Address is required "
"if name\n"
"\t is not specified.\n");
}