/*
* 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 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <stdio.h>
#include <ctype.h>
#include <locale.h>
#include <signal.h>
#include <stdarg.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <stropts.h>
#include <errno.h>
#include <strings.h>
#include <getopt.h>
#include <unistd.h>
#include <priv.h>
#include <termios.h>
#include <pwd.h>
#include <auth_attr.h>
#include <auth_list.h>
#include <libintl.h>
#include <libdevinfo.h>
#include <libdlpi.h>
#include <libdladm.h>
#include <libdllink.h>
#include <libdlstat.h>
#include <libdlaggr.h>
#include <libinetutil.h>
#include <bsm/adt_event.h>
#include <stddef.h>
#include <ofmt.h>
typedef struct link_chain_s {
} link_chain_t;
typedef void * (*stats2str_t)(const char *, void *,
char, boolean_t);
typedef struct show_state {
char ls_unit;
} show_state_t;
typedef struct show_history_state_s {
/*
* callback functions for printing output and error diagnostics.
*/
typedef void cmdfunc_t(int, char **, const char *);
static void die(const char *, ...);
static void die_optdup(int);
static void die_opterr(int, int, const char *);
static void die_dlerr(dladm_status_t, const char *, ...);
static void warn(const char *, ...);
typedef struct cmd {
char *c_name;
const char *c_usage;
} cmd_t;
{ "", do_show,
"dlstat [-r | -t] [-i <interval>] [link]\n"
" dlstat [-a | -A] [-i <interval>] [-p] [ -o field[,...]]\n"
" [-u R|K|M|G|T|P] [link]"},
{ "show-phys", do_show_phys,
"dlstat show-phys [-r | -t] [-i interval] [-a]\n"
" [-p] [ -o field[,...]] [-u R|K|M|G|T|P] "
"[link]"},
{ "show-link", do_show_link,
"dlstat show-link [-r [-F] | -t] [-i interval] [-a]\n"
" [-p] [ -o field[,...]] [-u R|K|M|G|T|P] "
"[link]\n"
" dlstat show-link -h [-a] [-d] [-F <format>]\n"
" -f <logfile> [<link>]" },
{ "show-aggr", do_show_aggr,
"dlstat show-aggr [-r | -t] [-i interval] [-p]\n"
" [ -o field[,...]] [-u R|K|M|G|T|P] "
" [link]" }
};
/*
* dlstat : total stat fields
*/
typedef struct total_fields_buf_s {
{ "LINK", 15,
{ "IPKTS", 8,
{ "RBYTES", 8,
{ "OPKTS", 8,
{ "OBYTES", 8,
/*
* dlstat show-phys: both Rx and Tx stat fields
*/
typedef struct ring_fields_buf_s {
{ "LINK", 15,
{ "TYPE", 5,
{ "ID", 7,
{ "INDEX", 6,
{ "PKTS", 8,
{ "BYTES", 8,
/*
* dlstat show-phys -r: Rx Ring stat fields
*/
typedef struct rx_ring_fields_buf_s {
{ "LINK", 15,
{ "TYPE", 5,
{ "ID", 7,
{ "INDEX", 6,
{ "IPKTS", 8,
{ "RBYTES", 8,
/*
* dlstat show-phys -t: Tx Ring stat fields
*/
typedef struct tx_ring_fields_buf_s {
{ "LINK", 15,
{ "TYPE", 5,
{ "ID", 7,
{ "INDEX", 6,
{ "OPKTS", 8,
{ "OBYTES", 8,
/*
* dlstat show-link: both Rx and Tx lane fields
*/
typedef struct lane_fields_buf_s {
{ "LINK", 15,
{ "TYPE", 5,
{ "ID", 7,
{ "INDEX", 6,
{ "PKTS", 8,
{ "BYTES", 8,
/*
* dlstat show-link -r, dlstat -r: Rx Lane stat fields
*/
typedef struct rx_lane_fields_buf_s {
{ "LINK", 10,
{ "TYPE", 5,
{ "ID", 7,
{ "INDEX", 6,
{ "IPKTS", 8,
{ "RBYTES", 8,
{ "INTRS", 8,
{ "POLLS", 8,
{ "SDROPS", 8,
{ "CH<10", 8,
{ "CH10-50", 8,
{ "CH>50", 8,
/*
* dlstat show-link -r -F: Rx fanout stat fields
*/
typedef struct rx_fanout_lane_fields_buf_s {
{ "LINK", 15,
{ "TYPE", 5,
{ "ID", 7,
{ "INDEX", 6,
{ "FOUT", 6,
{ "IPKTS", 8,
{ "RBYTES", 8,
/*
* dlstat show-link -t: Tx Lane stat fields
*/
typedef struct tx_lane_fields_buf_s {
{ "LINK", 15,
{ "TYPE", 5,
{ "ID", 7,
{ "INDEX", 6,
{ "OPKTS", 8,
{ "OBYTES", 8,
{ "BLKCNT", 8,
{ "UBLKCNT", 8,
{ "SDROPS", 8,
/*
* dlstat show-aggr: aggr port stat fields
*/
typedef struct aggr_port_fields_buf_s {
{ "LINK", 15,
{ "PORT", 15,
{ "IPKTS", 8,
{ "RBYTES", 8,
{ "OPKTS", 8,
{ "OBYTES", 8,
/*
* structures for 'dlstat show-link -h'
*/
typedef struct history_fields_buf_s {
{ "LINK", 13,
{ "DURATION", 11,
{ "IPKTS", 10,
{ "RBYTES", 11,
{ "OPKTS", 10,
{ "OBYTES", 11,
{ "BANDWIDTH", 15,
/*
* structures for 'dlstat show-link -h link'
*/
typedef struct history_l_fields_buf_s {
/* name, field width, offset */
{ "LINK", 13,
{ "START", 14,
{ "END", 14,
{ "RBYTES", 9,
{ "OBYTES", 9,
{ "BANDWIDTH", 15,
;
static char *progname;
/*
* Handle to libdladm. Opened in main() before the sub-command
* specific function is called.
*/
static void
usage(void)
{
int i;
}
/* close dladm handle if it was opened */
exit(1);
}
int
{
int i;
#if !defined(TEXT_DOMAIN)
#endif
(void) textdomain(TEXT_DOMAIN);
/* Open the libdladm handle */
if (argc == 1) {
goto done;
}
goto done;
}
}
done:
return (0);
}
/*ARGSUSED*/
static int
{
/*
* Only show history information for existing links unless '-a'
* is specified.
*/
if (!state->hs_showall) {
return (status);
}
if ((flags & DLADM_OPT_ACTIVE) == 0)
return (DLADM_STATUS_LINKINVAL);
}
return (DLADM_STATUS_OK);
}
static int
{
double bw;
/*
* Only show history information for existing links unless '-a'
* is specified.
*/
if (!state->hs_showall) {
return (status);
}
if ((flags & DLADM_OPT_ACTIVE) == 0)
return (DLADM_STATUS_LINKINVAL);
}
if (!state->hs_printheader) {
(void) printf("# Time");
}
(void) printf("\n");
}
} else {
}
(void) printf("\n");
}
}
return (DLADM_STATUS_OK);
}
buf);
buf);
return (DLADM_STATUS_OK);
}
static int
{
/*
* Only show history information for existing links unless '-a'
* is specified.
*/
if (!state->hs_showall) {
return (status);
}
if ((flags & DLADM_OPT_ACTIVE) == 0)
return (DLADM_STATUS_LINKINVAL);
}
return (DLADM_STATUS_OK);
}
static boolean_t
{
}
/*ARGSUSED*/
static void
{
int opt;
char *all_l_fields =
"link,start,end,rbytes,obytes,bandwidth";
switch (opt) {
case 'd':
break;
case 'a':
break;
case 'f':
break;
case 's':
break;
case 'e':
break;
case 'o':
fields_str = optarg;
break;
case 'F':
break;
default:
break;
}
}
die("show-link -h requires a file");
if (!state.hs_showall &&
((flags & DLADM_OPT_ACTIVE) == 0))) {
}
}
die("incompatible -d and -F options");
if (state.hs_parsable)
&ofmt);
} else {
&ofmt);
}
if (d_arg) {
/* Print log dates */
!F_arg) {
/* Print summary */
/* Print log entries for named resource */
} else {
/* Print time and information for each link */
}
if (status != DLADM_STATUS_OK)
}
{
return (B_TRUE);
}
return (B_FALSE);
}
void
{
if (parsable) {
return;
}
if (unit == '\0') {
int index;
;
switch (index) {
case 0:
unit = '\0';
break;
case 1:
unit = 'K';
break;
case 2:
unit = 'M';
break;
case 3:
unit = 'G';
break;
case 4:
unit = 'T';
break;
case 5:
/* Largest unit supported */
default:
unit = 'P';
break;
}
} else {
switch (unit) {
case 'R':
/* Already raw numbers */
unit = '\0';
break;
case 'K':
num /= 1000;
break;
case 'M':
break;
case 'G':
break;
case 'T':
break;
case 'P':
/* Largest unit supported */
default:
break;
}
}
if (unit == '\0')
else
}
{
/* Scan prev linkid list and look for entry matching this entry */
break;
}
/* New link, add it */
goto done;
sizeof (link_curr->lc_statchain));
}
done:
return (link_curr);
}
/*
* Number of links may change while dlstat with -i is executing.
* Free memory allocated for links that are no longer there.
* Prepare for next iteration by marking visited = false for existing stat
* entries.
*/
static void
{
int i;
/* Delete all nodes from the list that have lc_visited marked false */
if (lcurr->lc_visited) {
continue;
}
/* Is it head of the list? */
else
/* lprev remains the same */
/* Free stats memory for the removed link */
for (i = 0; i < DLADM_STAT_NUM_STATS; i++) {
if (state->ls_stattype[i])
}
}
}
void *
{
goto done;
linkname);
done:
return (buf);
}
void *
{
goto done;
linkname);
} else {
}
done:
return (buf);
}
void *
{
goto done;
linkname);
} else {
}
done:
return (buf);
}
void *
{
goto done;
linkname);
} else {
}
done:
return (buf);
}
void *
{
goto done;
linkname);
} else {
}
done:
return (buf);
}
void *
{
return (NULL);
goto done;
linkname);
else
} else {
}
done:
return (buf);
}
void *
{
return (NULL);
goto done;
linkname);
else
} else {
}
done:
return (buf);
}
void *
{
return (NULL);
goto done;
linkname);
else
} else {
}
done:
return (buf);
}
void *
{
return (NULL);
goto done;
linkname);
else
} else {
}
done:
return (buf);
}
void *
{
goto done;
linkname);
else
} else {
}
else {
}
done:
return (buf);
}
void *
{
goto done;
linkname);
!= DLADM_STATUS_OK) {
} else {
}
done:
return (buf);
}
{
/* Get prev iteration stat for this link */
goto done;
/* Query library for current stats */
goto done;
/* current stats - prev iteration stats */
/* Free prev stats */
/* Prev <- curr stats */
done:
return (diff_stat);
}
void
{
/* Unpack invidual stat entry and call library consumer's callback */
void *fields_buf;
/* Format the raw numbers for printing */
/* Print the stats */
if (fields_buf != NULL)
}
}
static int
{
int i;
DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
goto done;
}
for (i = 0; i < DLADM_STAT_NUM_STATS; i++) {
if (state->ls_stattype[i]) {
/*
* Query library for stats
* Stats are returned as chain of raw numbers
*/
}
}
done:
return (DLADM_WALK_CONTINUE);
}
void
{
for (;;) {
if (linkid == DATALINK_ALL_LINKID) {
} else {
}
if (interval == 0)
break;
}
}
void
{
return;
/*
* Print header
* If link name is already printed in previous iteration,
* don't print again
*/
/* Print stat fields */
}
}
if (stat_printed)
printf("---------------------------------------------------\n");
}
static int
{
int i;
for (i = 0; i < DLADM_STAT_NUM_STATS; i++) {
if (stattype[i]) {
}
}
done:
return (DLADM_WALK_CONTINUE);
}
void
{
if (linkid == DATALINK_ALL_LINKID) {
} else {
}
}
static void
{
int option;
char *total_stat_fields =
"link,ipkts,rbytes,opkts,obytes";
char *rx_total_stat_fields =
"link,ipkts,rbytes,intrs,polls,ch<10,ch10-50,ch>50";
char *tx_total_stat_fields =
"link,opkts,obytes,blkcnt,ublkcnt";
opterr = 0;
switch (option) {
case 'r':
if (r_arg)
break;
case 't':
if (t_arg)
break;
case 'a':
if (a_arg)
break;
case 'A':
if (A_arg)
break;
case 'i':
if (i_arg)
break;
case 'p':
if (p_arg)
break;
case 'o':
break;
case 'u':
if (u_arg)
die("invalid unit value '%s',"
"unit must be R|K|M|G|T|P", optarg);
break;
default:
break;
}
}
die("the options -t and -r are not compatible");
die("the options -u and -p are not compatible");
die("-p requires -o");
die("\"-o all\" is invalid with -p");
die("the options -a and -A are not compatible");
if (a_arg &&
die("the option -a is not compatible with "
"-p, -o, -u, -i");
}
if (A_arg &&
die("the option -A is not compatible with "
"-r, -t, -p, -o, -u, -i");
}
/* get link name (optional last argument) */
die("link name too long");
}
if (argc != 0)
usage();
}
if (a_arg) {
if (r_arg) {
} else if (t_arg) {
} else { /* Display both Rx and Tx lanes */
}
return;
}
if (A_arg) {
int i;
for (i = 0; i < DLADM_STAT_NUM_STATS; i++)
return;
}
if (state.ls_parsable)
if (r_arg) {
} else if (t_arg) {
} else { /* Display both Rx and Tx lanes total */
}
if (o_arg) {
}
}
static void
{
int option;
char *ring_stat_fields =
"link,type,index,pkts,bytes";
char *rx_ring_stat_fields =
"link,type,index,ipkts,rbytes";
char *tx_ring_stat_fields =
"link,type,index,opkts,obytes";
opterr = 0;
switch (option) {
case 'r':
if (r_arg)
break;
case 't':
if (t_arg)
break;
case 'a':
if (a_arg)
break;
case 'i':
if (i_arg)
break;
case 'p':
if (p_arg)
break;
case 'o':
break;
case 'u':
if (u_arg)
die("invalid unit value '%s',"
"unit must be R|K|M|G|T|P", optarg);
break;
default:
break;
}
}
die("the options -t and -r are not compatible");
die("the options -u and -p are not compatible");
die("-p requires -o");
die("\"-o all\" is invalid with -p");
if (a_arg &&
die("the option -a is not compatible with "
"-p, -o, -u, -i");
}
/* get link name (optional last argument) */
die("link name too long");
}
usage();
}
if (a_arg) {
if (r_arg) {
} else if (t_arg) {
} else { /* Display both Rx and Tx lanes */
}
return;
}
if (state.ls_parsable)
if (r_arg) {
} else if (t_arg) {
} else { /* Display both Rx and Tx lanes */
}
if (o_arg) {
}
}
static void
{
int option;
char *lane_stat_fields =
"link,type,id,index,pkts,bytes";
char *rx_lane_stat_fields =
"link,type,id,index,ipkts,rbytes,intrs,polls,ch<10,ch10-50,ch>50";
char *tx_lane_stat_fields =
"link,type,id,index,opkts,obytes,blkcnt,ublkcnt";
char *rx_fanout_stat_fields =
"link,id,index,fout,ipkts,rbytes";
opterr = 0;
switch (option) {
case 'h':
die("the option -h is not compatible with "
"-r, -F, -t, -i, -p, -o, -u, -a");
}
return;
case 'r':
if (r_arg)
break;
case 'F':
if (F_arg)
break;
case 't':
if (t_arg)
break;
case 'a':
if (a_arg)
break;
case 'i':
if (i_arg)
break;
case 'p':
if (p_arg)
break;
case 'o':
break;
case 'u':
if (u_arg)
die("invalid unit value '%s',"
"unit must be R|K|M|G|T|P", optarg);
break;
default:
break;
}
}
die("the options -t and -r are not compatible");
die("the options -u and -p are not compatible");
die("-F must be used with -r");
die("-p requires -o");
die("\"-o all\" is invalid with -p");
if (a_arg &&
die("the option -a is not compatible with "
"-p, -o, -u, -i");
}
/* get link name (optional last argument) */
die("link name too long");
}
usage();
}
if (a_arg) {
if (r_arg) {
if (F_arg) {
} else {
}
} else if (t_arg) {
} else { /* Display both Rx and Tx lanes */
}
return;
}
if (state.ls_parsable)
if (r_arg) {
if (F_arg) {
} else {
}
} else if (t_arg) {
} else { /* Display both Rx and Tx lanes */
}
if (o_arg) {
}
}
static void
{
int option;
char *aggr_stat_fields =
"link,port,ipkts,rbytes,opkts,obytes";
opterr = 0;
switch (option) {
case 'r':
if (r_arg)
break;
case 't':
if (t_arg)
break;
case 'i':
if (i_arg)
break;
case 'p':
if (p_arg)
break;
case 'o':
break;
case 'u':
if (u_arg)
die("invalid unit value '%s',"
"unit must be R|K|M|G|T|P", optarg);
break;
default:
break;
}
}
die("the options -t and -r are not compatible");
die("the options -u and -p are not compatible");
die("-p requires -o");
die("\"-o all\" is invalid with -p");
/* get link name (optional last argument) */
die("link name too long");
}
usage();
}
if (state.ls_parsable)
if (r_arg)
else if (t_arg)
else
if (o_arg) {
}
}
/* PRINTFLIKE1 */
static void
{
}
/*
* Also closes the dladm handle if it is not NULL.
*/
/* PRINTFLIKE2 */
static void
{
/* close dladm handle if it was opened */
}
/* PRINTFLIKE1 */
static void
{
/* close dladm handle if it was opened */
}
static void
{
}
static void
{
switch (opterr) {
case ':':
break;
case '?':
default:
break;
}
}
/*
* default output callback function that, when invoked,
* prints string which is offset by ofmt_arg->ofmt_id within buf.
*/
static boolean_t
{
char *value;
return (B_TRUE);
}
static void
{
if (oferr == OFMT_SUCCESS)
return;
/*
* All errors are considered fatal in parsable mode.
* NOMEM errors are always fatal, regardless of mode.
* For other errors, we print diagnostics in human-readable
* mode and processs what we can.
*/
} else {
}
}