File: [local] / src / usr.bin / systat / if.c (download)
Revision 1.12, Thu Jun 12 22:26:01 2008 UTC (15 years, 11 months ago) by canacar
Branch: MAIN
CVS Tags: OPENBSD_4_5_BASE, OPENBSD_4_5, OPENBSD_4_4_BASE, OPENBSD_4_4 Changes since 1.11: +164 -103 lines
New display engine for systat, based on pftop. Adds new views for pf
(status, state, rule, queue). While all displays work, some keyboard
comands are not implemented yet. Other features include better handling
of display resize and scrolling for long views. Committing now to fix
the remaining issues in the tree.
Testing and comments by otto@ and harding@, ok deraadt@
|
/* $OpenBSD: if.c,v 1.12 2008/06/12 22:26:01 canacar Exp $ */
/*
* Copyright (c) 2004 Markus Friedl <markus@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/route.h>
#include <stdlib.h>
#include <string.h>
#include "systat.h"
static enum state { BOOT, TIME, RUN } state = TIME;
struct ifcount {
u_int64_t ifc_ib; /* input bytes */
u_int64_t ifc_ip; /* input packets */
u_int64_t ifc_ie; /* input errors */
u_int64_t ifc_ob; /* output bytes */
u_int64_t ifc_op; /* output packets */
u_int64_t ifc_oe; /* output errors */
u_int64_t ifc_co; /* collisions */
int ifc_flags; /* up / down */
int ifc_state; /* link state */
} sum;
struct ifstat {
char ifs_name[IFNAMSIZ]; /* interface name */
struct ifcount ifs_cur;
struct ifcount ifs_old;
struct ifcount ifs_now;
} *ifstats;
static int nifs = 0;
static int num_ifs = 0;
void print_if(void);
int read_if(void);
int select_if(void);
int if_keyboard_callback(int);
static void fetchifstat(void);
static void showifstat(struct ifstat *);
static void showtotal(void);
/* Define fields */
field_def fields_if[] = {
{"IFACE", 8, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
{"STATE", 10, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
{"IPKTS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
{"IBYTES", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
{"IERRS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
{"OPKTS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
{"OBYTES", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
{"OERRS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
{"COLLS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
};
#define FIELD_ADDR(x) (&fields_if[x])
#define FLD_IF_IFACE FIELD_ADDR(0)
#define FLD_IF_STATE FIELD_ADDR(1)
#define FLD_IF_IPKTS FIELD_ADDR(2)
#define FLD_IF_IBYTES FIELD_ADDR(3)
#define FLD_IF_IERRS FIELD_ADDR(4)
#define FLD_IF_OPKTS FIELD_ADDR(5)
#define FLD_IF_OBYTES FIELD_ADDR(6)
#define FLD_IF_OERRS FIELD_ADDR(7)
#define FLD_IF_COLLS FIELD_ADDR(8)
/* Define views */
field_def *view_if_0[] = {
FLD_IF_IFACE, FLD_IF_STATE, FLD_IF_IPKTS, FLD_IF_IBYTES,
FLD_IF_IERRS, FLD_IF_OPKTS, FLD_IF_OBYTES, FLD_IF_OERRS,
FLD_IF_COLLS, NULL
};
/* Define view managers */
struct view_manager ifstat_mgr = {
"Ifstat", select_if, read_if, NULL, print_header,
print_if, if_keyboard_callback, NULL, NULL
};
field_view views_if[] = {
{view_if_0, "ifstat", '1', &ifstat_mgr},
{NULL, NULL, 0, NULL}
};
int
initifstat(void)
{
field_view *v;
read_if();
for (v = views_if; v->name != NULL; v++)
add_view(v);
return(1);
}
#define UPDATE(x, y) do { \
ifs->ifs_now.x = ifm.y; \
ifs->ifs_cur.x = ifs->ifs_now.x - ifs->ifs_old.x; \
if (state == TIME) {\
ifs->ifs_old.x = ifs->ifs_now.x; \
ifs->ifs_cur.x /= naptime; \
} \
sum.x += ifs->ifs_cur.x; \
} while(0)
void
rt_getaddrinfo(struct sockaddr *sa, int addrs, struct sockaddr **info)
{
int i;
for (i = 0; i < RTAX_MAX; i++) {
if (addrs & (1 << i)) {
info[i] = sa;
sa = (struct sockaddr *) ((char *)(sa) +
roundup(sa->sa_len, sizeof(long)));
} else
info[i] = NULL;
}
}
int
select_if(void)
{
num_disp = num_ifs + 1;
return (0);
}
int
read_if(void)
{
fetchifstat();
num_disp = num_ifs + 1;
return 0;
}
void
print_if(void)
{
int n, i, count = 0;
for (n = 0, i = 0; n < nifs; n++) {
if (ifstats[n].ifs_name[0] == '\0')
continue;
if (i++ < dispstart)
continue;
if (i == num_disp)
break;
showifstat(ifstats + n);
if (maxprint > 0 && ++count >= maxprint)
return;
}
showtotal();
}
static void
fetchifstat(void)
{
struct ifstat *newstats, *ifs;
struct if_msghdr ifm;
struct sockaddr *info[RTAX_MAX];
struct sockaddr_dl *sdl;
char *buf, *next, *lim;
int mib[6];
size_t need;
mib[0] = CTL_NET;
mib[1] = AF_ROUTE;
mib[2] = 0;
mib[3] = 0;
mib[4] = NET_RT_IFLIST;
mib[5] = 0;
if (sysctl(mib, 6, NULL, &need, NULL, 0) == -1)
return;
if ((buf = malloc(need)) == NULL)
return;
if (sysctl(mib, 6, buf, &need, NULL, 0) == -1) {
free(buf);
return;
}
bzero(&sum, sizeof(sum));
num_ifs = 0;
lim = buf + need;
for (next = buf; next < lim; next += ifm.ifm_msglen) {
bcopy(next, &ifm, sizeof ifm);
if (ifm.ifm_type != RTM_IFINFO ||
!(ifm.ifm_addrs & RTA_IFP))
continue;
if (ifm.ifm_index >= nifs) {
if ((newstats = realloc(ifstats, (ifm.ifm_index + 4)
* sizeof(struct ifstat))) == NULL)
continue;
ifstats = newstats;
for (; nifs < ifm.ifm_index + 4; nifs++)
bzero(&ifstats[nifs], sizeof(*ifstats));
}
ifs = &ifstats[ifm.ifm_index];
if (ifs->ifs_name[0] == '\0') {
bzero(&info, sizeof(info));
rt_getaddrinfo(
(struct sockaddr *)((struct if_msghdr *)next + 1),
ifm.ifm_addrs, info);
if ((sdl = (struct sockaddr_dl *)info[RTAX_IFP])) {
if (sdl->sdl_family == AF_LINK &&
sdl->sdl_nlen > 0) {
bcopy(sdl->sdl_data, ifs->ifs_name,
sdl->sdl_nlen);
ifs->ifs_name[sdl->sdl_nlen] = '\0';
}
}
if (ifs->ifs_name[0] == '\0')
continue;
}
num_ifs++;
UPDATE(ifc_ip, ifm_data.ifi_ipackets);
UPDATE(ifc_ib, ifm_data.ifi_ibytes);
UPDATE(ifc_ie, ifm_data.ifi_ierrors);
UPDATE(ifc_op, ifm_data.ifi_opackets);
UPDATE(ifc_ob, ifm_data.ifi_obytes);
UPDATE(ifc_oe, ifm_data.ifi_oerrors);
UPDATE(ifc_co, ifm_data.ifi_collisions);
ifs->ifs_cur.ifc_flags = ifm.ifm_flags;
ifs->ifs_cur.ifc_state = ifm.ifm_data.ifi_link_state;
}
free(buf);
}
static void
showifstat(struct ifstat *ifs)
{
print_fld_str(FLD_IF_IFACE, ifs->ifs_name);
tb_start();
tbprintf("%s", ifs->ifs_cur.ifc_flags & IFF_UP ?
"up" : "dn");
switch (ifs->ifs_cur.ifc_state) {
case LINK_STATE_UP:
case LINK_STATE_HALF_DUPLEX:
case LINK_STATE_FULL_DUPLEX:
tbprintf(":U");
break;
case LINK_STATE_DOWN:
tbprintf (":D");
break;
}
print_fld_tb(FLD_IF_STATE);
print_fld_size(FLD_IF_IBYTES, ifs->ifs_cur.ifc_ib);
print_fld_size(FLD_IF_IPKTS, ifs->ifs_cur.ifc_ip);
print_fld_size(FLD_IF_IERRS, ifs->ifs_cur.ifc_ie);
print_fld_size(FLD_IF_OBYTES, ifs->ifs_cur.ifc_ob);
print_fld_size(FLD_IF_OPKTS, ifs->ifs_cur.ifc_op);
print_fld_size(FLD_IF_OERRS, ifs->ifs_cur.ifc_oe);
print_fld_size(FLD_IF_COLLS, ifs->ifs_cur.ifc_co);
end_line();
}
static void
showtotal(void)
{
print_fld_str(FLD_IF_IFACE, "Totals");
print_fld_size(FLD_IF_IBYTES, sum.ifc_ib);
print_fld_size(FLD_IF_IPKTS, sum.ifc_ip);
print_fld_size(FLD_IF_IERRS, sum.ifc_ie);
print_fld_size(FLD_IF_OBYTES, sum.ifc_ob);
print_fld_size(FLD_IF_OPKTS, sum.ifc_op);
print_fld_size(FLD_IF_OERRS, sum.ifc_oe);
print_fld_size(FLD_IF_COLLS, sum.ifc_co);
end_line();
}
int
if_keyboard_callback(int ch)
{
struct ifstat *ifs;
switch (ch) {
case 'r':
for (ifs = ifstats; ifs < ifstats + nifs; ifs++)
ifs->ifs_old = ifs->ifs_now;
state = RUN;
gotsig_alarm = 1;
break;
case 'b':
state = BOOT;
for (ifs = ifstats; ifs < ifstats + nifs; ifs++)
bzero(&ifs->ifs_old, sizeof(ifs->ifs_old));
gotsig_alarm = 1;
break;
case 't':
state = TIME;
gotsig_alarm = 1;
break;
default:
return keyboard_callback(ch);
};
return 1;
}