tc_util.c revision e5879dc603ca2e9f27ca6d754fdf5e20f8072344
1/*
2 * tc_util.c		Misc TC utility functions.
3 *
4 *		This program is free software; you can redistribute it and/or
5 *		modify it under the terms of the GNU General Public License
6 *		as published by the Free Software Foundation; either version
7 *		2 of the License, or (at your option) any later version.
8 *
9 * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10 *
11 */
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <unistd.h>
16#include <syslog.h>
17#include <fcntl.h>
18#include <sys/socket.h>
19#include <netinet/in.h>
20#include <arpa/inet.h>
21#include <string.h>
22#include <math.h>
23
24#include "utils.h"
25#include "tc_util.h"
26
27int get_qdisc_handle(__u32 *h, const char *str)
28{
29	__u32 maj;
30	char *p;
31
32	maj = TC_H_UNSPEC;
33	if (strcmp(str, "none") == 0)
34		goto ok;
35	maj = strtoul(str, &p, 16);
36	if (p == str)
37		return -1;
38	maj <<= 16;
39	if (*p != ':' && *p!=0)
40		return -1;
41ok:
42	*h = maj;
43	return 0;
44}
45
46int get_tc_classid(__u32 *h, const char *str)
47{
48	__u32 maj, min;
49	char *p;
50
51	maj = TC_H_ROOT;
52	if (strcmp(str, "root") == 0)
53		goto ok;
54	maj = TC_H_UNSPEC;
55	if (strcmp(str, "none") == 0)
56		goto ok;
57	maj = strtoul(str, &p, 16);
58	if (p == str) {
59		maj = 0;
60		if (*p != ':')
61			return -1;
62	}
63	if (*p == ':') {
64		maj <<= 16;
65		str = p+1;
66		min = strtoul(str, &p, 16);
67		if (*p != 0)
68			return -1;
69		maj |= min;
70	} else if (*p != 0)
71		return -1;
72
73ok:
74	*h = maj;
75	return 0;
76}
77
78int print_tc_classid(char *buf, int len, __u32 h)
79{
80	if (h == TC_H_ROOT)
81		sprintf(buf, "root");
82	else if (h == TC_H_UNSPEC)
83		snprintf(buf, len, "none");
84	else if (TC_H_MAJ(h) == 0)
85		snprintf(buf, len, ":%x", TC_H_MIN(h));
86	else if (TC_H_MIN(h) == 0)
87		snprintf(buf, len, "%x:", TC_H_MAJ(h)>>16);
88	else
89		snprintf(buf, len, "%x:%x", TC_H_MAJ(h)>>16, TC_H_MIN(h));
90	return 0;
91}
92
93char * sprint_tc_classid(__u32 h, char *buf)
94{
95	if (print_tc_classid(buf, SPRINT_BSIZE-1, h))
96		strcpy(buf, "???");
97	return buf;
98}
99
100/* See http://physics.nist.gov/cuu/Units/binary.html */
101static const struct rate_suffix {
102	const char *name;
103	double scale;
104} suffixes[] = {
105	{ "bit",	1. },
106	{ "Kibit",	1024. },
107	{ "kbit",	1000. },
108	{ "mibit",	1024.*1024. },
109	{ "mbit",	1000000. },
110	{ "gibit",	1024.*1024.*1024. },
111	{ "gbit",	1000000000. },
112	{ "tibit",	1024.*1024.*1024.*1024. },
113	{ "tbit",	1000000000000. },
114	{ "Bps",	8. },
115	{ "KiBps",	8.*1024. },
116	{ "KBps",	8000. },
117	{ "MiBps",	8.*1024*1024. },
118	{ "MBps",	8000000. },
119	{ "GiBps",	8.*1024.*1024.*1024. },
120	{ "GBps",	8000000000. },
121	{ "TiBps",	8.*1024.*1024.*1024.*1024. },
122	{ "TBps",	8000000000000. },
123	{ NULL }
124};
125
126
127int get_rate(unsigned *rate, const char *str)
128{
129	char *p;
130	double bps = strtod(str, &p);
131	const struct rate_suffix *s;
132
133	if (p == str)
134		return -1;
135
136	if (*p == '\0') {
137		*rate = bps / 8.;	/* assume bytes/sec */
138		return 0;
139	}
140
141	for (s = suffixes; s->name; ++s) {
142		if (strcasecmp(s->name, p) == 0) {
143			*rate = (bps * s->scale) / 8.;
144			return 0;
145		}
146	}
147
148	return -1;
149}
150
151int get_rate_and_cell(unsigned *rate, int *cell_log, char *str)
152{
153	char * slash = strchr(str, '/');
154
155	if (slash)
156		*slash = 0;
157
158	if (get_rate(rate, str))
159		return -1;
160
161	if (slash) {
162		int cell;
163		int i;
164
165		if (get_integer(&cell, slash+1, 0))
166			return -1;
167		*slash = '/';
168
169		for (i=0; i<32; i++) {
170			if ((1<<i) == cell) {
171				*cell_log = i;
172				return 0;
173			}
174		}
175		return -1;
176	}
177	return 0;
178}
179
180void print_rate(char *buf, int len, __u32 rate)
181{
182	double tmp = (double)rate*8;
183	extern int use_iec;
184
185	if (use_iec) {
186		if (tmp >= 1000.0*1024.0*1024.0)
187			snprintf(buf, len, "%.0fMibit", tmp/1024.0*1024.0);
188		else if (tmp >= 1000.0*1024)
189			snprintf(buf, len, "%.0fKibit", tmp/1024);
190		else
191			snprintf(buf, len, "%.0fbit", tmp);
192	} else {
193		if (tmp >= 1000.0*1000000.0)
194			snprintf(buf, len, "%.0fMbit", tmp/1000000.0);
195		else if (tmp >= 1000.0 * 1000.0)
196			snprintf(buf, len, "%.0fKbit", tmp/1000.0);
197		else
198			snprintf(buf, len, "%.0fbit",  tmp);
199	}
200}
201
202char * sprint_rate(__u32 rate, char *buf)
203{
204	print_rate(buf, SPRINT_BSIZE-1, rate);
205	return buf;
206}
207
208int get_usecs(unsigned *usecs, const char *str)
209{
210	double t;
211	char *p;
212
213	t = strtod(str, &p);
214	if (p == str)
215		return -1;
216
217	if (*p) {
218		if (strcasecmp(p, "s") == 0 || strcasecmp(p, "sec")==0 ||
219		    strcasecmp(p, "secs")==0)
220			t *= 1000000;
221		else if (strcasecmp(p, "ms") == 0 || strcasecmp(p, "msec")==0 ||
222			 strcasecmp(p, "msecs") == 0)
223			t *= 1000;
224		else if (strcasecmp(p, "us") == 0 || strcasecmp(p, "usec")==0 ||
225			 strcasecmp(p, "usecs") == 0)
226			t *= 1;
227		else
228			return -1;
229	}
230
231	*usecs = t;
232	return 0;
233}
234
235
236void print_usecs(char *buf, int len, __u32 usec)
237{
238	double tmp = usec;
239
240	if (tmp >= 1000000)
241		snprintf(buf, len, "%.1fs", tmp/1000000);
242	else if (tmp >= 1000)
243		snprintf(buf, len, "%.1fms", tmp/1000);
244	else
245		snprintf(buf, len, "%uus", usec);
246}
247
248char * sprint_usecs(__u32 usecs, char *buf)
249{
250	print_usecs(buf, SPRINT_BSIZE-1, usecs);
251	return buf;
252}
253
254int get_size(unsigned *size, const char *str)
255{
256	double sz;
257	char *p;
258
259	sz = strtod(str, &p);
260	if (p == str)
261		return -1;
262
263	if (*p) {
264		if (strcasecmp(p, "kb") == 0 || strcasecmp(p, "k")==0)
265			sz *= 1024;
266		else if (strcasecmp(p, "gb") == 0 || strcasecmp(p, "g")==0)
267			sz *= 1024*1024*1024;
268		else if (strcasecmp(p, "gbit") == 0)
269			sz *= 1024*1024*1024/8;
270		else if (strcasecmp(p, "mb") == 0 || strcasecmp(p, "m")==0)
271			sz *= 1024*1024;
272		else if (strcasecmp(p, "mbit") == 0)
273			sz *= 1024*1024/8;
274		else if (strcasecmp(p, "kbit") == 0)
275			sz *= 1024/8;
276		else if (strcasecmp(p, "b") != 0)
277			return -1;
278	}
279
280	*size = sz;
281	return 0;
282}
283
284int get_size_and_cell(unsigned *size, int *cell_log, char *str)
285{
286	char * slash = strchr(str, '/');
287
288	if (slash)
289		*slash = 0;
290
291	if (get_size(size, str))
292		return -1;
293
294	if (slash) {
295		int cell;
296		int i;
297
298		if (get_integer(&cell, slash+1, 0))
299			return -1;
300		*slash = '/';
301
302		for (i=0; i<32; i++) {
303			if ((1<<i) == cell) {
304				*cell_log = i;
305				return 0;
306			}
307		}
308		return -1;
309	}
310	return 0;
311}
312
313void print_size(char *buf, int len, __u32 sz)
314{
315	double tmp = sz;
316
317	if (sz >= 1024*1024 && fabs(1024*1024*rint(tmp/(1024*1024)) - sz) < 1024)
318		snprintf(buf, len, "%gMb", rint(tmp/(1024*1024)));
319	else if (sz >= 1024 && fabs(1024*rint(tmp/1024) - sz) < 16)
320		snprintf(buf, len, "%gKb", rint(tmp/1024));
321	else
322		snprintf(buf, len, "%ub", sz);
323}
324
325char * sprint_size(__u32 size, char *buf)
326{
327	print_size(buf, SPRINT_BSIZE-1, size);
328	return buf;
329}
330
331static const double max_percent_value = 0xffffffff;
332
333int get_percent(__u32 *percent, const char *str)
334{
335	char *p;
336	double per = strtod(str, &p) / 100.;
337
338	if (per > 1. || per < 0)
339		return -1;
340	if (*p && strcmp(p, "%"))
341		return -1;
342
343	*percent = (unsigned) rint(per * max_percent_value);
344	return 0;
345}
346
347void print_percent(char *buf, int len, __u32 per)
348{
349	snprintf(buf, len, "%g%%", 100. * (double) per / max_percent_value);
350}
351
352char * sprint_percent(__u32 per, char *buf)
353{
354	print_percent(buf, SPRINT_BSIZE-1, per);
355	return buf;
356}
357
358void print_qdisc_handle(char *buf, int len, __u32 h)
359{
360	snprintf(buf, len, "%x:", TC_H_MAJ(h)>>16);
361}
362
363char * sprint_qdisc_handle(__u32 h, char *buf)
364{
365	print_qdisc_handle(buf, SPRINT_BSIZE-1, h);
366	return buf;
367}
368
369char * action_n2a(int action, char *buf, int len)
370{
371	switch (action) {
372	case -1:
373		return "continue";
374		break;
375	case TC_ACT_OK:
376		return "pass";
377		break;
378	case TC_ACT_SHOT:
379		return "drop";
380		break;
381	case TC_ACT_RECLASSIFY:
382		return "reclassify";
383	case TC_ACT_PIPE:
384		return "pipe";
385	case TC_ACT_STOLEN:
386		return "stolen";
387	default:
388		snprintf(buf, len, "%d", action);
389		return buf;
390	}
391}
392
393int action_a2n(char *arg, int *result)
394{
395	int res;
396
397	if (matches(arg, "continue") == 0)
398		res = -1;
399	else if (matches(arg, "drop") == 0)
400		res = TC_ACT_SHOT;
401	else if (matches(arg, "shot") == 0)
402		res = TC_ACT_SHOT;
403	else if (matches(arg, "pass") == 0)
404		res = TC_ACT_OK;
405	else if (strcmp(arg, "ok") == 0)
406		res = TC_ACT_OK;
407	else if (matches(arg, "reclassify") == 0)
408		res = TC_ACT_RECLASSIFY;
409	else {
410		char dummy;
411		if (sscanf(arg, "%d%c", &res, &dummy) != 1)
412			return -1;
413	}
414	*result = res;
415	return 0;
416}
417
418void print_tm(FILE * f, const struct tcf_t *tm)
419{
420	int hz = get_hz();
421	if (tm->install != 0)
422		fprintf(f, " installed %d sec", tm->install/hz);
423	if (tm->lastuse != 0)
424		fprintf(f, " used %d sec", tm->lastuse/hz);
425	if (tm->expires != 0)
426		fprintf(f, " expires %d sec", tm->expires/hz);
427}
428
429void print_tcstats2_attr(FILE *fp, struct rtattr *rta, char *prefix, struct rtattr **xstats)
430{
431	SPRINT_BUF(b1);
432	struct rtattr *tbs[TCA_STATS_MAX + 1] = {0};
433
434	parse_rtattr(tbs, TCA_STATS_MAX, RTA_DATA(rta), RTA_PAYLOAD(rta));
435
436	if (tbs[TCA_STATS_BASIC]) {
437		struct gnet_stats_basic bs = {0};
438		memcpy(&bs, RTA_DATA(tbs[TCA_STATS_BASIC]), MIN(RTA_PAYLOAD(tbs[TCA_STATS_BASIC]), sizeof(bs)));
439		fprintf(fp, "%sSent %llu bytes %u pkt",
440			prefix, bs.bytes, bs.packets);
441	}
442
443	if (tbs[TCA_STATS_QUEUE]) {
444		struct gnet_stats_queue q = {0};
445		memcpy(&q, RTA_DATA(tbs[TCA_STATS_QUEUE]), MIN(RTA_PAYLOAD(tbs[TCA_STATS_QUEUE]), sizeof(q)));
446		fprintf(fp, " (dropped %u, overlimits %u requeues %u) ",
447			q.drops, q.overlimits, q.requeues);
448	}
449
450	if (tbs[TCA_STATS_RATE_EST]) {
451		struct gnet_stats_rate_est re = {0};
452		memcpy(&re, RTA_DATA(tbs[TCA_STATS_RATE_EST]), MIN(RTA_PAYLOAD(tbs[TCA_STATS_RATE_EST]), sizeof(re)));
453		fprintf(fp, "\n%srate %s %upps ",
454			prefix, sprint_rate(re.bps, b1), re.pps);
455	}
456
457	if (tbs[TCA_STATS_QUEUE]) {
458		struct gnet_stats_queue q = {0};
459		memcpy(&q, RTA_DATA(tbs[TCA_STATS_QUEUE]), MIN(RTA_PAYLOAD(tbs[TCA_STATS_QUEUE]), sizeof(q)));
460		if (!tbs[TCA_STATS_RATE_EST])
461			fprintf(fp, "\n%s", prefix);
462		fprintf(fp, "backlog %s %up requeues %u ",
463			sprint_size(q.backlog, b1), q.qlen, q.requeues);
464	}
465
466	if (xstats)
467		*xstats = tbs[TCA_STATS_APP] ? : NULL;
468}
469
470void print_tcstats_attr(FILE *fp, struct rtattr *tb[], char *prefix, struct rtattr **xstats)
471{
472	SPRINT_BUF(b1);
473
474	if (tb[TCA_STATS2]) {
475		print_tcstats2_attr(fp, tb[TCA_STATS2], prefix, xstats);
476		if (xstats && NULL == *xstats)
477			goto compat_xstats;
478		return;
479	}
480	/* backward compatibility */
481	if (tb[TCA_STATS]) {
482		struct tc_stats st;
483
484		/* handle case where kernel returns more/less than we know about */
485		memset(&st, 0, sizeof(st));
486		memcpy(&st, RTA_DATA(tb[TCA_STATS]), MIN(RTA_PAYLOAD(tb[TCA_STATS]), sizeof(st)));
487
488		fprintf(fp, "%sSent %llu bytes %u pkts (dropped %u, overlimits %u) ",
489			prefix, (unsigned long long)st.bytes, st.packets, st.drops,
490			st.overlimits);
491
492		if (st.bps || st.pps || st.qlen || st.backlog) {
493			fprintf(fp, "\n%s", prefix);
494			if (st.bps || st.pps) {
495				fprintf(fp, "rate ");
496				if (st.bps)
497					fprintf(fp, "%s ", sprint_rate(st.bps, b1));
498				if (st.pps)
499					fprintf(fp, "%upps ", st.pps);
500			}
501			if (st.qlen || st.backlog) {
502				fprintf(fp, "backlog ");
503				if (st.backlog)
504					fprintf(fp, "%s ", sprint_size(st.backlog, b1));
505				if (st.qlen)
506					fprintf(fp, "%up ", st.qlen);
507			}
508		}
509	}
510
511compat_xstats:
512	if (tb[TCA_XSTATS] && xstats)
513		*xstats = tb[TCA_XSTATS];
514}
515
516