Skip to content

Commit

Permalink
Merge branch 'rate-size-parsing-output' into next
Browse files Browse the repository at this point in the history
Petr Machata says:
==================

The DCB tool will have commands that deal with buffer sizes and traffic
rates. TC is another tool that has a number of such commands, and functions
to support them: get_size(), get_rate/64(), s/print_size() and
s/print_rate(). In this patchset, these functions are moved from TC to lib/
for possible reuse and modernized.

s/print_rate() has a hidden parameter of a global variable use_iec, which
made the conversion non-trivial. The parameter was made explicit,
print_rate() converted to a mostly json_print-like function, and
sprint_rate() retired in favor of the new print_rate. Patches #1 and #2
deal with this.

The intention was to treat s/print_size() similarly, but unfortunately two
use cases of sprint_size() cannot be converted to a json_print-like
print_size(), and the function sprint_size() had to remain as a discouraged
backdoor to print_size(). This is done in patch #3.

Patch #4 then improves the code of sprint_size() a little bit.

Patch #5 fixes a buglet in formatting small rates in IEC mode.

Patches #6 and #7 handle a routine movement of, respectively,
get_rate/64() and get_size() from tc to lib.

This patchset does not actually add any new uses of these functions. A
follow-up patchset will add subtools for management of DCB buffer and DCB
maxrate objects that will make use of them.

====================

Signed-off-by: David Ahern <dsahern@gmail.com>
  • Loading branch information
dsahern committed Dec 9, 2020
2 parents 69629b4 + 44396bd commit 120cdeb
Show file tree
Hide file tree
Showing 26 changed files with 307 additions and 370 deletions.
14 changes: 14 additions & 0 deletions include/json_print.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ _PRINT_FUNC(on_off, bool)
_PRINT_FUNC(null, const char*)
_PRINT_FUNC(string, const char*)
_PRINT_FUNC(uint, unsigned int)
_PRINT_FUNC(size, __u32)
_PRINT_FUNC(u64, uint64_t)
_PRINT_FUNC(hhu, unsigned char)
_PRINT_FUNC(hu, unsigned short)
Expand All @@ -86,4 +87,17 @@ _PRINT_NAME_VALUE_FUNC(uint, unsigned int, u);
_PRINT_NAME_VALUE_FUNC(string, const char*, s);
#undef _PRINT_NAME_VALUE_FUNC

int print_color_rate(bool use_iec, enum output_type t, enum color_attr color,
const char *key, const char *fmt, unsigned long long rate);

static inline int print_rate(bool use_iec, enum output_type t,
const char *key, const char *fmt,
unsigned long long rate)
{
return print_color_rate(use_iec, t, COLOR_NONE, key, fmt, rate);
}

/* A backdoor to the size formatter. Please use print_size() instead. */
char *sprint_size(__u32 sz, char *buf);

#endif /* _JSON_PRINT_H_ */
4 changes: 3 additions & 1 deletion include/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@

extern int preferred_family;
extern int human_readable;
extern int use_iec;
extern int show_stats;
extern int show_details;
extern int show_raw;
Expand Down Expand Up @@ -163,6 +162,9 @@ int get_be64(__be64 *val, const char *arg, int base);
int get_be32(__be32 *val, const char *arg, int base);
int get_be16(__be16 *val, const char *arg, int base);
int get_addr64(__u64 *ap, const char *cp);
int get_rate(unsigned int *rate, const char *str);
int get_rate64(__u64 *rate, const char *str);
int get_size(unsigned int *size, const char *str);

int hex2mem(const char *buf, uint8_t *mem, int count);
char *hexstring_n2a(const __u8 *str, int len, char *buf, int blen);
Expand Down
2 changes: 2 additions & 0 deletions ip/ip_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

#include "json_print.h"

extern int use_iec;

struct link_filter {
int ifindex;
int family;
Expand Down
63 changes: 63 additions & 0 deletions lib/json_print.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include <stdarg.h>
#include <stdio.h>
#include <math.h>

#include "utils.h"
#include "json_print.h"
Expand Down Expand Up @@ -308,3 +309,65 @@ void print_nl(void)
if (!_jw)
printf("%s", _SL_);
}

int print_color_rate(bool use_iec, enum output_type type, enum color_attr color,
const char *key, const char *fmt, unsigned long long rate)
{
unsigned long kilo = use_iec ? 1024 : 1000;
const char *str = use_iec ? "i" : "";
static char *units[5] = {"", "K", "M", "G", "T"};
char *buf;
int rc;
int i;

if (_IS_JSON_CONTEXT(type))
return print_color_lluint(type, color, key, "%llu", rate);

rate <<= 3; /* bytes/sec -> bits/sec */

for (i = 0; i < ARRAY_SIZE(units) - 1; i++) {
if (rate < kilo)
break;
if (((rate % kilo) != 0) && rate < 1000*kilo)
break;
rate /= kilo;
}

rc = asprintf(&buf, "%.0f%s%sbit", (double)rate, units[i],
i > 0 ? str : "");
if (rc < 0)
return -1;

rc = print_color_string(type, color, key, fmt, buf);
free(buf);
return rc;
}

char *sprint_size(__u32 sz, char *buf)
{
long kilo = 1024;
long mega = kilo * kilo;
size_t len = SPRINT_BSIZE - 1;
double tmp = sz;

if (sz >= mega && fabs(mega * rint(tmp / mega) - sz) < 1024)
snprintf(buf, len, "%gMb", rint(tmp / mega));
else if (sz >= kilo && fabs(kilo * rint(tmp / kilo) - sz) < 16)
snprintf(buf, len, "%gKb", rint(tmp / kilo));
else
snprintf(buf, len, "%ub", sz);

return buf;
}

int print_color_size(enum output_type type, enum color_attr color,
const char *key, const char *fmt, __u32 sz)
{
SPRINT_BUF(buf);

if (_IS_JSON_CONTEXT(type))
return print_color_uint(type, color, key, "%u", sz);

sprint_size(sz, buf);
return print_color_string(type, color, key, fmt, buf);
}
114 changes: 114 additions & 0 deletions lib/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,120 @@ int get_addr64(__u64 *ap, const char *cp)
return 1;
}

/* See http://physics.nist.gov/cuu/Units/binary.html */
static const struct rate_suffix {
const char *name;
double scale;
} suffixes[] = {
{ "bit", 1. },
{ "Kibit", 1024. },
{ "kbit", 1000. },
{ "mibit", 1024.*1024. },
{ "mbit", 1000000. },
{ "gibit", 1024.*1024.*1024. },
{ "gbit", 1000000000. },
{ "tibit", 1024.*1024.*1024.*1024. },
{ "tbit", 1000000000000. },
{ "Bps", 8. },
{ "KiBps", 8.*1024. },
{ "KBps", 8000. },
{ "MiBps", 8.*1024*1024. },
{ "MBps", 8000000. },
{ "GiBps", 8.*1024.*1024.*1024. },
{ "GBps", 8000000000. },
{ "TiBps", 8.*1024.*1024.*1024.*1024. },
{ "TBps", 8000000000000. },
{ NULL }
};

int get_rate(unsigned int *rate, const char *str)
{
char *p;
double bps = strtod(str, &p);
const struct rate_suffix *s;

if (p == str)
return -1;

for (s = suffixes; s->name; ++s) {
if (strcasecmp(s->name, p) == 0) {
bps *= s->scale;
p += strlen(p);
break;
}
}

if (*p)
return -1; /* unknown suffix */

bps /= 8; /* -> bytes per second */
*rate = bps;
/* detect if an overflow happened */
if (*rate != floor(bps))
return -1;
return 0;
}

int get_rate64(__u64 *rate, const char *str)
{
char *p;
double bps = strtod(str, &p);
const struct rate_suffix *s;

if (p == str)
return -1;

for (s = suffixes; s->name; ++s) {
if (strcasecmp(s->name, p) == 0) {
bps *= s->scale;
p += strlen(p);
break;
}
}

if (*p)
return -1; /* unknown suffix */

bps /= 8; /* -> bytes per second */
*rate = bps;
return 0;
}

int get_size(unsigned int *size, const char *str)
{
double sz;
char *p;

sz = strtod(str, &p);
if (p == str)
return -1;

if (*p) {
if (strcasecmp(p, "kb") == 0 || strcasecmp(p, "k") == 0)
sz *= 1024;
else if (strcasecmp(p, "gb") == 0 || strcasecmp(p, "g") == 0)
sz *= 1024*1024*1024;
else if (strcasecmp(p, "gbit") == 0)
sz *= 1024*1024*1024/8;
else if (strcasecmp(p, "mb") == 0 || strcasecmp(p, "m") == 0)
sz *= 1024*1024;
else if (strcasecmp(p, "mbit") == 0)
sz *= 1024*1024/8;
else if (strcasecmp(p, "kbit") == 0)
sz *= 1024/8;
else if (strcasecmp(p, "b") != 0)
return -1;
}

*size = sz;

/* detect if an overflow happened */
if (*size != floor(sz))
return -1;

return 0;
}

static void set_address_type(inet_prefix *addr)
{
switch (addr->family) {
Expand Down
6 changes: 2 additions & 4 deletions tc/m_gate.c
Original file line number Diff line number Diff line change
Expand Up @@ -465,10 +465,8 @@ static int print_gate_list(struct rtattr *list)
}

if (maxoctets != -1) {
memset(buf, 0, sizeof(buf));
print_uint(PRINT_JSON, "max_octets", NULL, maxoctets);
print_string(PRINT_FP, NULL, "\t max-octets %s",
sprint_size(maxoctets, buf));
print_size(PRINT_ANY, "max_octets", "\t max-octets %s",
maxoctets);
} else {
print_string(PRINT_FP, NULL,
"\t max-octets %s", "wildcard");
Expand Down
14 changes: 6 additions & 8 deletions tc/m_police.c
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,6 @@ int parse_police(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n)

static int print_police(struct action_util *a, FILE *f, struct rtattr *arg)
{
SPRINT_BUF(b1);
SPRINT_BUF(b2);
struct tc_police *p;
struct rtattr *tb[TCA_POLICE_MAX+1];
Expand Down Expand Up @@ -269,10 +268,10 @@ static int print_police(struct action_util *a, FILE *f, struct rtattr *arg)
rate64 = rta_getattr_u64(tb[TCA_POLICE_RATE64]);

fprintf(f, " police 0x%x ", p->index);
fprintf(f, "rate %s ", sprint_rate(rate64, b1));
tc_print_rate(PRINT_FP, NULL, "rate %s ", rate64);
buffer = tc_calc_xmitsize(rate64, p->burst);
fprintf(f, "burst %s ", sprint_size(buffer, b1));
fprintf(f, "mtu %s ", sprint_size(p->mtu, b1));
print_size(PRINT_FP, NULL, "burst %s ", buffer);
print_size(PRINT_FP, NULL, "mtu %s ", p->mtu);
if (show_raw)
fprintf(f, "[%08x] ", p->burst);

Expand All @@ -282,12 +281,11 @@ static int print_police(struct action_util *a, FILE *f, struct rtattr *arg)
prate64 = rta_getattr_u64(tb[TCA_POLICE_PEAKRATE64]);

if (prate64)
fprintf(f, "peakrate %s ", sprint_rate(prate64, b1));
tc_print_rate(PRINT_FP, NULL, "peakrate %s ", prate64);

if (tb[TCA_POLICE_AVRATE])
fprintf(f, "avrate %s ",
sprint_rate(rta_getattr_u32(tb[TCA_POLICE_AVRATE]),
b1));
tc_print_rate(PRINT_FP, NULL, "avrate %s ",
rta_getattr_u32(tb[TCA_POLICE_AVRATE]));

print_action_control(f, "action ", p->action, "");

Expand Down
44 changes: 22 additions & 22 deletions tc/q_cake.c
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,6 @@ static int cake_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
int atm = 0;
int nat = 0;

SPRINT_BUF(b1);
SPRINT_BUF(b2);

if (opt == NULL)
Expand All @@ -445,11 +444,10 @@ static int cake_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
if (tb[TCA_CAKE_BASE_RATE64] &&
RTA_PAYLOAD(tb[TCA_CAKE_BASE_RATE64]) >= sizeof(bandwidth)) {
bandwidth = rta_getattr_u64(tb[TCA_CAKE_BASE_RATE64]);
if (bandwidth) {
print_uint(PRINT_JSON, "bandwidth", NULL, bandwidth);
print_string(PRINT_FP, NULL, "bandwidth %s ",
sprint_rate(bandwidth, b1));
} else
if (bandwidth)
tc_print_rate(PRINT_ANY, "bandwidth", "bandwidth %s ",
bandwidth);
else
print_string(PRINT_ANY, "bandwidth", "bandwidth %s ",
"unlimited");
}
Expand Down Expand Up @@ -574,11 +572,8 @@ static int cake_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
if (mpu)
print_uint(PRINT_ANY, "mpu", "mpu %u ", mpu);

if (memlimit) {
print_uint(PRINT_JSON, "memlimit", NULL, memlimit);
print_string(PRINT_FP, NULL, "memlimit %s ",
sprint_size(memlimit, b1));
}
if (memlimit)
print_size(PRINT_ANY, "memlimit", "memlimit %s ", memlimit);

if (fwmark)
print_uint(PRINT_FP, NULL, "fwmark 0x%x ", fwmark);
Expand Down Expand Up @@ -638,24 +633,22 @@ static int cake_print_xstats(struct qdisc_util *qu, FILE *f,

if (st[TCA_CAKE_STATS_MEMORY_USED] &&
st[TCA_CAKE_STATS_MEMORY_LIMIT]) {
print_string(PRINT_FP, NULL, " memory used: %s",
sprint_size(GET_STAT_U32(MEMORY_USED), b1));
print_size(PRINT_FP, NULL, " memory used: %s",
GET_STAT_U32(MEMORY_USED));

print_string(PRINT_FP, NULL, " of %s\n",
sprint_size(GET_STAT_U32(MEMORY_LIMIT), b1));
print_size(PRINT_FP, NULL, " of %s\n",
GET_STAT_U32(MEMORY_LIMIT));

print_uint(PRINT_JSON, "memory_used", NULL,
GET_STAT_U32(MEMORY_USED));
print_uint(PRINT_JSON, "memory_limit", NULL,
GET_STAT_U32(MEMORY_LIMIT));
}

if (st[TCA_CAKE_STATS_CAPACITY_ESTIMATE64]) {
print_string(PRINT_FP, NULL, " capacity estimate: %s\n",
sprint_rate(GET_STAT_U64(CAPACITY_ESTIMATE64), b1));
print_uint(PRINT_JSON, "capacity_estimate", NULL,
GET_STAT_U64(CAPACITY_ESTIMATE64));
}
if (st[TCA_CAKE_STATS_CAPACITY_ESTIMATE64])
tc_print_rate(PRINT_ANY, "capacity_estimate",
" capacity estimate: %s\n",
GET_STAT_U64(CAPACITY_ESTIMATE64));

if (st[TCA_CAKE_STATS_MIN_NETLEN] &&
st[TCA_CAKE_STATS_MAX_NETLEN]) {
Expand Down Expand Up @@ -790,7 +783,14 @@ static int cake_print_xstats(struct qdisc_util *qu, FILE *f,
#define PRINT_TSTAT_U64(name, attr) PRINT_TSTAT( \
name, attr, "llu", rta_getattr_u64(GET_TSTAT(i, attr)))

SPRINT_TSTAT(rate, u64, " thresh ", THRESHOLD_RATE64);
if (GET_TSTAT(0, THRESHOLD_RATE64)) {
fprintf(f, " thresh ");
for (i = 0; i < num_tins; i++)
tc_print_rate(PRINT_FP, NULL, " %12s",
rta_getattr_u64(GET_TSTAT(i, THRESHOLD_RATE64)));
fprintf(f, "%s", _SL_);
}

SPRINT_TSTAT(time, u32, " target ", TARGET_US);
SPRINT_TSTAT(time, u32, " interval", INTERVAL_US);
SPRINT_TSTAT(time, u32, " pk_delay", PEAK_DELAY_US);
Expand Down
Loading

0 comments on commit 120cdeb

Please sign in to comment.