Commit dfc3d015 authored by Stephen Hemminger's avatar Stephen Hemminger

Merge branch 'master' into net-next

parents 9a6422c2 fcc16c22
/*
* Simple streaming JSON writer
*
* This takes care of the annoying bits of JSON syntax like the commas
* after elements
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Authors: Stephen Hemminger <stephen@networkplumber.org>
*/
#ifndef _JSON_WRITER_H_
#define _JSON_WRITER_H_
#include <stdbool.h>
#include <stdint.h>
/* Opaque class structure */
typedef struct json_writer json_writer_t;
/* Create a new JSON stream */
json_writer_t *jsonw_new(FILE *f);
/* End output to JSON stream */
void jsonw_destroy(json_writer_t **self_p);
/* Cause output to have pretty whitespace */
void jsonw_pretty(json_writer_t *self, bool on);
/* Add property name */
void jsonw_name(json_writer_t *self, const char *name);
/* Add value */
void jsonw_string(json_writer_t *self, const char *value);
void jsonw_bool(json_writer_t *self, bool value);
void jsonw_float(json_writer_t *self, double number);
void jsonw_uint(json_writer_t *self, uint64_t number);
void jsonw_int(json_writer_t *self, int64_t number);
void jsonw_null(json_writer_t *self);
/* Useful Combinations of name and value */
void jsonw_string_field(json_writer_t *self, const char *prop, const char *val);
void jsonw_bool_field(json_writer_t *self, const char *prop, bool value);
void jsonw_float_field(json_writer_t *self, const char *prop, double num);
void jsonw_uint_field(json_writer_t *self, const char *prop, uint64_t num);
void jsonw_int_field(json_writer_t *self, const char *prop, int64_t num);
void jsonw_null_field(json_writer_t *self, const char *prop);
/* Collections */
void jsonw_start_object(json_writer_t *self);
void jsonw_end_object(json_writer_t *self);
void jsonw_start_array(json_writer_t *self);
void jsonw_end_array(json_writer_t *self);
/* Override default exception handling */
typedef void (jsonw_err_handler_fn)(const char *);
#endif /* _JSON_WRITER_H_ */
......@@ -1197,40 +1197,41 @@ static void do_help(int argc, char **argv)
int do_iplink(int argc, char **argv)
{
if (argc > 0) {
if (iplink_have_newlink()) {
if (matches(*argv, "add") == 0)
return iplink_modify(RTM_NEWLINK,
NLM_F_CREATE|NLM_F_EXCL,
argc-1, argv+1);
if (matches(*argv, "set") == 0 ||
matches(*argv, "change") == 0)
return iplink_modify(RTM_NEWLINK, 0,
argc-1, argv+1);
if (matches(*argv, "replace") == 0)
return iplink_modify(RTM_NEWLINK,
NLM_F_CREATE|NLM_F_REPLACE,
argc-1, argv+1);
if (matches(*argv, "delete") == 0)
return iplink_modify(RTM_DELLINK, 0,
argc-1, argv+1);
} else {
if (argc < 1)
return ipaddr_list_link(0, NULL);
if (iplink_have_newlink()) {
if (matches(*argv, "add") == 0)
return iplink_modify(RTM_NEWLINK,
NLM_F_CREATE|NLM_F_EXCL,
argc-1, argv+1);
if (matches(*argv, "set") == 0 ||
matches(*argv, "change") == 0)
return iplink_modify(RTM_NEWLINK, 0,
argc-1, argv+1);
if (matches(*argv, "replace") == 0)
return iplink_modify(RTM_NEWLINK,
NLM_F_CREATE|NLM_F_REPLACE,
argc-1, argv+1);
if (matches(*argv, "delete") == 0)
return iplink_modify(RTM_DELLINK, 0,
argc-1, argv+1);
} else {
#if IPLINK_IOCTL_COMPAT
if (matches(*argv, "set") == 0)
return do_set(argc-1, argv+1);
if (matches(*argv, "set") == 0)
return do_set(argc-1, argv+1);
#endif
}
if (matches(*argv, "show") == 0 ||
matches(*argv, "lst") == 0 ||
matches(*argv, "list") == 0)
return ipaddr_list_link(argc-1, argv+1);
if (matches(*argv, "help") == 0) {
do_help(argc-1, argv+1);
return 0;
}
} else
return ipaddr_list_link(0, NULL);
}
if (matches(*argv, "show") == 0 ||
matches(*argv, "lst") == 0 ||
matches(*argv, "list") == 0)
return ipaddr_list_link(argc-1, argv+1);
if (matches(*argv, "help") == 0) {
do_help(argc-1, argv+1);
return 0;
}
fprintf(stderr, "Command \"%s\" is unknown, try \"ip link help\".\n", *argv);
fprintf(stderr, "Command \"%s\" is unknown, try \"ip link help\".\n",
*argv);
exit(-1);
}
......@@ -6,7 +6,8 @@ endif
CFLAGS += -fPIC
UTILOBJ=utils.o rt_names.o ll_types.o ll_proto.o ll_addr.o inet_proto.o namespace.o \
UTILOBJ = utils.o rt_names.o ll_types.o ll_proto.o ll_addr.o \
inet_proto.o namespace.o json_writer.o \
names.o color.o
NLOBJ=libgenl.o ll_map.o libnetlink.o
......
/*
* Simple streaming JSON writer
*
* This takes care of the annoying bits of JSON syntax like the commas
* after elements
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Authors: Stephen Hemminger <stephen@networkplumber.org>
*/
#include <stdio.h>
#include <stdbool.h>
#include <stdarg.h>
#include <assert.h>
#include <malloc.h>
#include <inttypes.h>
#include <stdint.h>
#include "json_writer.h"
struct json_writer {
FILE *out; /* output file */
unsigned depth; /* nesting */
bool pretty; /* optional whitepace */
char sep; /* either nul or comma */
};
/* indentation for pretty print */
static void jsonw_indent(json_writer_t *self)
{
unsigned i;
for (i = 0; i <= self->depth; ++i)
fputs(" ", self->out);
}
/* end current line and indent if pretty printing */
static void jsonw_eol(json_writer_t *self)
{
if (!self->pretty)
return;
putc('\n', self->out);
jsonw_indent(self);
}
/* If current object is not empty print a comma */
static void jsonw_eor(json_writer_t *self)
{
if (self->sep != '\0')
putc(self->sep, self->out);
self->sep = ',';
}
/* Output JSON encoded string */
/* Handles C escapes, does not do Unicode */
static void jsonw_puts(json_writer_t *self, const char *str)
{
putc('"', self->out);
for (; *str; ++str)
switch (*str) {
case '\t':
fputs("\\t", self->out);
break;
case '\n':
fputs("\\n", self->out);
break;
case '\r':
fputs("\\r", self->out);
break;
case '\f':
fputs("\\f", self->out);
break;
case '\b':
fputs("\\b", self->out);
break;
case '\\':
fputs("\\n", self->out);
break;
case '"':
fputs("\\\"", self->out);
break;
case '\'':
fputs("\\\'", self->out);
break;
default:
putc(*str, self->out);
}
putc('"', self->out);
}
/* Create a new JSON stream */
json_writer_t *jsonw_new(FILE *f)
{
json_writer_t *self = malloc(sizeof(*self));
if (self) {
self->out = f;
self->depth = 0;
self->pretty = false;
self->sep = '\0';
putc('{', self->out);
}
return self;
}
/* End output to JSON stream */
void jsonw_destroy(json_writer_t **self_p)
{
json_writer_t *self = *self_p;
assert(self->depth == 0);
jsonw_eol(self);
fputs("}\n", self->out);
fflush(self->out);
free(self);
*self_p = NULL;
}
void jsonw_pretty(json_writer_t *self, bool on)
{
self->pretty = on;
}
/* Basic blocks */
static void jsonw_begin(json_writer_t *self, int c)
{
jsonw_eor(self);
putc(c, self->out);
++self->depth;
self->sep = '\0';
}
static void jsonw_end(json_writer_t *self, int c)
{
assert(self->depth > 0);
--self->depth;
if (self->sep != '\0')
jsonw_eol(self);
putc(c, self->out);
self->sep = ',';
}
/* Add a JSON property name */
void jsonw_name(json_writer_t *self, const char *name)
{
jsonw_eor(self);
jsonw_eol(self);
self->sep = '\0';
jsonw_puts(self, name);
putc(':', self->out);
if (self->pretty)
putc(' ', self->out);
}
static void jsonw_printf(json_writer_t *self, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
jsonw_eor(self);
vfprintf(self->out, fmt, ap);
va_end(ap);
}
/* Collections */
void jsonw_start_object(json_writer_t *self)
{
jsonw_begin(self, '{');
}
void jsonw_end_object(json_writer_t *self)
{
jsonw_end(self, '}');
}
void jsonw_start_array(json_writer_t *self)
{
jsonw_begin(self, '[');
}
void jsonw_end_array(json_writer_t *self)
{
jsonw_end(self, ']');
}
/* JSON value types */
void jsonw_string(json_writer_t *self, const char *value)
{
jsonw_eor(self);
jsonw_puts(self, value);
}
void jsonw_bool(json_writer_t *self, bool val)
{
jsonw_printf(self, "%s", val ? "true" : "false");
}
#ifdef notused
void jsonw_null(json_writer_t *self)
{
jsonw_printf(self, "null");
}
void jsonw_float(json_writer_t *self, double num)
{
jsonw_printf(self, "%g", num);
}
#endif
void jsonw_uint(json_writer_t *self, uint64_t num)
{
jsonw_printf(self, "%"PRIu64, num);
}
void jsonw_int(json_writer_t *self, int64_t num)
{
jsonw_printf(self, "%"PRId64, num);
}
/* Basic name/value objects */
void jsonw_string_field(json_writer_t *self, const char *prop, const char *val)
{
jsonw_name(self, prop);
jsonw_string(self, val);
}
void jsonw_bool_field(json_writer_t *self, const char *prop, bool val)
{
jsonw_name(self, prop);
jsonw_bool(self, val);
}
#ifdef notused
void jsonw_float_field(json_writer_t *self, const char *prop, double val)
{
jsonw_name(self, prop);
jsonw_float(self, val);
}
#endif
void jsonw_uint_field(json_writer_t *self, const char *prop, uint64_t num)
{
jsonw_name(self, prop);
jsonw_uint(self, num);
}
void jsonw_int_field(json_writer_t *self, const char *prop, int64_t num)
{
jsonw_name(self, prop);
jsonw_int(self, num);
}
#ifdef notused
void jsonw_null_field(json_writer_t *self, const char *prop)
{
jsonw_name(self, prop);
jsonw_null(self);
}
#endif
#ifdef TEST
int main(int argc, char **argv)
{
json_writer_t *wr = jsonw_new(stdout);
jsonw_pretty(wr, true);
jsonw_name(wr, "Vyatta");
jsonw_start_object(wr);
jsonw_string_field(wr, "url", "http://vyatta.com");
jsonw_uint_field(wr, "downloads", 2000000ul);
jsonw_float_field(wr, "stock", 8.16);
jsonw_name(wr, "ARGV");
jsonw_start_array(wr);
while (--argc)
jsonw_string(wr, *++argv);
jsonw_end_array(wr);
jsonw_name(wr, "empty");
jsonw_start_array(wr);
jsonw_end_array(wr);
jsonw_name(wr, "NIL");
jsonw_start_object(wr);
jsonw_end_object(wr);
jsonw_null_field(wr, "my_null");
jsonw_name(wr, "special chars");
jsonw_start_array(wr);
jsonw_string_field(wr, "slash", "/");
jsonw_string_field(wr, "newline", "\n");
jsonw_string_field(wr, "tab", "\t");
jsonw_string_field(wr, "ff", "\f");
jsonw_string_field(wr, "quote", "\"");
jsonw_string_field(wr, "tick", "\'");
jsonw_string_field(wr, "backslash", "\\");
jsonw_end_array(wr);
jsonw_end_object(wr);
jsonw_destroy(&wr);
return 0;
}
#endif
......@@ -58,35 +58,34 @@ int netns_switch(char *name)
if (setns(netns, CLONE_NEWNET) < 0) {
fprintf(stderr, "setting the network namespace \"%s\" failed: %s\n",
name, strerror(errno));
goto fail_close;
close(netns);
return -1;
}
close(netns);
if (unshare(CLONE_NEWNS) < 0) {
fprintf(stderr, "unshare failed: %s\n", strerror(errno));
goto fail_close;
return -1;
}
/* Don't let any mounts propagate back to the parent */
if (mount("", "/", "none", MS_SLAVE | MS_REC, NULL)) {
fprintf(stderr, "\"mount --make-rslave /\" failed: %s\n",
strerror(errno));
goto fail_close;
return -1;
}
/* Mount a version of /sys that describes the network namespace */
if (umount2("/sys", MNT_DETACH) < 0) {
fprintf(stderr, "umount of /sys failed: %s\n", strerror(errno));
goto fail_close;
return -1;
}
if (mount(name, "/sys", "sysfs", 0, NULL) < 0) {
fprintf(stderr, "mount of /sys failed: %s\n",strerror(errno));
goto fail_close;
return -1;
}
/* Setup bind mounts for config files in /etc */
bind_etc(name);
return 0;
fail_close:
close(netns);
return -1;
}
int netns_get_fd(const char *name)
......
......@@ -60,7 +60,7 @@ ip-address \- protocol address management
.IR FLAG " := "
.RB "[ " permanent " | " dynamic " | " secondary " | " primary " | \
[ - ] " tentative " | [ - ] " deprecated " | [ - ] " dadfailed " | "\
temporary " ] " CONFFLAG-LIST " ]"
temporary " ] [ " CONFFLAG-LIST " ]"
.ti -8
.IR CONFFLAG-LIST " := [ " CONFFLAG-LIST " ] " CONFFLAG
......
......@@ -315,7 +315,31 @@ the following additional arguments are supported:
- specifies the VLAN Identifer to use. Note that numbers with a leading " 0 " or " 0x " are interpreted as octal or hexadeimal, respectively.
.BR reorder_hdr " { " on " | " off " } "
- specifies whether ethernet headers are reordered or not.
- specifies whether ethernet headers are reordered or not (default is
.BR on ")."
.in +4
If
.BR reorder_hdr " is " on
then VLAN header will be not inserted immediately but only before passing to the
physical device (if this device does not support VLAN offloading), the similar
on the RX direction - by default the packet will be untagged before being
received by VLAN device. Reordering allows to accelerate tagging on egress and
to hide VLAN header on ingress so the packet looks like regular Ethernet packet,
at the same time it might be confusing while the packet sniffing as the VLAN header
does not exist within the packet.
VLAN offloading can be checked by
.BR ethtool "(8):"
.in +4
.sp
.B ethtool -k
<phy_dev> |
.RB grep " tx-vlan-offload"
.sp
.in -4
where <phy_dev> is the physical device to which VLAN device is bound.
.in -4
.BR gvrp " { " on " | " off " } "
- specifies whether this VLAN should be registered using GARP VLAN Registration Protocol.
......@@ -1073,7 +1097,8 @@ IEEE 802.15.4 device wpan0.
.SH SEE ALSO
.br
.BR ip (8),
.BR ip-netns (8)
.BR ip-netns (8),
.BR ethtool (8)
.SH AUTHOR
Original Manpage by Michail Litvak <mci@owl.openwall.com>
......@@ -19,7 +19,7 @@ all: $(TARGETS)
ss: $(SSOBJ)
nstat: nstat.c
$(CC) $(CFLAGS) $(LDFLAGS) -o nstat nstat.c -lm
$(CC) $(CFLAGS) $(LDFLAGS) -o nstat nstat.c $(LIBNETLINK) -lm
ifstat: ifstat.c
$(CC) $(CFLAGS) $(LDFLAGS) -o ifstat ifstat.c $(LIBNETLINK) -lm
......
......@@ -29,6 +29,7 @@
#include <getopt.h>
#include <libnetlink.h>
#include <json_writer.h>
#include <linux/if.h>
#include <linux/if_link.h>
......@@ -43,6 +44,7 @@ int no_update = 0;
int scan_interval = 0;
int time_constant = 0;
int show_errors = 0;
int pretty;
double W;
char **patterns;
int npatterns;
......@@ -238,13 +240,15 @@ static void load_raw_table(FILE *fp)
static void dump_raw_db(FILE *fp, int to_hist)
{
json_writer_t *jw = json_output ? jsonw_new(fp) : NULL;
struct ifstat_ent *n, *h;
const char *eol = "\n";
h = hist_db;
if (json_output)
fprintf(fp, "{ \"%s\":{", info_source);
else
if (jw) {
jsonw_pretty(jw, pretty);
jsonw_name(jw, info_source);
jsonw_start_object(jw);
} else
fprintf(fp, "#%s\n", info_source);
for (n=kern_db; n; n=n->next) {
......@@ -265,14 +269,13 @@ static void dump_raw_db(FILE *fp, int to_hist)
}
}
if (json_output) {
fprintf(fp, "%s \"%s\":{",
eol, n->name);
eol = ",\n";
if (jw) {
jsonw_name(jw, n->name);
jsonw_start_object(jw);
for (i=0; i<MAXS && stats[i]; i++)
fprintf(fp, " \"%s\":%llu",
stats[i], vals[i]);
fprintf(fp, "}");
jsonw_uint_field(jw, stats[i], vals[i]);
jsonw_end_object(jw);
} else {
fprintf(fp, "%d %s ", n->ifindex, n->name);
for (i=0; i<MAXS; i++)
......@@ -281,6 +284,10 @@ static void dump_raw_db(FILE *fp, int to_hist)
fprintf(fp, "\n");
}
}
if (jw) {
jsonw_end_object(jw);
jsonw_destroy(&jw);
}
}
/* use communication definitions of meg/kilo etc */
......@@ -373,20 +380,18 @@ static void print_head(FILE *fp)
}
}
static void print_one_json(FILE *fp, const struct ifstat_ent *n,
static void print_one_json(json_writer_t *jw, const struct ifstat_ent *n,
const unsigned long long *vals)
{
int i, m;
const char *sep = " ";
m = show_errors ? 20 : 10;
fprintf(fp, " \"%s\":{", n->name);
for (i=0; i < m && stats[i]; i++) {
fprintf(fp, "%s\"%s\":%llu",
sep, stats[i], vals[i]);
sep = ", ";
}
fprintf(fp, " }");
int i, m = show_errors ? 20 : 10;
jsonw_name(jw, n->name);
jsonw_start_object(jw);
for (i=0; i < m && stats[i]; i++)
jsonw_uint_field(jw, stats[i], vals[i]);
jsonw_end_object(jw);
}
static void print_one_if(FILE *fp, const struct ifstat_ent *n,
......@@ -439,39 +444,40 @@ static void print_one_if(FILE *fp, const struct ifstat_ent *n,
static void dump_kern_db(FILE *fp)
{
json_writer_t *jw = json_output ? jsonw_new(fp) : NULL;
struct ifstat_ent *n;
const char *eol = "\n";
if (json_output)
fprintf(fp, "{ \"%s\": {", info_source);
else
if (jw) {
jsonw_pretty(jw, pretty);
jsonw_name(jw, info_source);
jsonw_start_object(jw);
} else
print_head(fp);
for (n=kern_db; n; n=n->next) {
if (!match(n->name))
continue;
if (json_output) {
fprintf(fp, "%s", eol);
eol = ",\n";
print_one_json(fp, n, n->val);
} else
if (jw)
print_one_json(jw, n, n->val);
else
print_one_if(fp, n, n->val);
}
if (json_output)
fprintf(fp, "\n} }\n");
}
static void dump_incr_db(FILE *fp)
{
struct ifstat_ent *n, *h;
const char *eol = "\n";
json_writer_t *jw = json_output ? jsonw_new(fp) : NULL;
h = hist_db;
if (json_output)
fprintf(fp, "{ \"%s\":{", info_source);
else
if (jw) {
jsonw_pretty(jw, pretty);
jsonw_name(jw, info_source);
jsonw_start_object(jw);
} else
print_head(fp);
for (n=kern_db; n; n=n->next) {
......@@ -492,17 +498,17 @@ static void dump_incr_db(FILE *fp)
if (!match(n->name))
continue;
if (json_output) {
fprintf(fp, "%s", eol);
eol = ",\n";
print_one_json(fp, n, n->val);
} else
if (jw)
print_one_json(jw, n, n->val);
else
print_one_if(fp, n, vals);
}
if (json_output)
fprintf(fp, "\n} }\n");
}
if (jw) {
jsonw_end_object(jw);
jsonw_destroy(&jw);
}
}
static int children;
......@@ -646,6 +652,7 @@ static void usage(void)
" -e, --errors show errors\n"
" -j, --json format output in JSON\n"
" -n, --nooutput do history only\n"
" -p, --pretty pretty print\n"
" -r, --reset reset history\n"
" -s, --noupdate don\'t update history\n"
" -t, --interval=SECS report average over the last SECS\n"
......@@ -663,6 +670,7 @@ static const struct option longopts[] = {
{ "nooutput", 0, 0, 'n' },
{ "json", 0, 0, 'j' },
{ "reset", 0, 0, 'r' },
{ "pretty", 0, 0, 'p' },
{ "noupdate", 0, 0, 's' },
{ "interval", 1, 0, 't' },
{ "version", 0, 0, 'V' },
......@@ -678,7 +686,7 @@ int main(int argc, char *argv[])
int ch;
int fd;
while ((ch = getopt_long(argc, argv, "hjvVzrnasd:t:e",
while ((ch = getopt_long(argc, argv, "hjpvVzrnasd:t:e",
longopts, NULL)) != EOF) {
switch(ch) {
case 'z':
......@@ -702,6 +710,9 @@ int main(int argc, char *argv[])
case 'j':
json_output = 1;
break;
case 'p':
pretty = 1;
break;
case 'd':
scan_interval = atoi(optarg) * 1000;
if (scan_interval <= 0) {
......
......@@ -36,6 +36,7 @@
#include <string.h>
#include <getopt.h>
#include <json_writer.h>
#include "lnstat.h"
static struct option opts[] = {
......@@ -49,6 +50,7 @@ static struct option opts[] = {
{ "keys", 1, NULL, 'k' },
{ "subject", 1, NULL, 's' },
{ "width", 1, NULL, 'w' },
{ "oneline", 0, NULL, 0 },
};
static int usage(char *name, int exit_code)
......@@ -107,25 +109,17 @@ static void print_line(FILE *of, const struct lnstat_file *lnstat_files,
static void print_json(FILE *of, const struct lnstat_file *lnstat_files,
const struct field_params *fp)
{
json_writer_t *jw = jsonw_new(of);
int i;
const char *sep;
const char *base = NULL;
fputs("{\n", of);
jsonw_start_object(jw);
for (i = 0; i < fp->num; i++) {
const struct lnstat_field *lf = fp->params[i].lf;
if (!base || lf->file->basename != base) {
if (base) fputs("},\n", of);
base = lf->file->basename;
sep = "\n\t";
fprintf(of, " \"%s\":{", base);
}
fprintf(of, "%s\"%s\":%lu", sep,
lf->name, lf->result);
sep = ",\n\t";
jsonw_uint_field(jw, lf->name, lf->result);
}
fputs("}\n}\n", of);
jsonw_end_object(jw);
jsonw_destroy(&jw);
}
/* find lnstat_field according to user specification */
......@@ -272,7 +266,7 @@ int main(int argc, char **argv)
num_req_files = 1;
}
while ((c = getopt_long(argc, argv,"Vc:djf:h?i:k:s:w:",
while ((c = getopt_long(argc, argv,"Vc:djpf:h?i:k:s:w:",
opts, NULL)) != -1) {
int len = 0;
char *tmp, *tok;
......
......@@ -28,6 +28,7 @@
#include <math.h>
#include <getopt.h>
#include <json_writer.h>
#include <SNAPSHOT.h>
int dump_zeros = 0;
......@@ -35,6 +36,7 @@ int reset_history = 0;
int ignore_history = 0;
int no_output = 0;
int json_output = 0;
int pretty = 0;
int no_update = 0;
int scan_interval = 0;
int time_constant = 0;
......@@ -271,13 +273,15 @@ static void load_netstat(void)
static void dump_kern_db(FILE *fp, int to_hist)
{
json_writer_t *jw = json_output ? jsonw_new(fp) : NULL;
struct nstat_ent *n, *h;
const char *eol = "\n";
h = hist_db;
if (json_output)
fprintf(fp, "{ \"%s\":{", info_source);
else
if (jw) {
jsonw_pretty(jw, pretty);
jsonw_name(jw, info_source);
jsonw_start_object(jw);
} else
fprintf(fp, "#%s\n", info_source);
for (n=kern_db; n; n=n->next) {
......@@ -297,26 +301,29 @@ static void dump_kern_db(FILE *fp, int to_hist)
}
}
if (json_output) {
fprintf(fp, "%s \"%s\":%llu",
eol, n->id, val);
eol = ",\n";
} else
if (jw)
jsonw_uint_field(jw, n->id, val);
else
fprintf(fp, "%-32s%-16llu%6.1f\n", n->id, val, n->rate);
}
if (json_output)
fprintf(fp, "\n} }\n");
if (jw) {
jsonw_end_object(jw);
jsonw_destroy(&jw);
}
}
static void dump_incr_db(FILE *fp)
{
json_writer_t *jw = json_output ? jsonw_new(fp) : NULL;
struct nstat_ent *n, *h;
const char *eol = "\n";
h = hist_db;
if (json_output)
fprintf(fp, "{ \"%s\":{", info_source);
else
if (jw) {
jsonw_pretty(jw, pretty);
jsonw_name(jw, info_source);
jsonw_start_object(jw);
} else
fprintf(fp, "#%s\n", info_source);
for (n=kern_db; n; n=n->next) {
......@@ -339,16 +346,17 @@ static void dump_incr_db(FILE *fp)
if (!match(n->id))
continue;
if (json_output) {
fprintf(fp, "%s \"%s\":%llu",
eol, n->id, val);
eol = ",\n";
} else
if (jw)
jsonw_uint_field(jw, n->id, val);
else
fprintf(fp, "%-32s%-16llu%6.1f%s\n", n->id, val,
n->rate, ovfl?" (overflow)":"");
}
if (json_output)
fprintf(fp, "\n} }\n");
if (jw) {
jsonw_end_object(jw);
jsonw_destroy(&jw);
}
}
static int children;
......@@ -485,6 +493,7 @@ static void usage(void)
" -d, --scan=SECS sample every statistics every SECS\n"
" -j, --json format output in JSON\n"
" -n, --nooutput do history only\n"
" -p, --pretty pretty print\n"
" -r, --reset reset history\n"
" -s, --noupdate don\'t update history\n"
" -t, --interval=SECS report average over the last SECS\n"
......@@ -501,6 +510,7 @@ static const struct option longopts[] = {
{ "json", 0, 0, 'j' },
{ "reset", 0, 0, 'r' },
{ "noupdate", 0, 0, 's' },
{ "pretty", 0, 0, 'p' },
{ "interval", 1, 0, 't' },
{ "version", 0, 0, 'V' },
{ "zeros", 0, 0, 'z' },
......@@ -515,7 +525,7 @@ int main(int argc, char *argv[])
int ch;
int fd;
while ((ch = getopt_long(argc, argv, "h?vVzrnasd:t:j",
while ((ch = getopt_long(argc, argv, "h?vVzrnasd:t:jp",
longopts, NULL)) != EOF) {
switch(ch) {
case 'z':
......@@ -546,6 +556,9 @@ int main(int argc, char *argv[])
case 'j':
json_output = 1;
break;
case 'p':
pretty = 1;
break;
case 'v':
case 'V':
printf("nstat utility, iproute2-ss%s\n", SNAPSHOT);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment