1/*
2 * src/nl-qdisc-dump.c     Dump qdisc attributes
3 *
4 *	This library is free software; you can redistribute it and/or
5 *	modify it under the terms of the GNU Lesser General Public
6 *	License as published by the Free Software Foundation version 2.1
7 *	of the License.
8 *
9 * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
10 */
11
12#include "utils.h"
13#include <netlink/route/sch/fifo.h>
14#include <netlink/route/sch/prio.h>
15
16static void print_usage(void)
17{
18	printf(
19"Usage: nl-qdisc-add <ifindex> <handle> <parent> <kind>\n");
20	exit(1);
21}
22
23static int parse_blackhole_opts(struct rtnl_qdisc *qdisc, char *argv[],
24				int argc)
25{
26	return 0;
27}
28
29static int parse_pfifo_opts(struct rtnl_qdisc *qdisc, char *argv[], int argc)
30{
31	int err, limit;
32
33	if (argc > 0) {
34		if (argc != 2 || strcasecmp(argv[0], "limit")) {
35			fprintf(stderr, "Usage: ... pfifo limit <limit>\n");
36			return -1;
37		}
38
39		limit = strtoul(argv[1], NULL, 0);
40		err = rtnl_qdisc_fifo_set_limit(qdisc, limit);
41		if (err < 0) {
42			fprintf(stderr, "%s\n", nl_geterror());
43			return -1;
44		}
45	}
46
47	return 0;
48}
49
50static int parse_bfifo_opts(struct rtnl_qdisc *qdisc, char *argv[], int argc)
51{
52	int err, limit;
53
54	if (argc > 0) {
55		if (argc != 2 || strcasecmp(argv[0], "limit")) {
56			fprintf(stderr, "Usage: ... bfifo limit <limit>\n");
57			return -1;
58		}
59
60		limit = nl_size2int(argv[1]);
61		if (limit < 0) {
62			fprintf(stderr, "Invalid value for limit.\n");
63			return -1;
64		}
65
66		err = rtnl_qdisc_fifo_set_limit(qdisc, limit);
67		if (err < 0) {
68			fprintf(stderr, "%s\n", nl_geterror());
69			return -1;
70		}
71	}
72
73	return 0;
74}
75
76static int parse_prio_opts(struct rtnl_qdisc *qdisc, char *argv[], int argc)
77{
78	int i, err, bands;
79	uint8_t map[] = QDISC_PRIO_DEFAULT_PRIOMAP;
80
81	if (argc > 0) {
82		if (argc < 2 || strcasecmp(argv[0], "bands"))
83			goto usage;
84
85		bands = strtoul(argv[1], NULL, 0);
86		err = rtnl_qdisc_prio_set_bands(qdisc, bands);
87		if (err < 0) {
88			fprintf(stderr, "%s\n", nl_geterror());
89			return -1;
90		}
91	}
92
93	if (argc > 2) {
94		if (argc < 5 || strcasecmp(argv[2], "map"))
95			goto usage;
96
97		for (i = 3; i < (argc & ~1U); i += 2) {
98			int prio, band;
99
100			prio = rtnl_str2prio(argv[i]);
101			if (prio < 0 || prio > sizeof(map)/sizeof(map[0])) {
102				fprintf(stderr, "Invalid priority \"%s\"\n",
103					argv[i]);
104				return -1;
105			}
106
107			band = strtoul(argv[i+1], NULL, 0);
108
109			map[prio] = band;
110		}
111	}
112
113	err = rtnl_qdisc_prio_set_priomap(qdisc, map, sizeof(map));
114	if (err < 0) {
115		fprintf(stderr, "%s\n", nl_geterror());
116		return -1;
117	}
118
119	return 0;
120usage:
121	fprintf(stderr, "Usage: ... prio bands <nbands> map MAP\n"
122			"MAP := <prio> <band>\n");
123	return -1;
124}
125
126int main(int argc, char *argv[])
127{
128	struct nl_sock *nlh;
129	struct rtnl_qdisc *qdisc;
130	uint32_t handle, parent;
131	int err = 1;
132
133	if (nltool_init(argc, argv) < 0)
134		return -1;
135
136	if (argc < 5 || !strcmp(argv[1], "-h"))
137		print_usage();
138
139	nlh = nltool_alloc_handle();
140	if (!nlh)
141		goto errout;
142
143	qdisc = rtnl_qdisc_alloc();
144	if (!qdisc)
145		goto errout_free_handle;
146
147	rtnl_qdisc_set_ifindex(qdisc, strtoul(argv[1], NULL, 0));
148
149	if (rtnl_tc_str2handle(argv[2], &handle) < 0) {
150		fprintf(stderr, "%s\n", nl_geterror());
151		goto errout_free_qdisc;
152	}
153
154	if (rtnl_tc_str2handle(argv[3], &parent) < 0) {
155		fprintf(stderr, "%s\n", nl_geterror());
156		goto errout_free_qdisc;
157	}
158
159	rtnl_qdisc_set_handle(qdisc, handle);
160	rtnl_qdisc_set_parent(qdisc, parent);
161	rtnl_qdisc_set_kind(qdisc, argv[4]);
162
163	if (!strcasecmp(argv[4], "blackhole"))
164		err = parse_blackhole_opts(qdisc, &argv[5], argc-5);
165	else if (!strcasecmp(argv[4], "pfifo"))
166		err = parse_pfifo_opts(qdisc, &argv[5], argc-5);
167	else if (!strcasecmp(argv[4], "bfifo"))
168		err = parse_bfifo_opts(qdisc, &argv[5], argc-5);
169	else if (!strcasecmp(argv[4], "prio"))
170		err = parse_prio_opts(qdisc, &argv[5], argc-5);
171	else {
172		fprintf(stderr, "Unknown qdisc \"%s\"\n", argv[4]);
173		goto errout_free_qdisc;
174	}
175
176	if (err < 0)
177		goto errout_free_qdisc;
178
179	if (nltool_connect(nlh, NETLINK_ROUTE) < 0)
180		goto errout_free_qdisc;
181
182	if (rtnl_qdisc_add(nlh, qdisc, NLM_F_REPLACE) < 0) {
183		fprintf(stderr, "Unable to add Qdisc: %s\n", nl_geterror());
184		goto errout_close;
185	}
186
187	err = 0;
188errout_close:
189	nl_close(nlh);
190errout_free_qdisc:
191	rtnl_qdisc_put(qdisc);
192errout_free_handle:
193	nl_handle_destroy(nlh);
194errout:
195	return err;
196}
197