1/*
2 * m_police.c		Parse/print policing module options.
3 *
4 *		This program is free software; you can u32istribute 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 * FIXES:       19990619 - J Hadi Salim (hadi@cyberus.ca)
11 *		simple addattr packaging fix.
12 */
13
14#include <stdio.h>
15#include <stdlib.h>
16#include <unistd.h>
17#include <syslog.h>
18#include <fcntl.h>
19#include <sys/socket.h>
20#include <netinet/in.h>
21#include <arpa/inet.h>
22#include <string.h>
23
24#include "utils.h"
25#include "tc_util.h"
26
27static void explain(void)
28{
29	fprintf(stderr, "Usage: ... police rate BPS burst BYTES[/BYTES] [ mtu BYTES[/BYTES] ]\n");
30	fprintf(stderr, "                [ peakrate BPS ] [ avrate BPS ]\n");
31	fprintf(stderr, "                [ ACTION ]\n");
32	fprintf(stderr, "Where: ACTION := reclassify | drop | continue \n");
33}
34
35static void explain1(char *arg)
36{
37	fprintf(stderr, "Illegal \"%s\"\n", arg);
38}
39
40#define usage() return(-1)
41
42
43char *police_action_n2a(int action, char *buf, int len)
44{
45	switch (action) {
46	case -1:
47		return "continue";
48		break;
49	case TC_POLICE_OK:
50		return "pass";
51		break;
52	case TC_POLICE_SHOT:
53		return "drop";
54		break;
55	case TC_POLICE_RECLASSIFY:
56		return "reclassify";
57	default:
58		snprintf(buf, len, "%d", action);
59		return buf;
60	}
61}
62
63int police_action_a2n(char *arg, int *result)
64{
65	int res;
66
67	if (matches(arg, "continue") == 0)
68		res = -1;
69	else if (matches(arg, "drop") == 0)
70		res = TC_POLICE_SHOT;
71	else if (matches(arg, "shot") == 0)
72		res = TC_POLICE_SHOT;
73	else if (matches(arg, "pass") == 0)
74		res = TC_POLICE_OK;
75	else if (strcmp(arg, "ok") == 0)
76		res = TC_POLICE_OK;
77	else if (matches(arg, "reclassify") == 0)
78		res = TC_POLICE_RECLASSIFY;
79	else {
80		char dummy;
81		if (sscanf(arg, "%d%c", &res, &dummy) != 1)
82			return -1;
83	}
84	*result = res;
85	return 0;
86}
87
88
89int get_police_result(int *action, int *result, char *arg)
90{
91	char *p = strchr(arg, '/');
92
93	if (p)
94		*p = 0;
95
96	if (police_action_a2n(arg, action)) {
97		if (p)
98			*p = '/';
99		return -1;
100	}
101
102	if (p) {
103		*p = '/';
104		if (police_action_a2n(p+1, result))
105			return -1;
106	}
107	return 0;
108}
109
110int parse_police(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n)
111{
112	int argc = *argc_p;
113	char **argv = *argv_p;
114	int res = -1;
115	int ok=0;
116	struct tc_police p;
117	__u32 rtab[256];
118	__u32 ptab[256];
119	__u32 avrate = 0;
120	int presult = 0;
121	unsigned buffer=0, mtu=0, mpu=0;
122	int Rcell_log=-1, Pcell_log = -1;
123	struct rtattr *tail;
124
125	memset(&p, 0, sizeof(p));
126	p.action = TC_POLICE_RECLASSIFY;
127
128	if (argc <= 0)
129		return -1;
130
131	while (argc > 0) {
132		if (matches(*argv, "index") == 0) {
133			NEXT_ARG();
134			if (get_u32(&p.index, *argv, 16)) {
135				fprintf(stderr, "Illegal \"index\"\n");
136				return -1;
137			}
138		} else if (matches(*argv, "burst") == 0 ||
139			strcmp(*argv, "buffer") == 0 ||
140			strcmp(*argv, "maxburst") == 0) {
141			NEXT_ARG();
142			if (buffer) {
143				fprintf(stderr, "Double \"buffer/burst\" spec\n");
144				return -1;
145			}
146			if (get_size_and_cell(&buffer, &Rcell_log, *argv) < 0) {
147				explain1("buffer");
148				return -1;
149			}
150		} else if (strcmp(*argv, "mtu") == 0 ||
151			   strcmp(*argv, "minburst") == 0) {
152			NEXT_ARG();
153			if (mtu) {
154				fprintf(stderr, "Double \"mtu/minburst\" spec\n");
155				return -1;
156			}
157			if (get_size_and_cell(&mtu, &Pcell_log, *argv) < 0) {
158				explain1("mtu");
159				return -1;
160			}
161		} else if (strcmp(*argv, "mpu") == 0) {
162			NEXT_ARG();
163			if (mpu) {
164				fprintf(stderr, "Double \"mpu\" spec\n");
165				return -1;
166			}
167			if (get_size(&mpu, *argv)) {
168				explain1("mpu");
169				return -1;
170			}
171		} else if (strcmp(*argv, "rate") == 0) {
172			NEXT_ARG();
173			if (p.rate.rate) {
174				fprintf(stderr, "Double \"rate\" spec\n");
175				return -1;
176			}
177			if (get_rate(&p.rate.rate, *argv)) {
178				explain1("rate");
179				return -1;
180			}
181		} else if (strcmp(*argv, "avrate") == 0) {
182			NEXT_ARG();
183			if (avrate) {
184				fprintf(stderr, "Double \"avrate\" spec\n");
185				return -1;
186			}
187			if (get_rate(&avrate, *argv)) {
188				explain1("avrate");
189				return -1;
190			}
191		} else if (matches(*argv, "peakrate") == 0) {
192			NEXT_ARG();
193			if (p.peakrate.rate) {
194				fprintf(stderr, "Double \"peakrate\" spec\n");
195				return -1;
196			}
197			if (get_rate(&p.peakrate.rate, *argv)) {
198				explain1("peakrate");
199				return -1;
200			}
201		} else if (matches(*argv, "reclassify") == 0) {
202			p.action = TC_POLICE_RECLASSIFY;
203		} else if (matches(*argv, "drop") == 0 ||
204			   matches(*argv, "shot") == 0) {
205			p.action = TC_POLICE_SHOT;
206		} else if (matches(*argv, "continue") == 0) {
207			p.action = TC_POLICE_UNSPEC;
208		} else if (matches(*argv, "pass") == 0) {
209			p.action = TC_POLICE_OK;
210		} else if (strcmp(*argv, "action") == 0) {
211			NEXT_ARG();
212			if (get_police_result(&p.action, &presult, *argv)) {
213				fprintf(stderr, "Illegal \"action\"\n");
214				return -1;
215			}
216		} else if (strcmp(*argv, "help") == 0) {
217			explain();
218			return -1;
219		} else {
220			break;
221		}
222		ok++;
223		argc--; argv++;
224	}
225
226	if (!ok)
227		return -1;
228
229	if (p.rate.rate && !buffer) {
230		fprintf(stderr, "\"burst\" requires \"rate\".\n");
231		return -1;
232	}
233	if (p.peakrate.rate) {
234		if (!p.rate.rate) {
235			fprintf(stderr, "\"peakrate\" requires \"rate\".\n");
236			return -1;
237		}
238		if (!mtu) {
239			fprintf(stderr, "\"mtu\" is required, if \"peakrate\" is requested.\n");
240			return -1;
241		}
242	}
243
244	if (p.rate.rate) {
245		if ((Rcell_log = tc_calc_rtable(p.rate.rate, rtab, Rcell_log, mtu, mpu)) < 0) {
246			fprintf(stderr, "TBF: failed to calculate rate table.\n");
247			return -1;
248		}
249		p.burst = tc_calc_xmittime(p.rate.rate, buffer);
250		p.rate.cell_log = Rcell_log;
251		p.rate.mpu = mpu;
252	}
253	p.mtu = mtu;
254	if (p.peakrate.rate) {
255		if ((Pcell_log = tc_calc_rtable(p.peakrate.rate, ptab, Pcell_log, mtu, mpu)) < 0) {
256			fprintf(stderr, "POLICE: failed to calculate peak rate table.\n");
257			return -1;
258		}
259		p.peakrate.cell_log = Pcell_log;
260		p.peakrate.mpu = mpu;
261	}
262
263	tail = (struct rtattr*)(((void*)n)+NLMSG_ALIGN(n->nlmsg_len));
264	addattr_l(n, 1024, tca_id, NULL, 0);
265	addattr_l(n, 2024, TCA_POLICE_TBF, &p, sizeof(p));
266	if (p.rate.rate)
267		addattr_l(n, 3024, TCA_POLICE_RATE, rtab, 1024);
268	if (p.peakrate.rate)
269                addattr_l(n, 4096, TCA_POLICE_PEAKRATE, ptab, 1024);
270	if (avrate)
271		addattr32(n, 4096, TCA_POLICE_AVRATE, avrate);
272	if (presult)
273		addattr32(n, 4096, TCA_POLICE_RESULT, presult);
274#if 0
275#endif
276
277	tail->rta_len = (((void*)n)+NLMSG_ALIGN(n->nlmsg_len)) - (void*)tail;
278	res = 0;
279
280	*argc_p = argc;
281	*argv_p = argv;
282	return res;
283}
284
285
286int tc_print_police(FILE *f, struct rtattr *arg)
287{
288	SPRINT_BUF(b1);
289	struct tc_police *p;
290	struct rtattr *tb[TCA_POLICE_MAX+1];
291	unsigned buffer;
292
293	if (arg == NULL)
294		return 0;
295
296	memset(tb, 0, sizeof(tb));
297	parse_rtattr(tb, TCA_POLICE_MAX, RTA_DATA(arg), RTA_PAYLOAD(arg));
298
299	if (tb[TCA_POLICE_TBF] == NULL) {
300		fprintf(f, "[NULL police tbf]");
301		return 0;
302	}
303	if (RTA_PAYLOAD(tb[TCA_POLICE_TBF])  < sizeof(*p)) {
304		fprintf(f, "[truncated police tbf]");
305		return -1;
306	}
307	p = RTA_DATA(tb[TCA_POLICE_TBF]);
308
309	fprintf(f, "police %x ", p->index);
310	fprintf(f, "action %s", police_action_n2a(p->action, b1, sizeof(b1)));
311	if (tb[TCA_POLICE_RESULT]) {
312		fprintf(f, "/%s ", police_action_n2a(*(int*)RTA_DATA(tb[TCA_POLICE_RESULT]), b1, sizeof(b1)));
313	} else
314		fprintf(f, " ");
315	fprintf(f, "rate %s ", sprint_rate(p->rate.rate, b1));
316	buffer = ((double)p->rate.rate*tc_core_tick2usec(p->burst))/1000000;
317	fprintf(f, "burst %s ", sprint_size(buffer, b1));
318	fprintf(f, "mtu %s ", sprint_size(p->mtu, b1));
319	if (show_raw)
320		fprintf(f, "[%08x] ", p->burst);
321	if (p->peakrate.rate)
322		fprintf(f, "peakrate %s ", sprint_rate(p->peakrate.rate, b1));
323	if (tb[TCA_POLICE_AVRATE])
324		fprintf(f, "avrate %s ", sprint_rate(*(__u32*)RTA_DATA(tb[TCA_POLICE_AVRATE]), b1));
325
326	return 0;
327}
328
329