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