File: [local] / src / usr.bin / systat / if.c (download)
Revision 1.7, Fri Jun 2 08:16:51 2006 UTC (18 years ago) by claudio
Branch: MAIN
CVS Tags: OPENBSD_4_0_BASE, OPENBSD_4_0 Changes since 1.6: +30 -7 lines
Show interface state and link state in ifstat output. Idea and OK dlg@
|
/* $OpenBSD: if.c,v 1.7 2006/06/02 08:16:51 claudio 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"
#include "extern.h"
static enum state { BOOT, TIME, RUN } state = TIME;
struct ifcount {
u_long ifc_ib; /* input bytes */
u_long ifc_ip; /* input packets */
u_long ifc_ie; /* input errors */
u_long ifc_ob; /* output bytes */
u_long ifc_op; /* output packets */
u_long ifc_oe; /* output errors */
u_long 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;
extern u_int naptime;
const char *showlinkstate(int);
WINDOW *
openifstat(void)
{
return (subwin(stdscr, LINES-5-1, 0, 5, 0));
}
void
closeifstat(WINDOW *w)
{
if (w == NULL)
return;
wclear(w);
wrefresh(w);
delwin(w);
}
int
initifstat(void)
{
fetchifstat();
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;
}
}
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));
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++)
ifstats[nifs].ifs_name[0] = '\0';
}
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;
}
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);
}
#define INSET 0
void
labelifstat(void)
{
wmove(wnd, 0, 0);
wclrtobot(wnd);
mvwaddstr(wnd, 1, INSET, "Iface");
mvwaddstr(wnd, 1, INSET+9, "State");
mvwaddstr(wnd, 1, INSET+19, "Ibytes");
mvwaddstr(wnd, 1, INSET+29, "Ipkts");
mvwaddstr(wnd, 1, INSET+36, "Ierrs");
mvwaddstr(wnd, 1, INSET+48, "Obytes");
mvwaddstr(wnd, 1, INSET+58, "Opkts");
mvwaddstr(wnd, 1, INSET+65, "Oerrs");
mvwaddstr(wnd, 1, INSET+74, "Colls");
}
#define FMT "%-8.8s %2s%2s %10lu %8lu %6lu %10lu %8lu %6lu %6lu "
const char *
showlinkstate(int state)
{
switch (state) {
case LINK_STATE_UP:
return (":U");
case LINK_STATE_DOWN:
return (":D");
case LINK_STATE_UNKNOWN:
return ("");
}
}
void
showifstat(void)
{
int row;
struct ifstat *ifs;
row = 2;
wmove(wnd, 0, 0);
wclrtoeol(wnd);
for (ifs = ifstats; ifs < ifstats + nifs; ifs++) {
if (ifs->ifs_name[0] == '\0')
continue;
mvwprintw(wnd, row++, INSET, FMT,
ifs->ifs_name,
ifs->ifs_cur.ifc_flags & IFF_UP ? "up" : "dn",
showlinkstate(ifs->ifs_cur.ifc_state),
ifs->ifs_cur.ifc_ib,
ifs->ifs_cur.ifc_ip,
ifs->ifs_cur.ifc_ie,
ifs->ifs_cur.ifc_ob,
ifs->ifs_cur.ifc_op,
ifs->ifs_cur.ifc_oe,
ifs->ifs_cur.ifc_co);
}
mvwprintw(wnd, row++, INSET, FMT,
"Totals",
"", "",
sum.ifc_ib,
sum.ifc_ip,
sum.ifc_ie,
sum.ifc_ob,
sum.ifc_op,
sum.ifc_oe,
sum.ifc_co);
}
int
cmdifstat(char *cmd, char *args)
{
struct ifstat *ifs;
if (prefix(cmd, "run")) {
if (state != RUN)
for (ifs = ifstats; ifs < ifstats + nifs; ifs++)
ifs->ifs_old = ifs->ifs_now;
state = RUN;
return (1);
}
if (prefix(cmd, "boot")) {
state = BOOT;
for (ifs = ifstats; ifs < ifstats + nifs; ifs++)
bzero(&ifs->ifs_old, sizeof(ifs->ifs_old));
return (1);
}
if (prefix(cmd, "time")) {
state = TIME;
return (1);
}
if (prefix(cmd, "zero")) {
if (state == RUN)
for (ifs = ifstats; ifs < ifstats + nifs; ifs++)
ifs->ifs_old = ifs->ifs_now;
return (1);
}
return (1);
}