Handle device removal and removal+add cases to fix infinity rate.

PR:		219829
Submitted by:	ota@j.email.ne.jp
Reported by:	rezo@live.cn
MFC after:	2 weeks
Differential Revision:	https://reviews.freebsd.org/D25226
This commit is contained in:
Michael Reifenberger 2020-07-11 13:56:36 +00:00
parent ce28fd95e0
commit 4b9ac8a0a6
3 changed files with 74 additions and 45 deletions

View File

@ -74,6 +74,8 @@ ifcmd(const char *cmd, const char *args)
} }
} else if (prefix(cmd, "pps")) } else if (prefix(cmd, "pps"))
showpps = !showpps; showpps = !showpps;
else
return (0);
return (1); return (1);
} }

View File

@ -37,6 +37,7 @@
#include <net/if.h> #include <net/if.h>
#include <net/if_mib.h> #include <net/if_mib.h>
#include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <err.h> #include <err.h>
@ -67,7 +68,8 @@ SLIST_HEAD(, if_stat_disp) displist;
struct if_stat { struct if_stat {
SLIST_ENTRY(if_stat) link; SLIST_ENTRY(if_stat) link;
char if_name[IF_NAMESIZE]; char display_name[IF_NAMESIZE];
char dev_name[IFNAMSIZ]; /* copied from ifmibdata */
struct ifmibdata if_mib; struct ifmibdata if_mib;
struct timeval tv; struct timeval tv;
struct timeval tv_lastchanged; struct timeval tv_lastchanged;
@ -81,7 +83,7 @@ struct if_stat {
uint64_t if_out_pps_peak; uint64_t if_out_pps_peak;
u_int if_row; /* Index into ifmib sysctl */ u_int if_row; /* Index into ifmib sysctl */
int if_ypos; /* -1 if not being displayed */ int if_ypos; /* -1 if not being displayed */
u_int display; bool display;
u_int match; u_int match;
}; };
@ -91,11 +93,13 @@ extern int showpps;
extern int needsort; extern int needsort;
static int needclear = 0; static int needclear = 0;
static bool displayall = false;
static void right_align_string(struct if_stat *); static void format_device_name(struct if_stat *);
static void getifmibdata(const int, struct ifmibdata *); static int getifmibdata(const int, struct ifmibdata *);
static void sort_interface_list(void); static void sort_interface_list(void);
static u_int getifnum(void); static u_int getifnum(void);
static void clearifstat(void);
#define IFSTAT_ERR(n, s) do { \ #define IFSTAT_ERR(n, s) do { \
putchar('\014'); \ putchar('\014'); \
@ -165,7 +169,7 @@ static u_int getifnum(void);
} while (0) } while (0)
#define PUTNAME(p) do { \ #define PUTNAME(p) do { \
mvprintw(p->if_ypos, 0, "%s", p->if_name); \ mvprintw(p->if_ypos, 0, "%s", p->display_name); \
mvprintw(p->if_ypos, col2-3, "%s", (const char *)"in"); \ mvprintw(p->if_ypos, col2-3, "%s", (const char *)"in"); \
mvprintw(p->if_ypos+1, col2-3, "%s", (const char *)"out"); \ mvprintw(p->if_ypos+1, col2-3, "%s", (const char *)"out"); \
} while (0) } while (0)
@ -214,7 +218,7 @@ showifstat(void)
SLIST_FOREACH(ifp, &curlist, link) { SLIST_FOREACH(ifp, &curlist, link) {
if (ifp->if_ypos < LINES - 3 && ifp->if_ypos != -1) if (ifp->if_ypos < LINES - 3 && ifp->if_ypos != -1)
if (ifp->display == 0 || ifp->match == 0) { if (!ifp->display || ifp->match == 0) {
wmove(wnd, ifp->if_ypos, 0); wmove(wnd, ifp->if_ypos, 0);
wclrtoeol(wnd); wclrtoeol(wnd);
wmove(wnd, ifp->if_ypos + 1, 0); wmove(wnd, ifp->if_ypos + 1, 0);
@ -235,7 +239,7 @@ int
initifstat(void) initifstat(void)
{ {
struct if_stat *p = NULL; struct if_stat *p = NULL;
u_int n = 0, i = 0; u_int n, i;
n = getifnum(); n = getifnum();
if (n <= 0) if (n <= 0)
@ -247,18 +251,21 @@ initifstat(void)
p = (struct if_stat *)calloc(1, sizeof(struct if_stat)); p = (struct if_stat *)calloc(1, sizeof(struct if_stat));
if (p == NULL) if (p == NULL)
IFSTAT_ERR(1, "out of memory"); IFSTAT_ERR(1, "out of memory");
SLIST_INSERT_HEAD(&curlist, p, link);
p->if_row = i+1; p->if_row = i+1;
getifmibdata(p->if_row, &p->if_mib); if (getifmibdata(p->if_row, &p->if_mib) == -1) {
right_align_string(p); free(p);
continue;
}
SLIST_INSERT_HEAD(&curlist, p, link);
format_device_name(p);
p->match = 1; p->match = 1;
/* /*
* Initially, we only display interfaces that have * Initially, we only display interfaces that have
* received some traffic. * received some traffic unless display-all is on.
*/ */
if (p->if_mib.ifmd_data.ifi_ibytes != 0) if (displayall || p->if_mib.ifmd_data.ifi_ibytes != 0)
p->display = 1; p->display = true;
} }
sort_interface_list(); sort_interface_list();
@ -269,13 +276,13 @@ initifstat(void)
void void
fetchifstat(void) fetchifstat(void)
{ {
struct if_stat *ifp = NULL; struct if_stat *ifp = NULL, *temp_var;
struct timeval tv, new_tv, old_tv; struct timeval tv, new_tv, old_tv;
double elapsed = 0.0; double elapsed = 0.0;
uint64_t new_inb, new_outb, old_inb, old_outb = 0; uint64_t new_inb, new_outb, old_inb, old_outb = 0;
uint64_t new_inp, new_outp, old_inp, old_outp = 0; uint64_t new_inp, new_outp, old_inp, old_outp = 0;
SLIST_FOREACH(ifp, &curlist, link) { SLIST_FOREACH_SAFE(ifp, &curlist, link, temp_var) {
/* /*
* Grab a copy of the old input/output values before we * Grab a copy of the old input/output values before we
* call getifmibdata(). * call getifmibdata().
@ -287,7 +294,22 @@ fetchifstat(void)
ifp->tv_lastchanged = ifp->if_mib.ifmd_data.ifi_lastchange; ifp->tv_lastchanged = ifp->if_mib.ifmd_data.ifi_lastchange;
(void)gettimeofday(&new_tv, NULL); (void)gettimeofday(&new_tv, NULL);
(void)getifmibdata(ifp->if_row, &ifp->if_mib); if (getifmibdata(ifp->if_row, &ifp->if_mib) == -1 ) {
/* if a device was removed */
SLIST_REMOVE(&curlist, ifp, if_stat, link);
free(ifp);
needsort = 1;
clearifstat();
} else if (strcmp(ifp->dev_name, ifp->if_mib.ifmd_name) != 0 ) {
/* a device was removed and another one was added */
format_device_name(ifp);
/* clear to the current value for the new device */
old_inb = ifp->if_mib.ifmd_data.ifi_ibytes;
old_outb = ifp->if_mib.ifmd_data.ifi_obytes;
old_inp = ifp->if_mib.ifmd_data.ifi_ipackets;
old_outp = ifp->if_mib.ifmd_data.ifi_opackets;
needsort = 1;
}
new_inb = ifp->if_mib.ifmd_data.ifi_ibytes; new_inb = ifp->if_mib.ifmd_data.ifi_ibytes;
new_outb = ifp->if_mib.ifmd_data.ifi_obytes; new_outb = ifp->if_mib.ifmd_data.ifi_obytes;
@ -295,8 +317,8 @@ fetchifstat(void)
new_outp = ifp->if_mib.ifmd_data.ifi_opackets; new_outp = ifp->if_mib.ifmd_data.ifi_opackets;
/* Display interface if it's received some traffic. */ /* Display interface if it's received some traffic. */
if (new_inb > 0 && old_inb == 0) { if (!ifp->display && new_inb > 0 && old_inb == 0) {
ifp->display = 1; ifp->display = true;
needsort = 1; needsort = 1;
} }
@ -351,28 +373,18 @@ fetchifstat(void)
/* /*
* We want to right justify our interface names against the first column * We want to right justify our interface names against the first column
* (first sixteen or so characters), so we need to do some alignment. * (first sixteen or so characters), so we need to do some alignment.
* We save original name so that we can find a same spot is take by a
* different device.
*/ */
static void static void
right_align_string(struct if_stat *ifp) format_device_name(struct if_stat *ifp)
{ {
int str_len = 0, pad_len = 0;
char *newstr = NULL, *ptr = NULL;
if (ifp == NULL || ifp->if_mib.ifmd_name == NULL) if (ifp != NULL ) {
return; snprintf(ifp->display_name, IF_NAMESIZE, "%*s", IF_NAMESIZE-1,
else { ifp->if_mib.ifmd_name);
/* string length + '\0' */ strcpy(ifp->dev_name, ifp->if_mib.ifmd_name);
str_len = strlen(ifp->if_mib.ifmd_name)+1;
pad_len = IF_NAMESIZE-(str_len);
newstr = ifp->if_name;
ptr = newstr + pad_len;
(void)memset((void *)newstr, (int)' ', IF_NAMESIZE);
(void)strncpy(ptr, (const char *)&ifp->if_mib.ifmd_name,
str_len);
} }
return;
} }
static int static int
@ -461,9 +473,10 @@ getifnum(void)
return (data); return (data);
} }
static void static int
getifmibdata(int row, struct ifmibdata *data) getifmibdata(int row, struct ifmibdata *data)
{ {
int ret = 0;
size_t datalen = 0; size_t datalen = 0;
static int name[] = { CTL_NET, static int name[] = { CTL_NET,
PF_LINK, PF_LINK,
@ -474,9 +487,12 @@ getifmibdata(int row, struct ifmibdata *data)
datalen = sizeof(*data); datalen = sizeof(*data);
name[4] = row; name[4] = row;
if ((sysctl(name, 6, (void *)data, (size_t *)&datalen, (void *)NULL, ret = sysctl(name, 6, (void *)data, (size_t *)&datalen, (void *)NULL,
(size_t)0) != 0) && (errno != ENOENT)) (size_t)0);
if ((ret != 0) && (errno != ENOENT))
IFSTAT_ERR(2, "sysctl error getting interface data"); IFSTAT_ERR(2, "sysctl error getting interface data");
return (ret);
} }
int int
@ -487,13 +503,23 @@ cmdifstat(const char *cmd, const char *args)
retval = ifcmd(cmd, args); retval = ifcmd(cmd, args);
/* ifcmd() returns 1 on success */ /* ifcmd() returns 1 on success */
if (retval == 1) { if (retval == 1) {
if (needclear) { if (needclear)
showifstat(); clearifstat();
refresh(); }
werase(wnd); else if (prefix(cmd, "all")) {
labelifstat(); retval = 1;
needclear = 0; displayall = true;
}
} }
return (retval); return (retval);
} }
static void
clearifstat(void)
{
showifstat();
refresh();
werase(wnd);
labelifstat();
needclear = 0;
}

View File

@ -680,6 +680,7 @@ in Silicon Graphics'
system. system.
.Sh BUGS .Sh BUGS
Certain displays presume a minimum of 80 characters per line. Certain displays presume a minimum of 80 characters per line.
Ifstat does not detect new interfaces.
The The
.Ic vmstat .Ic vmstat
display looks out of place because it is (it was added in as display looks out of place because it is (it was added in as