Merge branch 'master' into net-next

This commit is contained in:
Stephen Hemminger 2017-02-06 14:13:27 -08:00
commit 818a10a77f
6 changed files with 173 additions and 22 deletions

View File

@ -144,7 +144,7 @@ static void hsr_print_help(struct link_util *lu, int argc, char **argv,
struct link_util hsr_link_util = {
.id = "hsr",
.maxattr = IFLA_VLAN_MAX,
.maxattr = IFLA_HSR_MAX,
.parse_opt = hsr_parse_opt,
.print_opt = hsr_print_opt,
.print_help = hsr_print_help,

View File

@ -18,7 +18,8 @@ MAN8PAGES = $(TARGETS) ip.8 arpd.8 lnstat.8 routel.8 rtacct.8 rtmon.8 rtpr.8 ss.
tc-connmark.8 tc-csum.8 tc-mirred.8 tc-nat.8 tc-pedit.8 tc-police.8 \
tc-simple.8 tc-skbedit.8 tc-vlan.8 tc-xt.8 tc-ife.8 \
tc-tunnel_key.8 \
devlink.8 devlink-dev.8 devlink-monitor.8 devlink-port.8 devlink-sb.8
devlink.8 devlink-dev.8 devlink-monitor.8 devlink-port.8 devlink-sb.8 \
ifstat.8
all: $(TARGETS)

View File

@ -14,7 +14,8 @@ ifstat \- handy utility to read network interface statistics
The utility keeps records of the previous data displayed in history files and
by default only shows difference between the last and the current call.
Location of the history files defaults to /tmp/.ifstat.u$UID but may be
overridden with the IFSTAT_HISTORY environment variable.
overridden with the IFSTAT_HISTORY environment variable. Similarly, the default
location for xstat (extended stats) is /tmp/.<xstat name>_ifstat.u$UID.
.SH OPTIONS
.TP
.B \-h, \-\-help
@ -46,6 +47,15 @@ Report average over the last SECS seconds.
.TP
.B \-z, \-\-zeros
Show entries with zero activity.
.TP
.B \-x, \-\-extended=TYPE
Show extended stats of TYPE. Supported types are:
.in +8
.B cpu_hits
- Counts only packets that went via the CPU.
.in -8
.SH ENVIRONMENT
.TP
.B IFSTAT_HISTORY

View File

@ -704,13 +704,13 @@ is a set of encapsulation attributes specific to the
.sp
.in -8
.RE
.TP
.BI expires " TIME " "(4.4+ only)"
the route will be deleted after the expires time.
.B Only
support IPv6 at present.
.RE
.TP
ip route delete

View File

@ -28,12 +28,13 @@
#include <math.h>
#include <getopt.h>
#include <libnetlink.h>
#include <json_writer.h>
#include <linux/if.h>
#include <linux/if_link.h>
#include <SNAPSHOT.h>
#include "libnetlink.h"
#include "json_writer.h"
#include "SNAPSHOT.h"
#include "utils.h"
int dump_zeros;
int reset_history;
@ -48,17 +49,21 @@ int pretty;
double W;
char **patterns;
int npatterns;
bool is_extended;
int filter_type;
int sub_type;
char info_source[128];
int source_mismatch;
#define MAXS (sizeof(struct rtnl_link_stats)/sizeof(__u32))
#define NO_SUB_TYPE 0xffff
struct ifstat_ent {
struct ifstat_ent *next;
char *name;
int ifindex;
unsigned long long val[MAXS];
__u64 val[MAXS];
double rate[MAXS];
__u32 ival[MAXS];
};
@ -106,6 +111,48 @@ static int match(const char *id)
return 0;
}
static int get_nlmsg_extended(const struct sockaddr_nl *who,
struct nlmsghdr *m, void *arg)
{
struct if_stats_msg *ifsm = NLMSG_DATA(m);
struct rtattr *tb[IFLA_STATS_MAX+1];
int len = m->nlmsg_len;
struct ifstat_ent *n;
if (m->nlmsg_type != RTM_NEWSTATS)
return 0;
len -= NLMSG_LENGTH(sizeof(*ifsm));
if (len < 0)
return -1;
parse_rtattr(tb, IFLA_STATS_MAX, IFLA_STATS_RTA(ifsm), len);
if (tb[filter_type] == NULL)
return 0;
n = malloc(sizeof(*n));
if (!n)
abort();
n->ifindex = ifsm->ifindex;
n->name = strdup(ll_index_to_name(ifsm->ifindex));
if (sub_type == NO_SUB_TYPE) {
memcpy(&n->val, RTA_DATA(tb[filter_type]), sizeof(n->val));
} else {
struct rtattr *attr;
attr = parse_rtattr_one_nested(sub_type, tb[filter_type]);
if (attr == NULL)
return 0;
memcpy(&n->val, RTA_DATA(attr), sizeof(n->val));
}
memset(&n->rate, 0, sizeof(n->rate));
n->next = kern_db;
kern_db = n;
return 0;
}
static int get_nlmsg(const struct sockaddr_nl *who,
struct nlmsghdr *m, void *arg)
{
@ -147,18 +194,34 @@ static void load_info(void)
{
struct ifstat_ent *db, *n;
struct rtnl_handle rth;
__u32 filter_mask;
if (rtnl_open(&rth, 0) < 0)
exit(1);
if (rtnl_wilddump_request(&rth, AF_INET, RTM_GETLINK) < 0) {
perror("Cannot send dump request");
exit(1);
}
if (is_extended) {
ll_init_map(&rth);
filter_mask = IFLA_STATS_FILTER_BIT(filter_type);
if (rtnl_wilddump_stats_req_filter(&rth, AF_UNSPEC, RTM_GETSTATS,
filter_mask) < 0) {
perror("Cannot send dump request");
exit(1);
}
if (rtnl_dump_filter(&rth, get_nlmsg, NULL) < 0) {
fprintf(stderr, "Dump terminated\n");
exit(1);
if (rtnl_dump_filter(&rth, get_nlmsg_extended, NULL) < 0) {
fprintf(stderr, "Dump terminated\n");
exit(1);
}
} else {
if (rtnl_wilddump_request(&rth, AF_INET, RTM_GETLINK) < 0) {
perror("Cannot send dump request");
exit(1);
}
if (rtnl_dump_filter(&rth, get_nlmsg, NULL) < 0) {
fprintf(stderr, "Dump terminated\n");
exit(1);
}
}
rtnl_close(&rth);
@ -553,10 +616,17 @@ static void update_db(int interval)
}
for (i = 0; i < MAXS; i++) {
double sample;
unsigned long incr = h1->ival[i] - n->ival[i];
__u64 incr;
if (is_extended) {
incr = h1->val[i] - n->val[i];
n->val[i] = h1->val[i];
} else {
incr = (__u32) (h1->ival[i] - n->ival[i]);
n->val[i] += incr;
n->ival[i] = h1->ival[i];
}
n->val[i] += incr;
n->ival[i] = h1->ival[i];
sample = (double)(incr*1000)/interval;
if (interval >= scan_interval) {
n->rate[i] += W*(sample-n->rate[i]);
@ -656,6 +726,49 @@ static int verify_forging(int fd)
return -1;
}
static void xstat_usage(void)
{
fprintf(stderr,
"Usage: ifstat supported xstats:\n"
" cpu_hits Counts only packets that went via the CPU.\n");
}
struct extended_stats_options_t {
char *name;
int id;
int sub_type;
};
/* Note: if one xstat name is subset of another, it should be before it in this
* list.
* Name length must be under 64 chars.
*/
static const struct extended_stats_options_t extended_stats_options[] = {
{"cpu_hits", IFLA_STATS_LINK_OFFLOAD_XSTATS, IFLA_OFFLOAD_XSTATS_CPU_HIT},
};
static const char *get_filter_type(const char *name)
{
int name_len;
int i;
name_len = strlen(name);
for (i = 0; i < ARRAY_SIZE(extended_stats_options); i++) {
const struct extended_stats_options_t *xstat;
xstat = &extended_stats_options[i];
if (strncmp(name, xstat->name, name_len) == 0) {
filter_type = xstat->id;
sub_type = xstat->sub_type;
return xstat->name;
}
}
fprintf(stderr, "invalid ifstat extension %s\n", name);
xstat_usage();
return NULL;
}
static void usage(void) __attribute__((noreturn));
static void usage(void)
@ -673,7 +786,8 @@ static void usage(void)
" -s, --noupdate don't update history\n"
" -t, --interval=SECS report average over the last SECS\n"
" -V, --version output version information\n"
" -z, --zeros show entries with zero activity\n");
" -z, --zeros show entries with zero activity\n"
" -x, --extended=TYPE show extended stats of TYPE\n");
exit(-1);
}
@ -691,6 +805,7 @@ static const struct option longopts[] = {
{ "interval", 1, 0, 't' },
{ "version", 0, 0, 'V' },
{ "zeros", 0, 0, 'z' },
{ "extended", 1, 0, 'x'},
{ 0 }
};
@ -699,10 +814,12 @@ int main(int argc, char *argv[])
char hist_name[128];
struct sockaddr_un sun;
FILE *hist_fp = NULL;
const char *stats_type = NULL;
int ch;
int fd;
while ((ch = getopt_long(argc, argv, "hjpvVzrnasd:t:e",
is_extended = false;
while ((ch = getopt_long(argc, argv, "hjpvVzrnasd:t:ex:",
longopts, NULL)) != EOF) {
switch (ch) {
case 'z':
@ -743,6 +860,10 @@ int main(int argc, char *argv[])
exit(-1);
}
break;
case 'x':
stats_type = optarg;
is_extended = true;
break;
case 'v':
case 'V':
printf("ifstat utility, iproute2-ss%s\n", SNAPSHOT);
@ -757,6 +878,12 @@ int main(int argc, char *argv[])
argc -= optind;
argv += optind;
if (stats_type) {
stats_type = get_filter_type(stats_type);
if (!stats_type)
exit(-1);
}
sun.sun_family = AF_UNIX;
sun.sun_path[0] = 0;
sprintf(sun.sun_path+1, "ifstat%d", getuid());
@ -795,8 +922,13 @@ int main(int argc, char *argv[])
snprintf(hist_name, sizeof(hist_name),
"%s", getenv("IFSTAT_HISTORY"));
else
snprintf(hist_name, sizeof(hist_name),
"%s/.ifstat.u%d", P_tmpdir, getuid());
if (!stats_type)
snprintf(hist_name, sizeof(hist_name),
"%s/.ifstat.u%d", P_tmpdir, getuid());
else
snprintf(hist_name, sizeof(hist_name),
"%s/.%s_ifstat.u%d", P_tmpdir, stats_type,
getuid());
if (reset_history)
unlink(hist_name);

View File

@ -707,6 +707,8 @@ struct tcpstat {
int snd_wscale;
int rcv_wscale;
int mss;
int rcv_mss;
int advmss;
unsigned int cwnd;
unsigned int lastsnd;
unsigned int lastrcv;
@ -1872,6 +1874,10 @@ static void tcp_stats_print(struct tcpstat *s)
if (s->mss)
printf(" mss:%d", s->mss);
if (s->rcv_mss)
printf(" rcvmss:%d", s->rcv_mss);
if (s->advmss)
printf(" advmss:%d", s->advmss);
if (s->cwnd)
printf(" cwnd:%u", s->cwnd);
if (s->ssthresh)
@ -2189,6 +2195,8 @@ static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r,
s.rttvar = (double)info->tcpi_rttvar / 1000;
s.ato = (double)info->tcpi_ato / 1000;
s.mss = info->tcpi_snd_mss;
s.rcv_mss = info->tcpi_rcv_mss;
s.advmss = info->tcpi_advmss;
s.rcv_space = info->tcpi_rcv_space;
s.rcv_rtt = (double)info->tcpi_rcv_rtt / 1000;
s.lastsnd = info->tcpi_last_data_sent;