1*de1e4e89SAndroid Build Coastguard Worker /*
2*de1e4e89SAndroid Build Coastguard Worker * tc_qdisc.c "tc qdisc".
3*de1e4e89SAndroid Build Coastguard Worker *
4*de1e4e89SAndroid Build Coastguard Worker * This program is free software; you can redistribute it and/or
5*de1e4e89SAndroid Build Coastguard Worker * modify it under the terms of the GNU General Public License
6*de1e4e89SAndroid Build Coastguard Worker * as published by the Free Software Foundation; either version
7*de1e4e89SAndroid Build Coastguard Worker * 2 of the License, or (at your option) any later version.
8*de1e4e89SAndroid Build Coastguard Worker *
9*de1e4e89SAndroid Build Coastguard Worker * Authors: Alexey Kuznetsov, <[email protected]>
10*de1e4e89SAndroid Build Coastguard Worker * J Hadi Salim: Extension to ingress
11*de1e4e89SAndroid Build Coastguard Worker */
12*de1e4e89SAndroid Build Coastguard Worker
13*de1e4e89SAndroid Build Coastguard Worker #include <stdio.h>
14*de1e4e89SAndroid Build Coastguard Worker #include <stdlib.h>
15*de1e4e89SAndroid Build Coastguard Worker #include <unistd.h>
16*de1e4e89SAndroid Build Coastguard Worker #include <syslog.h>
17*de1e4e89SAndroid Build Coastguard Worker #include <fcntl.h>
18*de1e4e89SAndroid Build Coastguard Worker #include <sys/socket.h>
19*de1e4e89SAndroid Build Coastguard Worker #include <netinet/in.h>
20*de1e4e89SAndroid Build Coastguard Worker #include <arpa/inet.h>
21*de1e4e89SAndroid Build Coastguard Worker #include <string.h>
22*de1e4e89SAndroid Build Coastguard Worker #include <math.h>
23*de1e4e89SAndroid Build Coastguard Worker #include <malloc.h>
24*de1e4e89SAndroid Build Coastguard Worker
25*de1e4e89SAndroid Build Coastguard Worker #include "utils.h"
26*de1e4e89SAndroid Build Coastguard Worker #include "tc_util.h"
27*de1e4e89SAndroid Build Coastguard Worker #include "tc_common.h"
28*de1e4e89SAndroid Build Coastguard Worker
usage(void)29*de1e4e89SAndroid Build Coastguard Worker static int usage(void)
30*de1e4e89SAndroid Build Coastguard Worker {
31*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Usage: tc qdisc [ add | del | replace | change | show ] dev STRING\n");
32*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, " [ handle QHANDLE ] [ root | ingress | clsact | parent CLASSID ]\n");
33*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, " [ estimator INTERVAL TIME_CONSTANT ]\n");
34*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, " [ stab [ help | STAB_OPTIONS] ]\n");
35*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, " [ [ QDISC_KIND ] [ help | OPTIONS ] ]\n");
36*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "\n");
37*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, " tc qdisc show [ dev STRING ] [ ingress | clsact ] [ invisible ]\n");
38*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Where:\n");
39*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "QDISC_KIND := { [p|b]fifo | tbf | prio | cbq | red | etc. }\n");
40*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "OPTIONS := ... try tc qdisc add <desired QDISC_KIND> help\n");
41*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "STAB_OPTIONS := ... try tc qdisc add stab help\n");
42*de1e4e89SAndroid Build Coastguard Worker return -1;
43*de1e4e89SAndroid Build Coastguard Worker }
44*de1e4e89SAndroid Build Coastguard Worker
tc_qdisc_modify(int cmd,unsigned int flags,int argc,char ** argv)45*de1e4e89SAndroid Build Coastguard Worker static int tc_qdisc_modify(int cmd, unsigned int flags, int argc, char **argv)
46*de1e4e89SAndroid Build Coastguard Worker {
47*de1e4e89SAndroid Build Coastguard Worker struct qdisc_util *q = NULL;
48*de1e4e89SAndroid Build Coastguard Worker struct tc_estimator est = {};
49*de1e4e89SAndroid Build Coastguard Worker struct {
50*de1e4e89SAndroid Build Coastguard Worker struct tc_sizespec szopts;
51*de1e4e89SAndroid Build Coastguard Worker __u16 *data;
52*de1e4e89SAndroid Build Coastguard Worker } stab = {};
53*de1e4e89SAndroid Build Coastguard Worker char d[16] = {};
54*de1e4e89SAndroid Build Coastguard Worker char k[16] = {};
55*de1e4e89SAndroid Build Coastguard Worker struct {
56*de1e4e89SAndroid Build Coastguard Worker struct nlmsghdr n;
57*de1e4e89SAndroid Build Coastguard Worker struct tcmsg t;
58*de1e4e89SAndroid Build Coastguard Worker char buf[TCA_BUF_MAX];
59*de1e4e89SAndroid Build Coastguard Worker } req = {
60*de1e4e89SAndroid Build Coastguard Worker .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
61*de1e4e89SAndroid Build Coastguard Worker .n.nlmsg_flags = NLM_F_REQUEST | flags,
62*de1e4e89SAndroid Build Coastguard Worker .n.nlmsg_type = cmd,
63*de1e4e89SAndroid Build Coastguard Worker .t.tcm_family = AF_UNSPEC,
64*de1e4e89SAndroid Build Coastguard Worker };
65*de1e4e89SAndroid Build Coastguard Worker
66*de1e4e89SAndroid Build Coastguard Worker while (argc > 0) {
67*de1e4e89SAndroid Build Coastguard Worker if (strcmp(*argv, "dev") == 0) {
68*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
69*de1e4e89SAndroid Build Coastguard Worker if (d[0])
70*de1e4e89SAndroid Build Coastguard Worker duparg("dev", *argv);
71*de1e4e89SAndroid Build Coastguard Worker strncpy(d, *argv, sizeof(d)-1);
72*de1e4e89SAndroid Build Coastguard Worker } else if (strcmp(*argv, "handle") == 0) {
73*de1e4e89SAndroid Build Coastguard Worker __u32 handle;
74*de1e4e89SAndroid Build Coastguard Worker
75*de1e4e89SAndroid Build Coastguard Worker if (req.t.tcm_handle)
76*de1e4e89SAndroid Build Coastguard Worker duparg("handle", *argv);
77*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
78*de1e4e89SAndroid Build Coastguard Worker if (get_qdisc_handle(&handle, *argv))
79*de1e4e89SAndroid Build Coastguard Worker invarg("invalid qdisc ID", *argv);
80*de1e4e89SAndroid Build Coastguard Worker req.t.tcm_handle = handle;
81*de1e4e89SAndroid Build Coastguard Worker } else if (strcmp(*argv, "root") == 0) {
82*de1e4e89SAndroid Build Coastguard Worker if (req.t.tcm_parent) {
83*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Error: \"root\" is duplicate parent ID\n");
84*de1e4e89SAndroid Build Coastguard Worker return -1;
85*de1e4e89SAndroid Build Coastguard Worker }
86*de1e4e89SAndroid Build Coastguard Worker req.t.tcm_parent = TC_H_ROOT;
87*de1e4e89SAndroid Build Coastguard Worker } else if (strcmp(*argv, "clsact") == 0) {
88*de1e4e89SAndroid Build Coastguard Worker if (req.t.tcm_parent) {
89*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Error: \"clsact\" is a duplicate parent ID\n");
90*de1e4e89SAndroid Build Coastguard Worker return -1;
91*de1e4e89SAndroid Build Coastguard Worker }
92*de1e4e89SAndroid Build Coastguard Worker req.t.tcm_parent = TC_H_CLSACT;
93*de1e4e89SAndroid Build Coastguard Worker strncpy(k, "clsact", sizeof(k) - 1);
94*de1e4e89SAndroid Build Coastguard Worker q = get_qdisc_kind(k);
95*de1e4e89SAndroid Build Coastguard Worker req.t.tcm_handle = TC_H_MAKE(TC_H_CLSACT, 0);
96*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG_FWD();
97*de1e4e89SAndroid Build Coastguard Worker break;
98*de1e4e89SAndroid Build Coastguard Worker } else if (strcmp(*argv, "ingress") == 0) {
99*de1e4e89SAndroid Build Coastguard Worker if (req.t.tcm_parent) {
100*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Error: \"ingress\" is a duplicate parent ID\n");
101*de1e4e89SAndroid Build Coastguard Worker return -1;
102*de1e4e89SAndroid Build Coastguard Worker }
103*de1e4e89SAndroid Build Coastguard Worker req.t.tcm_parent = TC_H_INGRESS;
104*de1e4e89SAndroid Build Coastguard Worker strncpy(k, "ingress", sizeof(k) - 1);
105*de1e4e89SAndroid Build Coastguard Worker q = get_qdisc_kind(k);
106*de1e4e89SAndroid Build Coastguard Worker req.t.tcm_handle = TC_H_MAKE(TC_H_INGRESS, 0);
107*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG_FWD();
108*de1e4e89SAndroid Build Coastguard Worker break;
109*de1e4e89SAndroid Build Coastguard Worker } else if (strcmp(*argv, "parent") == 0) {
110*de1e4e89SAndroid Build Coastguard Worker __u32 handle;
111*de1e4e89SAndroid Build Coastguard Worker
112*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
113*de1e4e89SAndroid Build Coastguard Worker if (req.t.tcm_parent)
114*de1e4e89SAndroid Build Coastguard Worker duparg("parent", *argv);
115*de1e4e89SAndroid Build Coastguard Worker if (get_tc_classid(&handle, *argv))
116*de1e4e89SAndroid Build Coastguard Worker invarg("invalid parent ID", *argv);
117*de1e4e89SAndroid Build Coastguard Worker req.t.tcm_parent = handle;
118*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "estimator") == 0) {
119*de1e4e89SAndroid Build Coastguard Worker if (parse_estimator(&argc, &argv, &est))
120*de1e4e89SAndroid Build Coastguard Worker return -1;
121*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "stab") == 0) {
122*de1e4e89SAndroid Build Coastguard Worker if (parse_size_table(&argc, &argv, &stab.szopts) < 0)
123*de1e4e89SAndroid Build Coastguard Worker return -1;
124*de1e4e89SAndroid Build Coastguard Worker continue;
125*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "help") == 0) {
126*de1e4e89SAndroid Build Coastguard Worker usage();
127*de1e4e89SAndroid Build Coastguard Worker } else {
128*de1e4e89SAndroid Build Coastguard Worker strncpy(k, *argv, sizeof(k)-1);
129*de1e4e89SAndroid Build Coastguard Worker
130*de1e4e89SAndroid Build Coastguard Worker q = get_qdisc_kind(k);
131*de1e4e89SAndroid Build Coastguard Worker argc--; argv++;
132*de1e4e89SAndroid Build Coastguard Worker break;
133*de1e4e89SAndroid Build Coastguard Worker }
134*de1e4e89SAndroid Build Coastguard Worker argc--; argv++;
135*de1e4e89SAndroid Build Coastguard Worker }
136*de1e4e89SAndroid Build Coastguard Worker
137*de1e4e89SAndroid Build Coastguard Worker if (k[0])
138*de1e4e89SAndroid Build Coastguard Worker addattr_l(&req.n, sizeof(req), TCA_KIND, k, strlen(k)+1);
139*de1e4e89SAndroid Build Coastguard Worker if (est.ewma_log)
140*de1e4e89SAndroid Build Coastguard Worker addattr_l(&req.n, sizeof(req), TCA_RATE, &est, sizeof(est));
141*de1e4e89SAndroid Build Coastguard Worker
142*de1e4e89SAndroid Build Coastguard Worker if (q) {
143*de1e4e89SAndroid Build Coastguard Worker if (q->parse_qopt) {
144*de1e4e89SAndroid Build Coastguard Worker if (q->parse_qopt(q, argc, argv, &req.n))
145*de1e4e89SAndroid Build Coastguard Worker return 1;
146*de1e4e89SAndroid Build Coastguard Worker } else if (argc) {
147*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "qdisc '%s' does not support option parsing\n", k);
148*de1e4e89SAndroid Build Coastguard Worker return -1;
149*de1e4e89SAndroid Build Coastguard Worker }
150*de1e4e89SAndroid Build Coastguard Worker } else {
151*de1e4e89SAndroid Build Coastguard Worker if (argc) {
152*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "help") == 0)
153*de1e4e89SAndroid Build Coastguard Worker usage();
154*de1e4e89SAndroid Build Coastguard Worker
155*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Garbage instead of arguments \"%s ...\". Try \"tc qdisc help\".\n", *argv);
156*de1e4e89SAndroid Build Coastguard Worker return -1;
157*de1e4e89SAndroid Build Coastguard Worker }
158*de1e4e89SAndroid Build Coastguard Worker }
159*de1e4e89SAndroid Build Coastguard Worker
160*de1e4e89SAndroid Build Coastguard Worker if (check_size_table_opts(&stab.szopts)) {
161*de1e4e89SAndroid Build Coastguard Worker struct rtattr *tail;
162*de1e4e89SAndroid Build Coastguard Worker
163*de1e4e89SAndroid Build Coastguard Worker if (tc_calc_size_table(&stab.szopts, &stab.data) < 0) {
164*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "failed to calculate size table.\n");
165*de1e4e89SAndroid Build Coastguard Worker return -1;
166*de1e4e89SAndroid Build Coastguard Worker }
167*de1e4e89SAndroid Build Coastguard Worker
168*de1e4e89SAndroid Build Coastguard Worker tail = NLMSG_TAIL(&req.n);
169*de1e4e89SAndroid Build Coastguard Worker addattr_l(&req.n, sizeof(req), TCA_STAB, NULL, 0);
170*de1e4e89SAndroid Build Coastguard Worker addattr_l(&req.n, sizeof(req), TCA_STAB_BASE, &stab.szopts,
171*de1e4e89SAndroid Build Coastguard Worker sizeof(stab.szopts));
172*de1e4e89SAndroid Build Coastguard Worker if (stab.data)
173*de1e4e89SAndroid Build Coastguard Worker addattr_l(&req.n, sizeof(req), TCA_STAB_DATA, stab.data,
174*de1e4e89SAndroid Build Coastguard Worker stab.szopts.tsize * sizeof(__u16));
175*de1e4e89SAndroid Build Coastguard Worker tail->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)tail;
176*de1e4e89SAndroid Build Coastguard Worker if (stab.data)
177*de1e4e89SAndroid Build Coastguard Worker free(stab.data);
178*de1e4e89SAndroid Build Coastguard Worker }
179*de1e4e89SAndroid Build Coastguard Worker
180*de1e4e89SAndroid Build Coastguard Worker if (d[0]) {
181*de1e4e89SAndroid Build Coastguard Worker int idx;
182*de1e4e89SAndroid Build Coastguard Worker
183*de1e4e89SAndroid Build Coastguard Worker ll_init_map(&rth);
184*de1e4e89SAndroid Build Coastguard Worker
185*de1e4e89SAndroid Build Coastguard Worker idx = ll_name_to_index(d);
186*de1e4e89SAndroid Build Coastguard Worker if (idx == 0) {
187*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Cannot find device \"%s\"\n", d);
188*de1e4e89SAndroid Build Coastguard Worker return 1;
189*de1e4e89SAndroid Build Coastguard Worker }
190*de1e4e89SAndroid Build Coastguard Worker req.t.tcm_ifindex = idx;
191*de1e4e89SAndroid Build Coastguard Worker }
192*de1e4e89SAndroid Build Coastguard Worker
193*de1e4e89SAndroid Build Coastguard Worker if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
194*de1e4e89SAndroid Build Coastguard Worker return 2;
195*de1e4e89SAndroid Build Coastguard Worker
196*de1e4e89SAndroid Build Coastguard Worker return 0;
197*de1e4e89SAndroid Build Coastguard Worker }
198*de1e4e89SAndroid Build Coastguard Worker
199*de1e4e89SAndroid Build Coastguard Worker static int filter_ifindex;
200*de1e4e89SAndroid Build Coastguard Worker
print_qdisc(const struct sockaddr_nl * who,struct nlmsghdr * n,void * arg)201*de1e4e89SAndroid Build Coastguard Worker int print_qdisc(const struct sockaddr_nl *who,
202*de1e4e89SAndroid Build Coastguard Worker struct nlmsghdr *n, void *arg)
203*de1e4e89SAndroid Build Coastguard Worker {
204*de1e4e89SAndroid Build Coastguard Worker FILE *fp = (FILE *)arg;
205*de1e4e89SAndroid Build Coastguard Worker struct tcmsg *t = NLMSG_DATA(n);
206*de1e4e89SAndroid Build Coastguard Worker int len = n->nlmsg_len;
207*de1e4e89SAndroid Build Coastguard Worker struct rtattr *tb[TCA_MAX+1];
208*de1e4e89SAndroid Build Coastguard Worker struct qdisc_util *q;
209*de1e4e89SAndroid Build Coastguard Worker char abuf[256];
210*de1e4e89SAndroid Build Coastguard Worker
211*de1e4e89SAndroid Build Coastguard Worker if (n->nlmsg_type != RTM_NEWQDISC && n->nlmsg_type != RTM_DELQDISC) {
212*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Not a qdisc\n");
213*de1e4e89SAndroid Build Coastguard Worker return 0;
214*de1e4e89SAndroid Build Coastguard Worker }
215*de1e4e89SAndroid Build Coastguard Worker len -= NLMSG_LENGTH(sizeof(*t));
216*de1e4e89SAndroid Build Coastguard Worker if (len < 0) {
217*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Wrong len %d\n", len);
218*de1e4e89SAndroid Build Coastguard Worker return -1;
219*de1e4e89SAndroid Build Coastguard Worker }
220*de1e4e89SAndroid Build Coastguard Worker
221*de1e4e89SAndroid Build Coastguard Worker if (filter_ifindex && filter_ifindex != t->tcm_ifindex)
222*de1e4e89SAndroid Build Coastguard Worker return 0;
223*de1e4e89SAndroid Build Coastguard Worker
224*de1e4e89SAndroid Build Coastguard Worker parse_rtattr(tb, TCA_MAX, TCA_RTA(t), len);
225*de1e4e89SAndroid Build Coastguard Worker
226*de1e4e89SAndroid Build Coastguard Worker if (tb[TCA_KIND] == NULL) {
227*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "print_qdisc: NULL kind\n");
228*de1e4e89SAndroid Build Coastguard Worker return -1;
229*de1e4e89SAndroid Build Coastguard Worker }
230*de1e4e89SAndroid Build Coastguard Worker
231*de1e4e89SAndroid Build Coastguard Worker if (n->nlmsg_type == RTM_DELQDISC)
232*de1e4e89SAndroid Build Coastguard Worker fprintf(fp, "deleted ");
233*de1e4e89SAndroid Build Coastguard Worker
234*de1e4e89SAndroid Build Coastguard Worker if (n->nlmsg_type == RTM_NEWQDISC &&
235*de1e4e89SAndroid Build Coastguard Worker (n->nlmsg_flags & NLM_F_CREATE) &&
236*de1e4e89SAndroid Build Coastguard Worker (n->nlmsg_flags & NLM_F_REPLACE))
237*de1e4e89SAndroid Build Coastguard Worker fprintf(fp, "replaced ");
238*de1e4e89SAndroid Build Coastguard Worker
239*de1e4e89SAndroid Build Coastguard Worker if (n->nlmsg_type == RTM_NEWQDISC &&
240*de1e4e89SAndroid Build Coastguard Worker (n->nlmsg_flags & NLM_F_CREATE) &&
241*de1e4e89SAndroid Build Coastguard Worker (n->nlmsg_flags & NLM_F_EXCL))
242*de1e4e89SAndroid Build Coastguard Worker fprintf(fp, "added ");
243*de1e4e89SAndroid Build Coastguard Worker
244*de1e4e89SAndroid Build Coastguard Worker if (show_raw)
245*de1e4e89SAndroid Build Coastguard Worker fprintf(fp, "qdisc %s %x:[%08x] ",
246*de1e4e89SAndroid Build Coastguard Worker rta_getattr_str(tb[TCA_KIND]),
247*de1e4e89SAndroid Build Coastguard Worker t->tcm_handle >> 16, t->tcm_handle);
248*de1e4e89SAndroid Build Coastguard Worker else
249*de1e4e89SAndroid Build Coastguard Worker fprintf(fp, "qdisc %s %x: ", rta_getattr_str(tb[TCA_KIND]),
250*de1e4e89SAndroid Build Coastguard Worker t->tcm_handle >> 16);
251*de1e4e89SAndroid Build Coastguard Worker
252*de1e4e89SAndroid Build Coastguard Worker if (filter_ifindex == 0)
253*de1e4e89SAndroid Build Coastguard Worker fprintf(fp, "dev %s ", ll_index_to_name(t->tcm_ifindex));
254*de1e4e89SAndroid Build Coastguard Worker
255*de1e4e89SAndroid Build Coastguard Worker if (t->tcm_parent == TC_H_ROOT)
256*de1e4e89SAndroid Build Coastguard Worker fprintf(fp, "root ");
257*de1e4e89SAndroid Build Coastguard Worker else if (t->tcm_parent) {
258*de1e4e89SAndroid Build Coastguard Worker print_tc_classid(abuf, sizeof(abuf), t->tcm_parent);
259*de1e4e89SAndroid Build Coastguard Worker fprintf(fp, "parent %s ", abuf);
260*de1e4e89SAndroid Build Coastguard Worker }
261*de1e4e89SAndroid Build Coastguard Worker
262*de1e4e89SAndroid Build Coastguard Worker if (t->tcm_info != 1)
263*de1e4e89SAndroid Build Coastguard Worker fprintf(fp, "refcnt %d ", t->tcm_info);
264*de1e4e89SAndroid Build Coastguard Worker
265*de1e4e89SAndroid Build Coastguard Worker /* pfifo_fast is generic enough to warrant the hardcoding --JHS */
266*de1e4e89SAndroid Build Coastguard Worker if (strcmp("pfifo_fast", RTA_DATA(tb[TCA_KIND])) == 0)
267*de1e4e89SAndroid Build Coastguard Worker q = get_qdisc_kind("prio");
268*de1e4e89SAndroid Build Coastguard Worker else
269*de1e4e89SAndroid Build Coastguard Worker q = get_qdisc_kind(RTA_DATA(tb[TCA_KIND]));
270*de1e4e89SAndroid Build Coastguard Worker
271*de1e4e89SAndroid Build Coastguard Worker if (tb[TCA_OPTIONS]) {
272*de1e4e89SAndroid Build Coastguard Worker if (q)
273*de1e4e89SAndroid Build Coastguard Worker q->print_qopt(q, fp, tb[TCA_OPTIONS]);
274*de1e4e89SAndroid Build Coastguard Worker else
275*de1e4e89SAndroid Build Coastguard Worker fprintf(fp, "[cannot parse qdisc parameters]");
276*de1e4e89SAndroid Build Coastguard Worker }
277*de1e4e89SAndroid Build Coastguard Worker fprintf(fp, "\n");
278*de1e4e89SAndroid Build Coastguard Worker
279*de1e4e89SAndroid Build Coastguard Worker if (show_details && tb[TCA_STAB]) {
280*de1e4e89SAndroid Build Coastguard Worker print_size_table(fp, " ", tb[TCA_STAB]);
281*de1e4e89SAndroid Build Coastguard Worker fprintf(fp, "\n");
282*de1e4e89SAndroid Build Coastguard Worker }
283*de1e4e89SAndroid Build Coastguard Worker
284*de1e4e89SAndroid Build Coastguard Worker if (show_stats) {
285*de1e4e89SAndroid Build Coastguard Worker struct rtattr *xstats = NULL;
286*de1e4e89SAndroid Build Coastguard Worker
287*de1e4e89SAndroid Build Coastguard Worker if (tb[TCA_STATS] || tb[TCA_STATS2] || tb[TCA_XSTATS]) {
288*de1e4e89SAndroid Build Coastguard Worker print_tcstats_attr(fp, tb, " ", &xstats);
289*de1e4e89SAndroid Build Coastguard Worker fprintf(fp, "\n");
290*de1e4e89SAndroid Build Coastguard Worker }
291*de1e4e89SAndroid Build Coastguard Worker
292*de1e4e89SAndroid Build Coastguard Worker if (q && xstats && q->print_xstats) {
293*de1e4e89SAndroid Build Coastguard Worker q->print_xstats(q, fp, xstats);
294*de1e4e89SAndroid Build Coastguard Worker fprintf(fp, "\n");
295*de1e4e89SAndroid Build Coastguard Worker }
296*de1e4e89SAndroid Build Coastguard Worker }
297*de1e4e89SAndroid Build Coastguard Worker fflush(fp);
298*de1e4e89SAndroid Build Coastguard Worker return 0;
299*de1e4e89SAndroid Build Coastguard Worker }
300*de1e4e89SAndroid Build Coastguard Worker
tc_qdisc_list(int argc,char ** argv)301*de1e4e89SAndroid Build Coastguard Worker static int tc_qdisc_list(int argc, char **argv)
302*de1e4e89SAndroid Build Coastguard Worker {
303*de1e4e89SAndroid Build Coastguard Worker struct tcmsg t = { .tcm_family = AF_UNSPEC };
304*de1e4e89SAndroid Build Coastguard Worker char d[16] = {};
305*de1e4e89SAndroid Build Coastguard Worker bool dump_invisible = false;
306*de1e4e89SAndroid Build Coastguard Worker
307*de1e4e89SAndroid Build Coastguard Worker while (argc > 0) {
308*de1e4e89SAndroid Build Coastguard Worker if (strcmp(*argv, "dev") == 0) {
309*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
310*de1e4e89SAndroid Build Coastguard Worker strncpy(d, *argv, sizeof(d)-1);
311*de1e4e89SAndroid Build Coastguard Worker } else if (strcmp(*argv, "ingress") == 0 ||
312*de1e4e89SAndroid Build Coastguard Worker strcmp(*argv, "clsact") == 0) {
313*de1e4e89SAndroid Build Coastguard Worker if (t.tcm_parent) {
314*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Duplicate parent ID\n");
315*de1e4e89SAndroid Build Coastguard Worker usage();
316*de1e4e89SAndroid Build Coastguard Worker }
317*de1e4e89SAndroid Build Coastguard Worker t.tcm_parent = TC_H_INGRESS;
318*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "help") == 0) {
319*de1e4e89SAndroid Build Coastguard Worker usage();
320*de1e4e89SAndroid Build Coastguard Worker } else if (strcmp(*argv, "invisible") == 0) {
321*de1e4e89SAndroid Build Coastguard Worker dump_invisible = true;
322*de1e4e89SAndroid Build Coastguard Worker } else {
323*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "What is \"%s\"? Try \"tc qdisc help\".\n", *argv);
324*de1e4e89SAndroid Build Coastguard Worker return -1;
325*de1e4e89SAndroid Build Coastguard Worker }
326*de1e4e89SAndroid Build Coastguard Worker
327*de1e4e89SAndroid Build Coastguard Worker argc--; argv++;
328*de1e4e89SAndroid Build Coastguard Worker }
329*de1e4e89SAndroid Build Coastguard Worker
330*de1e4e89SAndroid Build Coastguard Worker ll_init_map(&rth);
331*de1e4e89SAndroid Build Coastguard Worker
332*de1e4e89SAndroid Build Coastguard Worker if (d[0]) {
333*de1e4e89SAndroid Build Coastguard Worker t.tcm_ifindex = ll_name_to_index(d);
334*de1e4e89SAndroid Build Coastguard Worker if (t.tcm_ifindex == 0) {
335*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Cannot find device \"%s\"\n", d);
336*de1e4e89SAndroid Build Coastguard Worker return 1;
337*de1e4e89SAndroid Build Coastguard Worker }
338*de1e4e89SAndroid Build Coastguard Worker filter_ifindex = t.tcm_ifindex;
339*de1e4e89SAndroid Build Coastguard Worker }
340*de1e4e89SAndroid Build Coastguard Worker
341*de1e4e89SAndroid Build Coastguard Worker if (dump_invisible) {
342*de1e4e89SAndroid Build Coastguard Worker struct {
343*de1e4e89SAndroid Build Coastguard Worker struct nlmsghdr n;
344*de1e4e89SAndroid Build Coastguard Worker struct tcmsg t;
345*de1e4e89SAndroid Build Coastguard Worker char buf[256];
346*de1e4e89SAndroid Build Coastguard Worker } req = {
347*de1e4e89SAndroid Build Coastguard Worker .n.nlmsg_type = RTM_GETQDISC,
348*de1e4e89SAndroid Build Coastguard Worker .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
349*de1e4e89SAndroid Build Coastguard Worker };
350*de1e4e89SAndroid Build Coastguard Worker
351*de1e4e89SAndroid Build Coastguard Worker req.t.tcm_family = AF_UNSPEC;
352*de1e4e89SAndroid Build Coastguard Worker
353*de1e4e89SAndroid Build Coastguard Worker addattr(&req.n, 256, TCA_DUMP_INVISIBLE);
354*de1e4e89SAndroid Build Coastguard Worker if (rtnl_dump_request_n(&rth, &req.n) < 0) {
355*de1e4e89SAndroid Build Coastguard Worker perror("Cannot send dump request");
356*de1e4e89SAndroid Build Coastguard Worker return 1;
357*de1e4e89SAndroid Build Coastguard Worker }
358*de1e4e89SAndroid Build Coastguard Worker
359*de1e4e89SAndroid Build Coastguard Worker } else if (rtnl_dump_request(&rth, RTM_GETQDISC, &t, sizeof(t)) < 0) {
360*de1e4e89SAndroid Build Coastguard Worker perror("Cannot send dump request");
361*de1e4e89SAndroid Build Coastguard Worker return 1;
362*de1e4e89SAndroid Build Coastguard Worker }
363*de1e4e89SAndroid Build Coastguard Worker
364*de1e4e89SAndroid Build Coastguard Worker if (rtnl_dump_filter(&rth, print_qdisc, stdout) < 0) {
365*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Dump terminated\n");
366*de1e4e89SAndroid Build Coastguard Worker return 1;
367*de1e4e89SAndroid Build Coastguard Worker }
368*de1e4e89SAndroid Build Coastguard Worker
369*de1e4e89SAndroid Build Coastguard Worker return 0;
370*de1e4e89SAndroid Build Coastguard Worker }
371*de1e4e89SAndroid Build Coastguard Worker
do_qdisc(int argc,char ** argv)372*de1e4e89SAndroid Build Coastguard Worker int do_qdisc(int argc, char **argv)
373*de1e4e89SAndroid Build Coastguard Worker {
374*de1e4e89SAndroid Build Coastguard Worker if (argc < 1)
375*de1e4e89SAndroid Build Coastguard Worker return tc_qdisc_list(0, NULL);
376*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "add") == 0)
377*de1e4e89SAndroid Build Coastguard Worker return tc_qdisc_modify(RTM_NEWQDISC, NLM_F_EXCL|NLM_F_CREATE, argc-1, argv+1);
378*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "change") == 0)
379*de1e4e89SAndroid Build Coastguard Worker return tc_qdisc_modify(RTM_NEWQDISC, 0, argc-1, argv+1);
380*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "replace") == 0)
381*de1e4e89SAndroid Build Coastguard Worker return tc_qdisc_modify(RTM_NEWQDISC, NLM_F_CREATE|NLM_F_REPLACE, argc-1, argv+1);
382*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "link") == 0)
383*de1e4e89SAndroid Build Coastguard Worker return tc_qdisc_modify(RTM_NEWQDISC, NLM_F_REPLACE, argc-1, argv+1);
384*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "delete") == 0)
385*de1e4e89SAndroid Build Coastguard Worker return tc_qdisc_modify(RTM_DELQDISC, 0, argc-1, argv+1);
386*de1e4e89SAndroid Build Coastguard Worker #if 0
387*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "get") == 0)
388*de1e4e89SAndroid Build Coastguard Worker return tc_qdisc_get(RTM_GETQDISC, 0, argc-1, argv+1);
389*de1e4e89SAndroid Build Coastguard Worker #endif
390*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
391*de1e4e89SAndroid Build Coastguard Worker || matches(*argv, "lst") == 0)
392*de1e4e89SAndroid Build Coastguard Worker return tc_qdisc_list(argc-1, argv+1);
393*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "help") == 0) {
394*de1e4e89SAndroid Build Coastguard Worker usage();
395*de1e4e89SAndroid Build Coastguard Worker return 0;
396*de1e4e89SAndroid Build Coastguard Worker }
397*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Command \"%s\" is unknown, try \"tc qdisc help\".\n", *argv);
398*de1e4e89SAndroid Build Coastguard Worker return -1;
399*de1e4e89SAndroid Build Coastguard Worker }
400