1/*
2 * q_rr.c		RR.
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:	PJ Waskiewicz, <peter.p.waskiewicz.jr@intel.com>
10 * Original Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> (from PRIO)
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
23#include "utils.h"
24#include "tc_util.h"
25
26static void explain(void)
27{
28	fprintf(stderr, "Usage: ... rr bands NUMBER priomap P1 P2... [multiqueue]\n");
29}
30
31
32static int rr_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
33{
34	int pmap_mode = 0;
35	int idx = 0;
36	struct tc_prio_qopt opt={3,{ 1, 2, 2, 2, 1, 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 }};
37	struct rtattr *nest;
38	unsigned char mq = 0;
39
40	while (argc > 0) {
41		if (strcmp(*argv, "bands") == 0) {
42			if (pmap_mode)
43				explain();
44			NEXT_ARG();
45			if (get_integer(&opt.bands, *argv, 10)) {
46				fprintf(stderr, "Illegal \"bands\"\n");
47				return -1;
48			}
49		} else if (strcmp(*argv, "priomap") == 0) {
50			if (pmap_mode) {
51				fprintf(stderr, "Error: duplicate priomap\n");
52				return -1;
53			}
54			pmap_mode = 1;
55		} else if (strcmp(*argv, "help") == 0) {
56			explain();
57			return -1;
58		} else if (strcmp(*argv, "multiqueue") == 0) {
59			mq = 1;
60		} else {
61			unsigned band;
62			if (!pmap_mode) {
63				fprintf(stderr, "What is \"%s\"?\n", *argv);
64				explain();
65				return -1;
66			}
67			if (get_unsigned(&band, *argv, 10)) {
68				fprintf(stderr, "Illegal \"priomap\" element\n");
69				return -1;
70			}
71			if (band > opt.bands) {
72				fprintf(stderr, "\"priomap\" element is out of bands\n");
73				return -1;
74			}
75			if (idx > TC_PRIO_MAX) {
76				fprintf(stderr, "\"priomap\" index > TC_RR_MAX=%u\n", TC_PRIO_MAX);
77				return -1;
78			}
79			opt.priomap[idx++] = band;
80		}
81		argc--; argv++;
82	}
83
84	nest = addattr_nest_compat(n, 1024, TCA_OPTIONS, &opt, sizeof(opt));
85	if (mq)
86		addattr_l(n, 1024, TCA_PRIO_MQ, NULL, 0);
87	addattr_nest_compat_end(n, nest);
88	return 0;
89}
90
91int rr_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
92{
93	int i;
94	struct tc_prio_qopt *qopt;
95	struct rtattr *tb[TCA_PRIO_MAX + 1];
96
97	if (opt == NULL)
98		return 0;
99
100	if (parse_rtattr_nested_compat(tb, TCA_PRIO_MAX, opt, qopt,
101						sizeof(*qopt)))
102		return -1;
103
104	fprintf(f, "bands %u priomap ", qopt->bands);
105	for (i=0; i <= TC_PRIO_MAX; i++)
106		fprintf(f, " %d", qopt->priomap[i]);
107
108	if (tb[TCA_PRIO_MQ])
109		fprintf(f, " multiqueue: %s ",
110			rta_getattr_u8(tb[TCA_PRIO_MQ]) ? "on" : "off");
111
112	return 0;
113}
114
115struct qdisc_util rr_qdisc_util = {
116	.id	 	= "rr",
117	.parse_qopt	= rr_parse_opt,
118	.print_qopt	= rr_print_opt,
119};
120