tc_util.c revision 6dc9f016347441fbf94cf851c054b0f45ba32c1c
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 >= 1024*1023 &&
187		    fabs(1024*1024*rint(tmp/(1024*1024)) - tmp) < 1024)
188			snprintf(buf, len, "%gMibit", rint(tmp/(1024*1024)));
189		else if (tmp >= 1024-16 && fabs(1024*rint(tmp/1024) - tmp) < 16)
190			snprintf(buf, len, "%gKibit", rint(tmp/1024));
191		else
192			snprintf(buf, len, "%ubit", rate);
193
194	} else {
195		if (tmp >= 999999 &&
196		    fabs(1000000.*rint(tmp/1000000.) - tmp) < 1000)
197			snprintf(buf, len, "%gMbit", rint(tmp/1000000.));
198		else if (tmp >= 990 && fabs(1000.*rint(tmp/1000.) - tmp) < 10)
199			snprintf(buf, len, "%gKbit", rint(tmp/1000.));
200		else
201			snprintf(buf, len, "%ubit", rate);
202	}
203}
204
205char * sprint_rate(__u32 rate, char *buf)
206{
207	print_rate(buf, SPRINT_BSIZE-1, rate);
208	return buf;
209}
210
211int get_usecs(unsigned *usecs, const char *str)
212{
213	double t;
214	char *p;
215
216	t = strtod(str, &p);
217	if (p == str)
218		return -1;
219
220	if (*p) {
221		if (strcasecmp(p, "s") == 0 || strcasecmp(p, "sec")==0 ||
222		    strcasecmp(p, "secs")==0)
223			t *= 1000000;
224		else if (strcasecmp(p, "ms") == 0 || strcasecmp(p, "msec")==0 ||
225			 strcasecmp(p, "msecs") == 0)
226			t *= 1000;
227		else if (strcasecmp(p, "us") == 0 || strcasecmp(p, "usec")==0 ||
228			 strcasecmp(p, "usecs") == 0)
229			t *= 1;
230		else
231			return -1;
232	}
233
234	*usecs = t;
235	return 0;
236}
237
238
239void print_usecs(char *buf, int len, __u32 usec)
240{
241	double tmp = usec;
242
243	if (tmp >= 1000000)
244		snprintf(buf, len, "%.1fs", tmp/1000000);
245	else if (tmp >= 1000)
246		snprintf(buf, len, "%.1fms", tmp/1000);
247	else
248		snprintf(buf, len, "%uus", usec);
249}
250
251char * sprint_usecs(__u32 usecs, char *buf)
252{
253	print_usecs(buf, SPRINT_BSIZE-1, usecs);
254	return buf;
255}
256
257int get_size(unsigned *size, const char *str)
258{
259	double sz;
260	char *p;
261
262	sz = strtod(str, &p);
263	if (p == str)
264		return -1;
265
266	if (*p) {
267		if (strcasecmp(p, "kb") == 0 || strcasecmp(p, "k")==0)
268			sz *= 1024;
269		else if (strcasecmp(p, "gb") == 0 || strcasecmp(p, "g")==0)
270			sz *= 1024*1024*1024;
271		else if (strcasecmp(p, "gbit") == 0)
272			sz *= 1024*1024*1024/8;
273		else if (strcasecmp(p, "mb") == 0 || strcasecmp(p, "m")==0)
274			sz *= 1024*1024;
275		else if (strcasecmp(p, "mbit") == 0)
276			sz *= 1024*1024/8;
277		else if (strcasecmp(p, "kbit") == 0)
278			sz *= 1024/8;
279		else if (strcasecmp(p, "b") != 0)
280			return -1;
281	}
282
283	*size = sz;
284	return 0;
285}
286
287int get_size_and_cell(unsigned *size, int *cell_log, char *str)
288{
289	char * slash = strchr(str, '/');
290
291	if (slash)
292		*slash = 0;
293
294	if (get_size(size, str))
295		return -1;
296
297	if (slash) {
298		int cell;
299		int i;
300
301		if (get_integer(&cell, slash+1, 0))
302			return -1;
303		*slash = '/';
304
305		for (i=0; i<32; i++) {
306			if ((1<<i) == cell) {
307				*cell_log = i;
308				return 0;
309			}
310		}
311		return -1;
312	}
313	return 0;
314}
315
316void print_size(char *buf, int len, __u32 sz)
317{
318	double tmp = sz;
319
320	if (sz >= 1024*1024 && fabs(1024*1024*rint(tmp/(1024*1024)) - sz) < 1024)
321		snprintf(buf, len, "%gMb", rint(tmp/(1024*1024)));
322	else if (sz >= 1024 && fabs(1024*rint(tmp/1024) - sz) < 16)
323		snprintf(buf, len, "%gKb", rint(tmp/1024));
324	else
325		snprintf(buf, len, "%ub", sz);
326}
327
328char * sprint_size(__u32 size, char *buf)
329{
330	print_size(buf, SPRINT_BSIZE-1, size);
331	return buf;
332}
333
334static const double max_percent_value = 0xffffffff;
335
336int get_percent(__u32 *percent, const char *str)
337{
338	char *p;
339	double per = strtod(str, &p) / 100.;
340
341	if (per > 1. || per < 0)
342		return -1;
343	if (*p && strcmp(p, "%"))
344		return -1;
345
346	*percent = (unsigned) rint(per * max_percent_value);
347	return 0;
348}
349
350void print_percent(char *buf, int len, __u32 per)
351{
352	snprintf(buf, len, "%g%%", 100. * (double) per / max_percent_value);
353}
354
355char * sprint_percent(__u32 per, char *buf)
356{
357	print_percent(buf, SPRINT_BSIZE-1, per);
358	return buf;
359}
360
361void print_qdisc_handle(char *buf, int len, __u32 h)
362{
363	snprintf(buf, len, "%x:", TC_H_MAJ(h)>>16);
364}
365
366char * sprint_qdisc_handle(__u32 h, char *buf)
367{
368	print_qdisc_handle(buf, SPRINT_BSIZE-1, h);
369	return buf;
370}
371
372char * action_n2a(int action, char *buf, int len)
373{
374	switch (action) {
375	case -1:
376		return "continue";
377		break;
378	case TC_ACT_OK:
379		return "pass";
380		break;
381	case TC_ACT_SHOT:
382		return "drop";
383		break;
384	case TC_ACT_RECLASSIFY:
385		return "reclassify";
386	case TC_ACT_PIPE:
387		return "pipe";
388	case TC_ACT_STOLEN:
389		return "stolen";
390	default:
391		snprintf(buf, len, "%d", action);
392		return buf;
393	}
394}
395
396int action_a2n(char *arg, int *result)
397{
398	int res;
399
400	if (matches(arg, "continue") == 0)
401		res = -1;
402	else if (matches(arg, "drop") == 0)
403		res = TC_ACT_SHOT;
404	else if (matches(arg, "shot") == 0)
405		res = TC_ACT_SHOT;
406	else if (matches(arg, "pass") == 0)
407		res = TC_ACT_OK;
408	else if (strcmp(arg, "ok") == 0)
409		res = TC_ACT_OK;
410	else if (matches(arg, "reclassify") == 0)
411		res = TC_ACT_RECLASSIFY;
412	else {
413		char dummy;
414		if (sscanf(arg, "%d%c", &res, &dummy) != 1)
415			return -1;
416	}
417	*result = res;
418	return 0;
419}
420
421void print_tm(FILE * f, const struct tcf_t *tm)
422{
423	int hz = get_hz();
424	if (tm->install != 0)
425		fprintf(f, " installed %d sec", tm->install/hz);
426	if (tm->lastuse != 0)
427		fprintf(f, " used %d sec", tm->lastuse/hz);
428	if (tm->expires != 0)
429		fprintf(f, " expires %d sec", tm->expires/hz);
430}
431