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