11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * net/sched/sch_api.c	Packet scheduler API.
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		This program is free software; you can redistribute it and/or
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		modify it under the terms of the GNU General Public License
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		as published by the Free Software Foundation; either version
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		2 of the License, or (at your option) any later version.
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Fixes:
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Rani Assaf <rani@magic.metawire.com> :980802: JIFFIES and CPU clock sources are repaired.
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Eduardo J. Blanco <ejbs@netlabs.com.uy> :990222: kmod support
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Jamal Hadi Salim <hadi@nortelnetworks.com>: 990601: ingress support
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/proc_fs.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/seq_file.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kmod.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/list.h>
294179477f637caa730626bd597fdf28c5bad73565Patrick McHardy#include <linux/hrtimer.h>
3025bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawski#include <linux/lockdep.h>
315a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33457c4cbc5a3dde259d2a1f15d5f9785290397267Eric W. Biederman#include <net/net_namespace.h>
34b854272b3c732316676e9128f7b9e6f1e1ff88b0Denis V. Lunev#include <net/sock.h>
35dc5fc579b90ed0a9a4e55b0218cdbaf0a8cf2e67Arnaldo Carvalho de Melo#include <net/netlink.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/pkt_sched.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
387316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic int qdisc_notify(struct net *net, struct sk_buff *oskb,
397316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff			struct nlmsghdr *n, u32 clid,
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct Qdisc *old, struct Qdisc *new);
417316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic int tclass_notify(struct net *net, struct sk_buff *oskb,
427316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff			 struct nlmsghdr *n, struct Qdisc *q,
437316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff			 unsigned long cl, int event);
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Short review.
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   -------------
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   This file consists of two interrelated parts:
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   1. queueing disciplines manager frontend.
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   2. traffic classes manager frontend.
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Generally, queueing discipline ("qdisc") is a black box,
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   which is able to enqueue packets and to dequeue them (when
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   device is ready to send something) in order and at times
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   determined by algorithm hidden in it.
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   qdisc's are divided to two categories:
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   - "queues", which have no internal structure visible from outside.
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   - "schedulers", which split all the packets to "traffic classes",
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     using "packet classifiers" (look at cls_api.c)
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   In turn, classes may have child qdiscs (as rule, queues)
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   attached to them etc. etc. etc.
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   The goal of the routines in this file is to translate
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   information supplied by user in the form of handles
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   to more intelligible for kernel form, to make some sanity
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   checks and part of work, which is common to all qdiscs
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   and to provide rtnetlink notifications.
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   All real intelligent work is done inside qdisc modules.
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Every discipline has two major routines: enqueue and dequeue.
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   ---dequeue
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   dequeue usually returns a skb to send. It is allowed to return NULL,
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   but it does not mean that queue is empty, it just means that
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   discipline does not want to send anything this time.
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Queue is really empty if q->q.qlen == 0.
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   For complicated disciplines with multiple queues q->q is not
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   real packet queue, but however q->q.qlen must be valid.
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   ---enqueue
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   enqueue returns 0, if packet was enqueued successfully.
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   If packet (this one or another one) was dropped, it returns
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   not zero error code.
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   NET_XMIT_DROP 	- this packet dropped
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     Expected action: do not backoff, but wait until queue will clear.
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   NET_XMIT_CN	 	- probably this packet enqueued, but another one dropped.
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     Expected action: backoff or ignore
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   NET_XMIT_POLICED	- dropped by police.
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     Expected action: backoff or error to real-time apps.
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Auxiliary routines:
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10399c0db26797edb39cf83c8c5f8972067f5426b4eJarek Poplawski   ---peek
10499c0db26797edb39cf83c8c5f8972067f5426b4eJarek Poplawski
10599c0db26797edb39cf83c8c5f8972067f5426b4eJarek Poplawski   like dequeue but without removing a packet from the queue
10699c0db26797edb39cf83c8c5f8972067f5426b4eJarek Poplawski
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   ---reset
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   returns qdisc to initial state: purge all buffers, clear all
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   timers, counters (except for statistics) etc.
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   ---init
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   initializes newly created qdisc.
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   ---destroy
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   destroys resources allocated by init and during lifetime of qdisc.
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   ---change
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   changes qdisc parameters.
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Protects list of registered TC modules. It is pure SMP lock. */
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEFINE_RWLOCK(qdisc_mod_lock);
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/************************************************
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Queueing disciplines manipulation.	*
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ************************************************/
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The list of all installed queueing disciplines. */
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct Qdisc_ops *qdisc_base;
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Register/uregister queueing discipline */
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint register_qdisc(struct Qdisc_ops *qops)
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc_ops *q, **qp;
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc = -EEXIST;
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_lock(&qdisc_mod_lock);
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (qp = &qdisc_base; (q = *qp) != NULL; qp = &q->next)
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!strcmp(qops->id, q->id))
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (qops->enqueue == NULL)
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qops->enqueue = noop_qdisc_ops.enqueue;
15299c0db26797edb39cf83c8c5f8972067f5426b4eJarek Poplawski	if (qops->peek == NULL) {
15368fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski		if (qops->dequeue == NULL)
15499c0db26797edb39cf83c8c5f8972067f5426b4eJarek Poplawski			qops->peek = noop_qdisc_ops.peek;
15568fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski		else
15668fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski			goto out_einval;
15799c0db26797edb39cf83c8c5f8972067f5426b4eJarek Poplawski	}
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (qops->dequeue == NULL)
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qops->dequeue = noop_qdisc_ops.dequeue;
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16168fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski	if (qops->cl_ops) {
16268fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski		const struct Qdisc_class_ops *cops = qops->cl_ops;
16368fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski
1643e9e5a5921f4b7dc098a01d01e5972bebb36491eJarek Poplawski		if (!(cops->get && cops->put && cops->walk && cops->leaf))
16568fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski			goto out_einval;
16668fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski
16768fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski		if (cops->tcf_chain && !(cops->bind_tcf && cops->unbind_tcf))
16868fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski			goto out_einval;
16968fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski	}
17068fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qops->next = NULL;
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*qp = qops;
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = 0;
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock(&qdisc_mod_lock);
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
17768fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski
17868fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawskiout_einval:
17968fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski	rc = -EINVAL;
18068fd26b59856b466edd14d8a90d01255983cd3eeJarek Poplawski	goto out;
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18262e3ba1b558e5f393ef746880613fb8222e64d03Patrick McHardyEXPORT_SYMBOL(register_qdisc);
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint unregister_qdisc(struct Qdisc_ops *qops)
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc_ops *q, **qp;
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = -ENOENT;
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_lock(&qdisc_mod_lock);
190cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	for (qp = &qdisc_base; (q = *qp) != NULL; qp = &q->next)
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (q == qops)
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (q) {
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*qp = q->next;
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		q->next = NULL;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = 0;
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_unlock(&qdisc_mod_lock);
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20162e3ba1b558e5f393ef746880613fb8222e64d03Patrick McHardyEXPORT_SYMBOL(unregister_qdisc);
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* We know handle. Find qdisc among all qdisc's attached to device
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   (root qdisc, all its children, children of children etc.)
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2076113b748fb9935399ec2bbca3a3dc82008f6167fHannes Ederstatic struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle)
2088123b421e8ed944671d7241323ed3198cccb4041David S. Miller{
2098123b421e8ed944671d7241323ed3198cccb4041David S. Miller	struct Qdisc *q;
2108123b421e8ed944671d7241323ed3198cccb4041David S. Miller
2118123b421e8ed944671d7241323ed3198cccb4041David S. Miller	if (!(root->flags & TCQ_F_BUILTIN) &&
2128123b421e8ed944671d7241323ed3198cccb4041David S. Miller	    root->handle == handle)
2138123b421e8ed944671d7241323ed3198cccb4041David S. Miller		return root;
2148123b421e8ed944671d7241323ed3198cccb4041David S. Miller
2158123b421e8ed944671d7241323ed3198cccb4041David S. Miller	list_for_each_entry(q, &root->list, list) {
2168123b421e8ed944671d7241323ed3198cccb4041David S. Miller		if (q->handle == handle)
2178123b421e8ed944671d7241323ed3198cccb4041David S. Miller			return q;
2188123b421e8ed944671d7241323ed3198cccb4041David S. Miller	}
2198123b421e8ed944671d7241323ed3198cccb4041David S. Miller	return NULL;
2208123b421e8ed944671d7241323ed3198cccb4041David S. Miller}
2218123b421e8ed944671d7241323ed3198cccb4041David S. Miller
222f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawskistatic void qdisc_list_add(struct Qdisc *q)
223f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski{
224f6486d40b33d1ac2c44c7c55db7edf022d9f4329Jarek Poplawski	if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS))
225af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy		list_add_tail(&q->list, &qdisc_dev(q)->qdisc->list);
226f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski}
227f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski
228f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawskivoid qdisc_list_del(struct Qdisc *q)
229f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski{
230f6486d40b33d1ac2c44c7c55db7edf022d9f4329Jarek Poplawski	if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS))
231f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski		list_del(&q->list);
232f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski}
233f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek PoplawskiEXPORT_SYMBOL(qdisc_list_del);
234f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski
235ead81cc5fc6d996db6afb20f211241612610a07aDavid S. Millerstruct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle)
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
237f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski	struct Qdisc *q;
238f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski
239af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy	q = qdisc_match_from_root(dev->qdisc, handle);
240af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy	if (q)
241af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy		goto out;
242f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski
24324824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet	if (dev_ingress_queue(dev))
24424824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet		q = qdisc_match_from_root(
24524824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet			dev_ingress_queue(dev)->qdisc_sleeping,
24624824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet			handle);
247f6486d40b33d1ac2c44c7c55db7edf022d9f4329Jarek Poplawskiout:
248f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski	return q;
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct Qdisc *qdisc_leaf(struct Qdisc *p, u32 classid)
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long cl;
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *leaf;
25520fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet	const struct Qdisc_class_ops *cops = p->ops->cl_ops;
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cops == NULL)
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cl = cops->get(p, classid);
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cl == 0)
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	leaf = cops->leaf(p, cl);
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cops->put(p, cl);
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return leaf;
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Find queueing discipline by name */
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2701e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardystatic struct Qdisc_ops *qdisc_lookup_ops(struct nlattr *kind)
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc_ops *q = NULL;
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (kind) {
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		read_lock(&qdisc_mod_lock);
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (q = qdisc_base; q; q = q->next) {
2771e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy			if (nla_strcmp(kind, q->id) == 0) {
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!try_module_get(q->owner))
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					q = NULL;
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		read_unlock(&qdisc_mod_lock);
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return q;
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct qdisc_rate_table *qdisc_rtab_list;
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2901e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardystruct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, struct nlattr *tab)
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct qdisc_rate_table *rtab;
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29440edeff6e1c6f9a6f16536ae3375e3af9d648449Eric Dumazet	if (tab == NULL || r->rate == 0 || r->cell_log == 0 ||
29540edeff6e1c6f9a6f16536ae3375e3af9d648449Eric Dumazet	    nla_len(tab) != TC_RTAB_SIZE)
29640edeff6e1c6f9a6f16536ae3375e3af9d648449Eric Dumazet		return NULL;
29740edeff6e1c6f9a6f16536ae3375e3af9d648449Eric Dumazet
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (rtab = qdisc_rtab_list; rtab; rtab = rtab->next) {
29940edeff6e1c6f9a6f16536ae3375e3af9d648449Eric Dumazet		if (!memcmp(&rtab->rate, r, sizeof(struct tc_ratespec)) &&
30040edeff6e1c6f9a6f16536ae3375e3af9d648449Eric Dumazet		    !memcmp(&rtab->data, nla_data(tab), 1024)) {
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rtab->refcnt++;
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return rtab;
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rtab = kmalloc(sizeof(*rtab), GFP_KERNEL);
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rtab) {
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rtab->rate = *r;
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rtab->refcnt = 1;
3101e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		memcpy(rtab->data, nla_data(tab), 1024);
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rtab->next = qdisc_rtab_list;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qdisc_rtab_list = rtab;
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rtab;
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
31662e3ba1b558e5f393ef746880613fb8222e64d03Patrick McHardyEXPORT_SYMBOL(qdisc_get_rtab);
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid qdisc_put_rtab(struct qdisc_rate_table *tab)
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct qdisc_rate_table *rtab, **rtabp;
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!tab || --tab->refcnt)
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
325cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	for (rtabp = &qdisc_rtab_list;
326cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	     (rtab = *rtabp) != NULL;
327cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	     rtabp = &rtab->next) {
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (rtab == tab) {
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*rtabp = rtab->next;
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(rtab);
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
33562e3ba1b558e5f393ef746880613fb8222e64d03Patrick McHardyEXPORT_SYMBOL(qdisc_put_rtab);
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
337175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic LIST_HEAD(qdisc_stab_list);
338175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic DEFINE_SPINLOCK(qdisc_stab_lock);
339175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
340175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic const struct nla_policy stab_policy[TCA_STAB_MAX + 1] = {
341175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	[TCA_STAB_BASE]	= { .len = sizeof(struct tc_sizespec) },
342175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	[TCA_STAB_DATA] = { .type = NLA_BINARY },
343175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna};
344175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
345175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic struct qdisc_size_table *qdisc_get_stab(struct nlattr *opt)
346175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna{
347175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	struct nlattr *tb[TCA_STAB_MAX + 1];
348175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	struct qdisc_size_table *stab;
349175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	struct tc_sizespec *s;
350175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	unsigned int tsize = 0;
351175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	u16 *tab = NULL;
352175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	int err;
353175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
354175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	err = nla_parse_nested(tb, TCA_STAB_MAX, opt, stab_policy);
355175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (err < 0)
356175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		return ERR_PTR(err);
357175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (!tb[TCA_STAB_BASE])
358175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		return ERR_PTR(-EINVAL);
359175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
360175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	s = nla_data(tb[TCA_STAB_BASE]);
361175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
362175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (s->tsize > 0) {
363175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		if (!tb[TCA_STAB_DATA])
364175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna			return ERR_PTR(-EINVAL);
365175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		tab = nla_data(tb[TCA_STAB_DATA]);
366175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		tsize = nla_len(tb[TCA_STAB_DATA]) / sizeof(u16);
367175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	}
368175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
36900093fab980d0a8950a64bdf9e346d0497b9a7e4Dan Carpenter	if (tsize != s->tsize || (!tab && tsize > 0))
370175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		return ERR_PTR(-EINVAL);
371175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
372f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller	spin_lock(&qdisc_stab_lock);
373175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
374175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	list_for_each_entry(stab, &qdisc_stab_list, list) {
375175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		if (memcmp(&stab->szopts, s, sizeof(*s)))
376175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna			continue;
377175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		if (tsize > 0 && memcmp(stab->data, tab, tsize * sizeof(u16)))
378175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna			continue;
379175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		stab->refcnt++;
380f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller		spin_unlock(&qdisc_stab_lock);
381175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		return stab;
382175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	}
383175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
384f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller	spin_unlock(&qdisc_stab_lock);
385175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
386175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	stab = kmalloc(sizeof(*stab) + tsize * sizeof(u16), GFP_KERNEL);
387175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (!stab)
388175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		return ERR_PTR(-ENOMEM);
389175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
390175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	stab->refcnt = 1;
391175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	stab->szopts = *s;
392175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (tsize > 0)
393175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		memcpy(stab->data, tab, tsize * sizeof(u16));
394175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
395f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller	spin_lock(&qdisc_stab_lock);
396175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	list_add_tail(&stab->list, &qdisc_stab_list);
397f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller	spin_unlock(&qdisc_stab_lock);
398175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
399175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	return stab;
400175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna}
401175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
402a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazetstatic void stab_kfree_rcu(struct rcu_head *head)
403a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet{
404a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet	kfree(container_of(head, struct qdisc_size_table, rcu));
405a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet}
406a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet
407175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnavoid qdisc_put_stab(struct qdisc_size_table *tab)
408175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna{
409175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (!tab)
410175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		return;
411175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
412f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller	spin_lock(&qdisc_stab_lock);
413175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
414175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (--tab->refcnt == 0) {
415175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		list_del(&tab->list);
416a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet		call_rcu_bh(&tab->rcu, stab_kfree_rcu);
417175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	}
418175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
419f3b9605d744df537dee10fd06630f35a62b343ecDavid S. Miller	spin_unlock(&qdisc_stab_lock);
420175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna}
421175f9c1bba9b825d22b142d183c9e175488b260cJussi KivilinnaEXPORT_SYMBOL(qdisc_put_stab);
422175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
423175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnastatic int qdisc_dump_stab(struct sk_buff *skb, struct qdisc_size_table *stab)
424175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna{
425175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	struct nlattr *nest;
426175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
427175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	nest = nla_nest_start(skb, TCA_STAB);
4283aa4614da741f10b09559a5675c79e2eff5cccd8Patrick McHardy	if (nest == NULL)
4293aa4614da741f10b09559a5675c79e2eff5cccd8Patrick McHardy		goto nla_put_failure;
4301b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller	if (nla_put(skb, TCA_STAB_BASE, sizeof(stab->szopts), &stab->szopts))
4311b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller		goto nla_put_failure;
432175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	nla_nest_end(skb, nest);
433175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
434175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	return skb->len;
435175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
436175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnanla_put_failure:
437175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	return -1;
438175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna}
439175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
440a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazetvoid __qdisc_calculate_pkt_len(struct sk_buff *skb, const struct qdisc_size_table *stab)
441175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna{
442175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	int pkt_len, slot;
443175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
444175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	pkt_len = skb->len + stab->szopts.overhead;
445175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (unlikely(!stab->szopts.tsize))
446175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		goto out;
447175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
448175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	slot = pkt_len + stab->szopts.cell_align;
449175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (unlikely(slot < 0))
450175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		slot = 0;
451175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
452175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	slot >>= stab->szopts.cell_log;
453175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (likely(slot < stab->szopts.tsize))
454175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		pkt_len = stab->data[slot];
455175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	else
456175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		pkt_len = stab->data[stab->szopts.tsize - 1] *
457175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna				(slot / stab->szopts.tsize) +
458175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna				stab->data[slot % stab->szopts.tsize];
459175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
460175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	pkt_len <<= stab->szopts.size_log;
461175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinnaout:
462175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (unlikely(pkt_len < 1))
463175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		pkt_len = 1;
464175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	qdisc_skb_cb(skb)->pkt_len = pkt_len;
465175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna}
466a2da570d62fcb9e8816f6920e1ec02c706b289faEric DumazetEXPORT_SYMBOL(__qdisc_calculate_pkt_len);
467175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
468b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawskivoid qdisc_warn_nonwc(char *txt, struct Qdisc *qdisc)
469b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawski{
470b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawski	if (!(qdisc->flags & TCQ_F_WARN_NONWC)) {
471cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet		pr_warn("%s: %s qdisc %X: is non-work-conserving?\n",
472cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet			txt, qdisc->ops->id, qdisc->handle >> 16);
473b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawski		qdisc->flags |= TCQ_F_WARN_NONWC;
474b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawski	}
475b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawski}
476b00355db3f88d96810a60011a30cfb2c3469409dJarek PoplawskiEXPORT_SYMBOL(qdisc_warn_nonwc);
477b00355db3f88d96810a60011a30cfb2c3469409dJarek Poplawski
4784179477f637caa730626bd597fdf28c5bad73565Patrick McHardystatic enum hrtimer_restart qdisc_watchdog(struct hrtimer *timer)
4794179477f637caa730626bd597fdf28c5bad73565Patrick McHardy{
4804179477f637caa730626bd597fdf28c5bad73565Patrick McHardy	struct qdisc_watchdog *wd = container_of(timer, struct qdisc_watchdog,
4812fbd3da3877ad8d923b055e5996f80b4d4a6daf4David S. Miller						 timer);
4824179477f637caa730626bd597fdf28c5bad73565Patrick McHardy
483fd245a4adb5288eac37250875f237c40a20a1944Eric Dumazet	qdisc_unthrottled(wd->qdisc);
4848608db031b4d2932d645709e2cfe8fbcd91a7305David S. Miller	__netif_schedule(qdisc_root(wd->qdisc));
4851936502d00ae6c2aa3931c42f6cf54afaba094f2Stephen Hemminger
4864179477f637caa730626bd597fdf28c5bad73565Patrick McHardy	return HRTIMER_NORESTART;
4874179477f637caa730626bd597fdf28c5bad73565Patrick McHardy}
4884179477f637caa730626bd597fdf28c5bad73565Patrick McHardy
4894179477f637caa730626bd597fdf28c5bad73565Patrick McHardyvoid qdisc_watchdog_init(struct qdisc_watchdog *wd, struct Qdisc *qdisc)
4904179477f637caa730626bd597fdf28c5bad73565Patrick McHardy{
4912fbd3da3877ad8d923b055e5996f80b4d4a6daf4David S. Miller	hrtimer_init(&wd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
4922fbd3da3877ad8d923b055e5996f80b4d4a6daf4David S. Miller	wd->timer.function = qdisc_watchdog;
4934179477f637caa730626bd597fdf28c5bad73565Patrick McHardy	wd->qdisc = qdisc;
4944179477f637caa730626bd597fdf28c5bad73565Patrick McHardy}
4954179477f637caa730626bd597fdf28c5bad73565Patrick McHardyEXPORT_SYMBOL(qdisc_watchdog_init);
4964179477f637caa730626bd597fdf28c5bad73565Patrick McHardy
49734c5d292ce05d2bf52e692c44292b0ababba2853Jiri Pirkovoid qdisc_watchdog_schedule_ns(struct qdisc_watchdog *wd, u64 expires)
4984179477f637caa730626bd597fdf28c5bad73565Patrick McHardy{
4992540e0511ea17e25831be543cdf9381e6209950dJarek Poplawski	if (test_bit(__QDISC_STATE_DEACTIVATED,
5002540e0511ea17e25831be543cdf9381e6209950dJarek Poplawski		     &qdisc_root_sleeping(wd->qdisc)->state))
5012540e0511ea17e25831be543cdf9381e6209950dJarek Poplawski		return;
5022540e0511ea17e25831be543cdf9381e6209950dJarek Poplawski
503fd245a4adb5288eac37250875f237c40a20a1944Eric Dumazet	qdisc_throttled(wd->qdisc);
50446baac38ef633b08168d27df7b02eb14578fb760Eric Dumazet
50546baac38ef633b08168d27df7b02eb14578fb760Eric Dumazet	hrtimer_start(&wd->timer,
50634c5d292ce05d2bf52e692c44292b0ababba2853Jiri Pirko		      ns_to_ktime(expires),
50746baac38ef633b08168d27df7b02eb14578fb760Eric Dumazet		      HRTIMER_MODE_ABS);
5084179477f637caa730626bd597fdf28c5bad73565Patrick McHardy}
50934c5d292ce05d2bf52e692c44292b0ababba2853Jiri PirkoEXPORT_SYMBOL(qdisc_watchdog_schedule_ns);
5104179477f637caa730626bd597fdf28c5bad73565Patrick McHardy
5114179477f637caa730626bd597fdf28c5bad73565Patrick McHardyvoid qdisc_watchdog_cancel(struct qdisc_watchdog *wd)
5124179477f637caa730626bd597fdf28c5bad73565Patrick McHardy{
5132fbd3da3877ad8d923b055e5996f80b4d4a6daf4David S. Miller	hrtimer_cancel(&wd->timer);
514fd245a4adb5288eac37250875f237c40a20a1944Eric Dumazet	qdisc_unthrottled(wd->qdisc);
5154179477f637caa730626bd597fdf28c5bad73565Patrick McHardy}
5164179477f637caa730626bd597fdf28c5bad73565Patrick McHardyEXPORT_SYMBOL(qdisc_watchdog_cancel);
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
518a94f779f9d82eb2d758a8715eaae5df98e8dcb21Adrian Bunkstatic struct hlist_head *qdisc_class_hash_alloc(unsigned int n)
5196fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{
5206fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	unsigned int size = n * sizeof(struct hlist_head), i;
5216fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	struct hlist_head *h;
5226fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5236fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	if (size <= PAGE_SIZE)
5246fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		h = kmalloc(size, GFP_KERNEL);
5256fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	else
5266fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		h = (struct hlist_head *)
5276fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy			__get_free_pages(GFP_KERNEL, get_order(size));
5286fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5296fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	if (h != NULL) {
5306fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		for (i = 0; i < n; i++)
5316fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy			INIT_HLIST_HEAD(&h[i]);
5326fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	}
5336fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	return h;
5346fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy}
5356fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5366fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardystatic void qdisc_class_hash_free(struct hlist_head *h, unsigned int n)
5376fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{
5386fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	unsigned int size = n * sizeof(struct hlist_head);
5396fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5406fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	if (size <= PAGE_SIZE)
5416fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		kfree(h);
5426fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	else
5436fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		free_pages((unsigned long)h, get_order(size));
5446fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy}
5456fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5466fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyvoid qdisc_class_hash_grow(struct Qdisc *sch, struct Qdisc_class_hash *clhash)
5476fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{
5486fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	struct Qdisc_class_common *cl;
549b67bfe0d42cac56c512dd5da4b1b347a23f4b70aSasha Levin	struct hlist_node *next;
5506fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	struct hlist_head *nhash, *ohash;
5516fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	unsigned int nsize, nmask, osize;
5526fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	unsigned int i, h;
5536fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5546fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	/* Rehash when load factor exceeds 0.75 */
5556fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	if (clhash->hashelems * 4 <= clhash->hashsize * 3)
5566fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		return;
5576fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	nsize = clhash->hashsize * 2;
5586fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	nmask = nsize - 1;
5596fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	nhash = qdisc_class_hash_alloc(nsize);
5606fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	if (nhash == NULL)
5616fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		return;
5626fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5636fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	ohash = clhash->hash;
5646fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	osize = clhash->hashsize;
5656fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5666fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	sch_tree_lock(sch);
5676fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	for (i = 0; i < osize; i++) {
568b67bfe0d42cac56c512dd5da4b1b347a23f4b70aSasha Levin		hlist_for_each_entry_safe(cl, next, &ohash[i], hnode) {
5696fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy			h = qdisc_class_hash(cl->classid, nmask);
5706fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy			hlist_add_head(&cl->hnode, &nhash[h]);
5716fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		}
5726fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	}
5736fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hash     = nhash;
5746fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hashsize = nsize;
5756fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hashmask = nmask;
5766fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	sch_tree_unlock(sch);
5776fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5786fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	qdisc_class_hash_free(ohash, osize);
5796fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy}
5806fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyEXPORT_SYMBOL(qdisc_class_hash_grow);
5816fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5826fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyint qdisc_class_hash_init(struct Qdisc_class_hash *clhash)
5836fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{
5846fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	unsigned int size = 4;
5856fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5866fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hash = qdisc_class_hash_alloc(size);
5876fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	if (clhash->hash == NULL)
5886fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy		return -ENOMEM;
5896fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hashsize  = size;
5906fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hashmask  = size - 1;
5916fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hashelems = 0;
5926fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	return 0;
5936fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy}
5946fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyEXPORT_SYMBOL(qdisc_class_hash_init);
5956fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
5966fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyvoid qdisc_class_hash_destroy(struct Qdisc_class_hash *clhash)
5976fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{
5986fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	qdisc_class_hash_free(clhash->hash, clhash->hashsize);
5996fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy}
6006fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyEXPORT_SYMBOL(qdisc_class_hash_destroy);
6016fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
6026fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyvoid qdisc_class_hash_insert(struct Qdisc_class_hash *clhash,
6036fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy			     struct Qdisc_class_common *cl)
6046fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{
6056fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	unsigned int h;
6066fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
6076fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	INIT_HLIST_NODE(&cl->hnode);
6086fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	h = qdisc_class_hash(cl->classid, clhash->hashmask);
6096fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	hlist_add_head(&cl->hnode, &clhash->hash[h]);
6106fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hashelems++;
6116fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy}
6126fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyEXPORT_SYMBOL(qdisc_class_hash_insert);
6136fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
6146fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyvoid qdisc_class_hash_remove(struct Qdisc_class_hash *clhash,
6156fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy			     struct Qdisc_class_common *cl)
6166fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy{
6176fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	hlist_del(&cl->hnode);
6186fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy	clhash->hashelems--;
6196fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy}
6206fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardyEXPORT_SYMBOL(qdisc_class_hash_remove);
6216fe1c7a5556807e9d7154a2d2fb938d8a9e47e5fPatrick McHardy
622fa0f5aa74316c636427ac92dad0bc5714c34ca17Eric Dumazet/* Allocate an unique handle from space managed by kernel
623fa0f5aa74316c636427ac92dad0bc5714c34ca17Eric Dumazet * Possible range is [8000-FFFF]:0000 (0x8000 values)
624fa0f5aa74316c636427ac92dad0bc5714c34ca17Eric Dumazet */
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u32 qdisc_alloc_handle(struct net_device *dev)
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
627fa0f5aa74316c636427ac92dad0bc5714c34ca17Eric Dumazet	int i = 0x8000;
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static u32 autohandle = TC_H_MAKE(0x80000000U, 0);
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		autohandle += TC_H_MAKE(0x10000U, 0);
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (autohandle == TC_H_MAKE(TC_H_ROOT, 0))
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			autohandle = TC_H_MAKE(0x80000000U, 0);
634fa0f5aa74316c636427ac92dad0bc5714c34ca17Eric Dumazet		if (!qdisc_lookup(dev, autohandle))
635fa0f5aa74316c636427ac92dad0bc5714c34ca17Eric Dumazet			return autohandle;
636fa0f5aa74316c636427ac92dad0bc5714c34ca17Eric Dumazet		cond_resched();
637fa0f5aa74316c636427ac92dad0bc5714c34ca17Eric Dumazet	} while	(--i > 0);
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
639fa0f5aa74316c636427ac92dad0bc5714c34ca17Eric Dumazet	return 0;
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
64243effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardyvoid qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n)
64343effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy{
64420fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet	const struct Qdisc_class_ops *cops;
64543effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy	unsigned long cl;
64643effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy	u32 parentid;
64743effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy
64843effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy	if (n == 0)
64943effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy		return;
65043effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy	while ((parentid = sch->parent)) {
651066a3b5b2346febf9a655b444567b7138e3bb939Jarek Poplawski		if (TC_H_MAJ(parentid) == TC_H_MAJ(TC_H_INGRESS))
652066a3b5b2346febf9a655b444567b7138e3bb939Jarek Poplawski			return;
653066a3b5b2346febf9a655b444567b7138e3bb939Jarek Poplawski
6545ce2d488fe039ddd86a638496cf704df86c74eebDavid S. Miller		sch = qdisc_lookup(qdisc_dev(sch), TC_H_MAJ(parentid));
655ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy		if (sch == NULL) {
656ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy			WARN_ON(parentid != TC_H_ROOT);
657ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy			return;
658ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy		}
65943effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy		cops = sch->ops->cl_ops;
66043effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy		if (cops->qlen_notify) {
66143effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy			cl = cops->get(sch, parentid);
66243effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy			cops->qlen_notify(sch, cl);
66343effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy			cops->put(sch, cl);
66443effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy		}
66543effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy		sch->q.qlen -= n;
66643effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy	}
66743effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardy}
66843effa1e57fc4635e0301b27d78f9d83afe78974Patrick McHardyEXPORT_SYMBOL(qdisc_tree_decrease_qlen);
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6707316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic void notify_and_destroy(struct net *net, struct sk_buff *skb,
6717316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff			       struct nlmsghdr *n, u32 clid,
67299194cff398d056e5ee469647c294466c246c88aDavid S. Miller			       struct Qdisc *old, struct Qdisc *new)
67399194cff398d056e5ee469647c294466c246c88aDavid S. Miller{
67499194cff398d056e5ee469647c294466c246c88aDavid S. Miller	if (new || old)
6757316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff		qdisc_notify(net, skb, n, clid, old, new);
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6774d8863a29c4755a0461cd31b6865026187d6c43aDavid S. Miller	if (old)
67899194cff398d056e5ee469647c294466c246c88aDavid S. Miller		qdisc_destroy(old);
67999194cff398d056e5ee469647c294466c246c88aDavid S. Miller}
68099194cff398d056e5ee469647c294466c246c88aDavid S. Miller
68199194cff398d056e5ee469647c294466c246c88aDavid S. Miller/* Graft qdisc "new" to class "classid" of qdisc "parent" or
68299194cff398d056e5ee469647c294466c246c88aDavid S. Miller * to device "dev".
68399194cff398d056e5ee469647c294466c246c88aDavid S. Miller *
68499194cff398d056e5ee469647c294466c246c88aDavid S. Miller * When appropriate send a netlink notification using 'skb'
68599194cff398d056e5ee469647c294466c246c88aDavid S. Miller * and "n".
68699194cff398d056e5ee469647c294466c246c88aDavid S. Miller *
68799194cff398d056e5ee469647c294466c246c88aDavid S. Miller * On success, destroy old qdisc.
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
69199194cff398d056e5ee469647c294466c246c88aDavid S. Miller		       struct sk_buff *skb, struct nlmsghdr *n, u32 classid,
69299194cff398d056e5ee469647c294466c246c88aDavid S. Miller		       struct Qdisc *new, struct Qdisc *old)
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
69499194cff398d056e5ee469647c294466c246c88aDavid S. Miller	struct Qdisc *q = old;
6957316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff	struct net *net = dev_net(dev);
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0;
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
69810297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki	if (parent == NULL) {
69999194cff398d056e5ee469647c294466c246c88aDavid S. Miller		unsigned int i, num_q, ingress;
70099194cff398d056e5ee469647c294466c246c88aDavid S. Miller
70199194cff398d056e5ee469647c294466c246c88aDavid S. Miller		ingress = 0;
70299194cff398d056e5ee469647c294466c246c88aDavid S. Miller		num_q = dev->num_tx_queues;
7038d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller		if ((q && q->flags & TCQ_F_INGRESS) ||
7048d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller		    (new && new->flags & TCQ_F_INGRESS)) {
70599194cff398d056e5ee469647c294466c246c88aDavid S. Miller			num_q = 1;
70699194cff398d056e5ee469647c294466c246c88aDavid S. Miller			ingress = 1;
70724824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet			if (!dev_ingress_queue(dev))
70824824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet				return -ENOENT;
70999194cff398d056e5ee469647c294466c246c88aDavid S. Miller		}
71099194cff398d056e5ee469647c294466c246c88aDavid S. Miller
71199194cff398d056e5ee469647c294466c246c88aDavid S. Miller		if (dev->flags & IFF_UP)
71299194cff398d056e5ee469647c294466c246c88aDavid S. Miller			dev_deactivate(dev);
71399194cff398d056e5ee469647c294466c246c88aDavid S. Miller
7146ec1c69a8f6492fd25722f4762721921da074c12David S. Miller		if (new && new->ops->attach) {
7156ec1c69a8f6492fd25722f4762721921da074c12David S. Miller			new->ops->attach(new);
7166ec1c69a8f6492fd25722f4762721921da074c12David S. Miller			num_q = 0;
7176ec1c69a8f6492fd25722f4762721921da074c12David S. Miller		}
7186ec1c69a8f6492fd25722f4762721921da074c12David S. Miller
71999194cff398d056e5ee469647c294466c246c88aDavid S. Miller		for (i = 0; i < num_q; i++) {
72024824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet			struct netdev_queue *dev_queue = dev_ingress_queue(dev);
72199194cff398d056e5ee469647c294466c246c88aDavid S. Miller
72299194cff398d056e5ee469647c294466c246c88aDavid S. Miller			if (!ingress)
72399194cff398d056e5ee469647c294466c246c88aDavid S. Miller				dev_queue = netdev_get_tx_queue(dev, i);
72499194cff398d056e5ee469647c294466c246c88aDavid S. Miller
7258d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller			old = dev_graft_qdisc(dev_queue, new);
7268d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller			if (new && i > 0)
7278d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller				atomic_inc(&new->refcnt);
7288d50b53d66a8a6ae41bafbdcabe401467803f33aDavid S. Miller
729036d6a673fa0a2e2c5b72a3b1d1b86114c1711c0Jarek Poplawski			if (!ingress)
730036d6a673fa0a2e2c5b72a3b1d1b86114c1711c0Jarek Poplawski				qdisc_destroy(old);
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
73299194cff398d056e5ee469647c294466c246c88aDavid S. Miller
733036d6a673fa0a2e2c5b72a3b1d1b86114c1711c0Jarek Poplawski		if (!ingress) {
7347316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff			notify_and_destroy(net, skb, n, classid,
7357316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff					   dev->qdisc, new);
736036d6a673fa0a2e2c5b72a3b1d1b86114c1711c0Jarek Poplawski			if (new && !new->ops->attach)
737036d6a673fa0a2e2c5b72a3b1d1b86114c1711c0Jarek Poplawski				atomic_inc(&new->refcnt);
738036d6a673fa0a2e2c5b72a3b1d1b86114c1711c0Jarek Poplawski			dev->qdisc = new ? : &noop_qdisc;
739036d6a673fa0a2e2c5b72a3b1d1b86114c1711c0Jarek Poplawski		} else {
7407316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff			notify_and_destroy(net, skb, n, classid, old, new);
741036d6a673fa0a2e2c5b72a3b1d1b86114c1711c0Jarek Poplawski		}
742af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy
74399194cff398d056e5ee469647c294466c246c88aDavid S. Miller		if (dev->flags & IFF_UP)
74499194cff398d056e5ee469647c294466c246c88aDavid S. Miller			dev_activate(dev);
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
74620fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet		const struct Qdisc_class_ops *cops = parent->ops->cl_ops;
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
748c9f1d0389b962521af1e2b699c8ee5e299d77b85Patrick McHardy		err = -EOPNOTSUPP;
749c9f1d0389b962521af1e2b699c8ee5e299d77b85Patrick McHardy		if (cops && cops->graft) {
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			unsigned long cl = cops->get(parent, classid);
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (cl) {
75299194cff398d056e5ee469647c294466c246c88aDavid S. Miller				err = cops->graft(parent, cl, new, &old);
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				cops->put(parent, cl);
754c9f1d0389b962521af1e2b699c8ee5e299d77b85Patrick McHardy			} else
755c9f1d0389b962521af1e2b699c8ee5e299d77b85Patrick McHardy				err = -ENOENT;
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
75799194cff398d056e5ee469647c294466c246c88aDavid S. Miller		if (!err)
7587316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff			notify_and_destroy(net, skb, n, classid, old, new);
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
76325bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawski/* lockdep annotation is needed for ingress; egress gets it only for name */
76425bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawskistatic struct lock_class_key qdisc_tx_lock;
76525bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawskistatic struct lock_class_key qdisc_rx_lock;
76625bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawski
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Allocate and initialize new qdisc.
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Parameters are passed via opt.
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct Qdisc *
774bb949fbd1878973c3539d9aecff52f284482a937David S. Millerqdisc_create(struct net_device *dev, struct netdev_queue *dev_queue,
77523bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy	     struct Qdisc *p, u32 parent, u32 handle,
77623bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy	     struct nlattr **tca, int *errp)
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
7791e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	struct nlattr *kind = tca[TCA_KIND];
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *sch;
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc_ops *ops;
782175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	struct qdisc_size_table *stab;
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ops = qdisc_lookup_ops(kind);
78595a5afca4a8d2e1cb77e1d4bc6ff9f718dc32f7aJohannes Berg#ifdef CONFIG_MODULES
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ops == NULL && kind != NULL) {
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		char name[IFNAMSIZ];
7881e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		if (nla_strlcpy(name, kind, IFNAMSIZ) < IFNAMSIZ) {
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* We dropped the RTNL semaphore in order to
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * perform the module load.  So, even if we
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * succeeded in loading the module we have to
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * tell the caller to replay the request.  We
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * indicate this using -EAGAIN.
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * We replay the request because the device may
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * go away in the mean time.
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rtnl_unlock();
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			request_module("sch_%s", name);
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rtnl_lock();
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ops = qdisc_lookup_ops(kind);
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ops != NULL) {
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* We will try again qdisc_lookup_ops,
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * so don't keep a reference.
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 */
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				module_put(ops->owner);
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				err = -EAGAIN;
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto err_out;
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
813b9e2cc0f0e47ad351349156018ef8a365e9c6d25Jamal Hadi Salim	err = -ENOENT;
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ops == NULL)
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_out;
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8175ce2d488fe039ddd86a638496cf704df86c74eebDavid S. Miller	sch = qdisc_alloc(dev_queue, ops);
8183d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf	if (IS_ERR(sch)) {
8193d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf		err = PTR_ERR(sch);
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_out2;
8213d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf	}
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
823ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy	sch->parent = parent;
824ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy
8253d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf	if (handle == TC_H_INGRESS) {
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sch->flags |= TCQ_F_INGRESS;
8273d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf		handle = TC_H_MAKE(TC_H_INGRESS, 0);
82825bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawski		lockdep_set_class(qdisc_lock(sch), &qdisc_rx_lock);
829fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy	} else {
830fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy		if (handle == 0) {
831fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy			handle = qdisc_alloc_handle(dev);
832fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy			err = -ENOMEM;
833fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy			if (handle == 0)
834fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy				goto err_out3;
835fd44de7cc1d430caef91ad9aecec9ff000fe86f8Patrick McHardy		}
83625bfcd5a78a377ea4c54a3c21e44590e2fc478a6Jarek Poplawski		lockdep_set_class(qdisc_lock(sch), &qdisc_tx_lock);
8371abbe1394a84c10919e32242318e715b04d7e33bEric Dumazet		if (!netif_is_multiqueue(dev))
8381abbe1394a84c10919e32242318e715b04d7e33bEric Dumazet			sch->flags |= TCQ_F_ONETXQUEUE;
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8413d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf	sch->handle = handle;
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8431e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	if (!ops->init || (err = ops->init(sch, tca[TCA_OPTIONS])) == 0) {
844175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		if (tca[TCA_STAB]) {
845175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna			stab = qdisc_get_stab(tca[TCA_STAB]);
846175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna			if (IS_ERR(stab)) {
847175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna				err = PTR_ERR(stab);
8487c64b9f3f584008000cf3b960f25cd6a68fce191Jarek Poplawski				goto err_out4;
849175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna			}
850a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet			rcu_assign_pointer(sch->stab, stab);
851175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		}
8521e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		if (tca[TCA_RATE]) {
853f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski			spinlock_t *root_lock;
854f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski
85523bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy			err = -EOPNOTSUPP;
85623bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy			if (sch->flags & TCQ_F_MQROOT)
85723bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy				goto err_out4;
85823bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy
859f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski			if ((sch->parent != TC_H_ROOT) &&
86023bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy			    !(sch->flags & TCQ_F_INGRESS) &&
86123bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy			    (!p || !(p->flags & TCQ_F_MQROOT)))
862f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski				root_lock = qdisc_root_sleeping_lock(sch);
863f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski			else
864f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski				root_lock = qdisc_lock(sch);
865f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski
866023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf			err = gen_new_estimator(&sch->bstats, &sch->rate_est,
867f6f9b93f1624206c802ac9162c9302edaf59bfd9Jarek Poplawski						root_lock, tca[TCA_RATE]);
86823bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy			if (err)
86923bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy				goto err_out4;
870023e09a767a89bf1b8646307410852d93fd72f00Thomas Graf		}
871f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski
872f6e0b239a2657ea8cb67f0d83d0bfdbfd19a481bJarek Poplawski		qdisc_list_add(sch);
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return sch;
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out3:
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_put(dev);
8783d54b82fdf0ca79608f61448fb8ab92676487645Thomas Graf	kfree((char *) sch - sch->padded);
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out2:
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	module_put(ops->owner);
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out:
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*errp = err;
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
88423bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy
88523bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardyerr_out4:
88623bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy	/*
88723bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy	 * Any broken qdiscs that would require a ops->reset() here?
88823bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy	 * The qdisc was never in action so it shouldn't be necessary.
88923bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy	 */
890a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet	qdisc_put_stab(rtnl_dereference(sch->stab));
89123bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy	if (ops->destroy)
89223bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy		ops->destroy(sch);
89323bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy	goto err_out3;
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8961e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardystatic int qdisc_change(struct Qdisc *sch, struct nlattr **tca)
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
898a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet	struct qdisc_size_table *ostab, *stab = NULL;
899175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	int err = 0;
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
901175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (tca[TCA_OPTIONS]) {
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (sch->ops->change == NULL)
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
9041e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		err = sch->ops->change(sch, tca[TCA_OPTIONS]);
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (err)
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return err;
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
908175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
909175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	if (tca[TCA_STAB]) {
910175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		stab = qdisc_get_stab(tca[TCA_STAB]);
911175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		if (IS_ERR(stab))
912175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna			return PTR_ERR(stab);
913175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	}
914175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
915a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet	ostab = rtnl_dereference(sch->stab);
916a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet	rcu_assign_pointer(sch->stab, stab);
917a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet	qdisc_put_stab(ostab);
918175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
91923bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy	if (tca[TCA_RATE]) {
92071bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger		/* NB: ignores errors from replace_estimator
92171bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger		   because change can't be undone. */
92223bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy		if (sch->flags & TCQ_F_MQROOT)
92323bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy			goto out;
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		gen_replace_estimator(&sch->bstats, &sch->rate_est,
92571bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger					    qdisc_root_sleeping_lock(sch),
92671bcb09a57894fa35591ce93dd972065eeecb63aStephen Hemminger					    tca[TCA_RATE]);
92723bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardy	}
92823bcf634c8bc0d84607a5b863333191d58baee4cPatrick McHardyout:
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
932cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazetstruct check_loop_arg {
933cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	struct qdisc_walker	w;
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc		*p;
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			depth;
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int check_loop_fn(struct Qdisc *q, unsigned long cl, struct qdisc_walker *w);
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int check_loop(struct Qdisc *q, struct Qdisc *p, int depth)
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct check_loop_arg	arg;
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (q->ops->cl_ops == NULL)
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	arg.w.stop = arg.w.skip = arg.w.count = 0;
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	arg.w.fn = check_loop_fn;
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	arg.depth = depth;
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	arg.p = p;
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q->ops->cl_ops->walk(q, &arg.w);
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return arg.w.stop ? -ELOOP : 0;
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscheck_loop_fn(struct Qdisc *q, unsigned long cl, struct qdisc_walker *w)
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *leaf;
95920fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet	const struct Qdisc_class_ops *cops = q->ops->cl_ops;
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct check_loop_arg *arg = (struct check_loop_arg *)w;
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	leaf = cops->leaf(q, cl);
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (leaf) {
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (leaf == arg->p || arg->depth > 7)
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ELOOP;
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return check_loop(leaf, arg->p, arg->depth + 1);
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Delete/get qdisc.
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
975661d2967b3f1b34eeaa7e212e7b9bbe8ee072b59Thomas Grafstatic int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n)
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9773b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki	struct net *net = sock_net(skb->sk);
97802ef22ca4044fe90867f77cba720e4a442122826David S. Miller	struct tcmsg *tcm = nlmsg_data(n);
9791e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	struct nlattr *tca[TCA_MAX + 1];
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
981de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo	u32 clid;
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *q = NULL;
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *p = NULL;
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
986dfc47ef8639facd77210e74be831943c2fdd9c74Eric W. Biederman	if ((n->nlmsg_type != RTM_GETQDISC) && !capable(CAP_NET_ADMIN))
987dfc47ef8639facd77210e74be831943c2fdd9c74Eric W. Biederman		return -EPERM;
988dfc47ef8639facd77210e74be831943c2fdd9c74Eric W. Biederman
9891e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL);
9901e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	if (err < 0)
9911e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		return err;
9921e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy
993de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo	dev = __dev_get_by_index(net, tcm->tcm_ifindex);
994de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo	if (!dev)
995de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo		return -ENODEV;
996de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo
997de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo	clid = tcm->tcm_parent;
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clid) {
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (clid != TC_H_ROOT) {
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (TC_H_MAJ(clid) != TC_H_MAJ(TC_H_INGRESS)) {
1001cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				p = qdisc_lookup(dev, TC_H_MAJ(clid));
1002cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				if (!p)
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -ENOENT;
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				q = qdisc_leaf(p, clid);
1005cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet			} else if (dev_ingress_queue(dev)) {
1006cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				q = dev_ingress_queue(dev)->qdisc_sleeping;
100710297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki			}
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
1009af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy			q = dev->qdisc;
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!q)
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENOENT;
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tcm->tcm_handle && q->handle != tcm->tcm_handle)
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
1017cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet		q = qdisc_lookup(dev, tcm->tcm_handle);
1018cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet		if (!q)
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENOENT;
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10221e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], q->ops->id))
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (n->nlmsg_type == RTM_DELQDISC) {
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!clid)
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (q->handle == 0)
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENOENT;
1030cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet		err = qdisc_graft(dev, p, skb, n, clid, NULL, q);
1031cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet		if (err != 0)
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return err;
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
10347316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff		qdisc_notify(net, skb, n, clid, NULL, q);
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1040cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet * Create/change qdisc.
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1043661d2967b3f1b34eeaa7e212e7b9bbe8ee072b59Thomas Grafstatic int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n)
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10453b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki	struct net *net = sock_net(skb->sk);
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tcmsg *tcm;
10471e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	struct nlattr *tca[TCA_MAX + 1];
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 clid;
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *q, *p;
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1053dfc47ef8639facd77210e74be831943c2fdd9c74Eric W. Biederman	if (!capable(CAP_NET_ADMIN))
1054dfc47ef8639facd77210e74be831943c2fdd9c74Eric W. Biederman		return -EPERM;
1055dfc47ef8639facd77210e74be831943c2fdd9c74Eric W. Biederman
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreplay:
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Reinit, just in case something touches this. */
1058de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo	err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL);
1059de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo	if (err < 0)
1060de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo		return err;
1061de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo
106202ef22ca4044fe90867f77cba720e4a442122826David S. Miller	tcm = nlmsg_data(n);
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	clid = tcm->tcm_parent;
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q = p = NULL;
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1066cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	dev = __dev_get_by_index(net, tcm->tcm_ifindex);
1067cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	if (!dev)
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10701e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clid) {
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (clid != TC_H_ROOT) {
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (clid != TC_H_INGRESS) {
1074cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				p = qdisc_lookup(dev, TC_H_MAJ(clid));
1075cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				if (!p)
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -ENOENT;
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				q = qdisc_leaf(p, clid);
1078cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet			} else if (dev_ingress_queue_create(dev)) {
1079cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				q = dev_ingress_queue(dev)->qdisc_sleeping;
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
1082af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy			q = dev->qdisc;
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* It may be default qdisc, ignore it */
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (q && q->handle == 0)
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			q = NULL;
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!q || !tcm->tcm_handle || q->handle != tcm->tcm_handle) {
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (tcm->tcm_handle) {
1091cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				if (q && !(n->nlmsg_flags & NLM_F_REPLACE))
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -EEXIST;
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (TC_H_MIN(tcm->tcm_handle))
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -EINVAL;
1095cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				q = qdisc_lookup(dev, tcm->tcm_handle);
1096cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				if (!q)
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					goto create_n_graft;
1098cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				if (n->nlmsg_flags & NLM_F_EXCL)
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -EEXIST;
11001e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy				if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], q->ops->id))
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -EINVAL;
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (q == p ||
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    (p && check_loop(q, p, 0)))
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -ELOOP;
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				atomic_inc(&q->refcnt);
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto graft;
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
1108cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				if (!q)
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					goto create_n_graft;
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* This magic test requires explanation.
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   We know, that some child q is already
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   attached to this parent and have choice:
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   either to change it or to create/graft new one.
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   1. We are allowed to create/graft only
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   if CREATE and REPLACE flags are set.
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   2. If EXCL is set, requestor wanted to say,
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   that qdisc tcm_handle is not expected
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   to exist, so that we choose create/graft too.
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   3. The last case is when no flags are set.
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   Alas, it is sort of hole in API, we
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   cannot decide what to do unambiguously.
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   For now we select create/graft, if
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 *   user gave KIND, which does not match existing.
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 */
1130cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				if ((n->nlmsg_flags & NLM_F_CREATE) &&
1131cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				    (n->nlmsg_flags & NLM_F_REPLACE) &&
1132cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				    ((n->nlmsg_flags & NLM_F_EXCL) ||
11331e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy				     (tca[TCA_KIND] &&
11341e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy				      nla_strcmp(tca[TCA_KIND], q->ops->id))))
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					goto create_n_graft;
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!tcm->tcm_handle)
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		q = qdisc_lookup(dev, tcm->tcm_handle);
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Change qdisc parameters */
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (q == NULL)
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOENT;
1147cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	if (n->nlmsg_flags & NLM_F_EXCL)
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EEXIST;
11491e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], q->ops->id))
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = qdisc_change(q, tca);
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err == 0)
11537316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff		qdisc_notify(net, skb, n, clid, NULL, q);
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscreate_n_graft:
1157cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	if (!(n->nlmsg_flags & NLM_F_CREATE))
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOENT;
115924824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet	if (clid == TC_H_INGRESS) {
116024824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet		if (dev_ingress_queue(dev))
116124824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet			q = qdisc_create(dev, dev_ingress_queue(dev), p,
116224824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet					 tcm->tcm_parent, tcm->tcm_parent,
116324824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet					 tca, &err);
116424824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet		else
116524824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet			err = -ENOENT;
116624824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet	} else {
1167926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski		struct netdev_queue *dev_queue;
11686ec1c69a8f6492fd25722f4762721921da074c12David S. Miller
11696ec1c69a8f6492fd25722f4762721921da074c12David S. Miller		if (p && p->ops->cl_ops && p->ops->cl_ops->select_queue)
1170926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski			dev_queue = p->ops->cl_ops->select_queue(p, tcm);
1171926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski		else if (p)
1172926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski			dev_queue = p->dev_queue;
1173926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski		else
1174926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski			dev_queue = netdev_get_tx_queue(dev, 0);
11756ec1c69a8f6492fd25722f4762721921da074c12David S. Miller
1176926e61b7c44db83013159ac2f74bccd451607b5aJarek Poplawski		q = qdisc_create(dev, dev_queue, p,
1177bb949fbd1878973c3539d9aecff52f284482a937David S. Miller				 tcm->tcm_parent, tcm->tcm_handle,
1178ffc8fefaf289fa485bc5c33e71572e6ce559d569Patrick McHardy				 tca, &err);
11796ec1c69a8f6492fd25722f4762721921da074c12David S. Miller	}
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (q == NULL) {
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (err == -EAGAIN)
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto replay;
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return err;
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsgraft:
1187e5befbd9525d92bb074b70192eb2c69aae65fc60Ilpo Järvinen	err = qdisc_graft(dev, p, skb, n, clid, q, NULL);
1188e5befbd9525d92bb074b70192eb2c69aae65fc60Ilpo Järvinen	if (err) {
1189e5befbd9525d92bb074b70192eb2c69aae65fc60Ilpo Järvinen		if (q)
1190e5befbd9525d92bb074b70192eb2c69aae65fc60Ilpo Järvinen			qdisc_destroy(q);
1191e5befbd9525d92bb074b70192eb2c69aae65fc60Ilpo Järvinen		return err;
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1193e5befbd9525d92bb074b70192eb2c69aae65fc60Ilpo Järvinen
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid,
119815e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman			 u32 portid, u32 seq, u16 flags, int event)
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tcmsg *tcm;
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nlmsghdr  *nlh;
120227a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo	unsigned char *b = skb_tail_pointer(skb);
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct gnet_dump d;
1204a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet	struct qdisc_size_table *stab;
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
120615e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman	nlh = nlmsg_put(skb, portid, seq, event, sizeof(*tcm), flags);
120702ef22ca4044fe90867f77cba720e4a442122826David S. Miller	if (!nlh)
120802ef22ca4044fe90867f77cba720e4a442122826David S. Miller		goto out_nlmsg_trim;
120902ef22ca4044fe90867f77cba720e4a442122826David S. Miller	tcm = nlmsg_data(nlh);
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_family = AF_UNSPEC;
12119ef1d4c7c7aca1cd436612b6ca785b726ffb8ed8Patrick McHardy	tcm->tcm__pad1 = 0;
12129ef1d4c7c7aca1cd436612b6ca785b726ffb8ed8Patrick McHardy	tcm->tcm__pad2 = 0;
12135ce2d488fe039ddd86a638496cf704df86c74eebDavid S. Miller	tcm->tcm_ifindex = qdisc_dev(q)->ifindex;
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_parent = clid;
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_handle = q->handle;
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_info = atomic_read(&q->refcnt);
12171b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller	if (nla_put_string(skb, TCA_KIND, q->ops->id))
12181b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller		goto nla_put_failure;
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (q->ops->dump && q->ops->dump(q, skb) < 0)
12201e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q->qstats.qlen = q->q.qlen;
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1223a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet	stab = rtnl_dereference(q->stab);
1224a2da570d62fcb9e8816f6920e1ec02c706b289faEric Dumazet	if (stab && qdisc_dump_stab(skb, stab) < 0)
1225175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna		goto nla_put_failure;
1226175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna
1227102396ae65108b026e4e1868e30fa013f45a169eJarek Poplawski	if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, TCA_XSTATS,
1228102396ae65108b026e4e1868e30fa013f45a169eJarek Poplawski					 qdisc_root_sleeping_lock(q), &d) < 0)
12291e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (q->ops->dump_stats && q->ops->dump_stats(q, &d) < 0)
12321e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (gnet_stats_copy_basic(&d, &q->bstats) < 0 ||
1235d250a5f90e53f5e150618186230795352d154c88Eric Dumazet	    gnet_stats_copy_rate_est(&d, &q->bstats, &q->rate_est) < 0 ||
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    gnet_stats_copy_queue(&d, &q->qstats) < 0)
12371e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
123810297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (gnet_stats_finish_copy(&d) < 0)
12401e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
124110297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki
124227a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return skb->len;
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
124502ef22ca4044fe90867f77cba720e4a442122826David S. Millerout_nlmsg_trim:
12461e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardynla_put_failure:
1247dc5fc579b90ed0a9a4e55b0218cdbaf0a8cf2e67Arnaldo Carvalho de Melo	nlmsg_trim(skb, b);
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
125153b0f08042f04813cd1a7473dacd3edfacb28eb3Eric Dumazetstatic bool tc_qdisc_dump_ignore(struct Qdisc *q)
125253b0f08042f04813cd1a7473dacd3edfacb28eb3Eric Dumazet{
125353b0f08042f04813cd1a7473dacd3edfacb28eb3Eric Dumazet	return (q->flags & TCQ_F_BUILTIN) ? true : false;
125453b0f08042f04813cd1a7473dacd3edfacb28eb3Eric Dumazet}
125553b0f08042f04813cd1a7473dacd3edfacb28eb3Eric Dumazet
12567316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic int qdisc_notify(struct net *net, struct sk_buff *oskb,
12577316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff			struct nlmsghdr *n, u32 clid,
12587316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff			struct Qdisc *old, struct Qdisc *new)
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
126115e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman	u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!skb)
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOBUFS;
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
126753b0f08042f04813cd1a7473dacd3edfacb28eb3Eric Dumazet	if (old && !tc_qdisc_dump_ignore(old)) {
126815e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman		if (tc_fill_qdisc(skb, old, clid, portid, n->nlmsg_seq,
1269cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				  0, RTM_DELQDISC) < 0)
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto err_out;
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
127253b0f08042f04813cd1a7473dacd3edfacb28eb3Eric Dumazet	if (new && !tc_qdisc_dump_ignore(new)) {
127315e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman		if (tc_fill_qdisc(skb, new, clid, portid, n->nlmsg_seq,
1274cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				  old ? NLM_F_REPLACE : 0, RTM_NEWQDISC) < 0)
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto err_out;
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (skb->len)
127915e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman		return rtnetlink_send(skb, net, portid, RTNLGRP_TC,
1280cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet				      n->nlmsg_flags & NLM_F_ECHO);
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out:
12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree_skb(skb);
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EINVAL;
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12873072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerstatic int tc_dump_qdisc_root(struct Qdisc *root, struct sk_buff *skb,
12883072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			      struct netlink_callback *cb,
12893072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			      int *q_idx_p, int s_q_idx)
12903072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller{
12913072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	int ret = 0, q_idx = *q_idx_p;
12923072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	struct Qdisc *q;
12933072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
12943072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	if (!root)
12953072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		return 0;
12963072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
12973072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	q = root;
12983072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	if (q_idx < s_q_idx) {
12993072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		q_idx++;
13003072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	} else {
13013072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		if (!tc_qdisc_dump_ignore(q) &&
130215e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman		    tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).portid,
13033072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller				  cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0)
13043072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			goto done;
13053072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		q_idx++;
13063072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	}
13073072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	list_for_each_entry(q, &root->list, list) {
13083072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		if (q_idx < s_q_idx) {
13093072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			q_idx++;
13103072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			continue;
13113072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		}
1312cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet		if (!tc_qdisc_dump_ignore(q) &&
131315e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman		    tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).portid,
13143072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller				  cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0)
13153072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			goto done;
13163072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		q_idx++;
13173072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	}
13183072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
13193072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerout:
13203072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	*q_idx_p = q_idx;
13213072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	return ret;
13223072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerdone:
13233072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	ret = -1;
13243072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	goto out;
13253072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller}
13263072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13293b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki	struct net *net = sock_net(skb->sk);
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int idx, q_idx;
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int s_idx, s_q_idx;
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s_idx = cb->args[0];
13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s_q_idx = q_idx = cb->args[1];
1336f1e9016da6d0f16551d90085758ae45d26826118stephen hemminger
1337f1e9016da6d0f16551d90085758ae45d26826118stephen hemminger	rcu_read_lock();
13387562f876cd93800f2f8c89445f2a563590b24e09Pavel Emelianov	idx = 0;
13397316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff	for_each_netdev_rcu(net, dev) {
13403072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		struct netdev_queue *dev_queue;
13413072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (idx < s_idx)
13437562f876cd93800f2f8c89445f2a563590b24e09Pavel Emelianov			goto cont;
13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (idx > s_idx)
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			s_q_idx = 0;
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		q_idx = 0;
13473072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
1348af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy		if (tc_dump_qdisc_root(dev->qdisc, skb, cb, &q_idx, s_q_idx) < 0)
13493072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			goto done;
13503072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
135124824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet		dev_queue = dev_ingress_queue(dev);
135224824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet		if (dev_queue &&
135324824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet		    tc_dump_qdisc_root(dev_queue->qdisc_sleeping, skb, cb,
135424824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet				       &q_idx, s_q_idx) < 0)
13553072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			goto done;
13563072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
13577562f876cd93800f2f8c89445f2a563590b24e09Pavel Emelianovcont:
13587562f876cd93800f2f8c89445f2a563590b24e09Pavel Emelianov		idx++;
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdone:
1362f1e9016da6d0f16551d90085758ae45d26826118stephen hemminger	rcu_read_unlock();
13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cb->args[0] = idx;
13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cb->args[1] = q_idx;
13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return skb->len;
13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/************************************************
13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Traffic classes manipulation.		*
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ************************************************/
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1378661d2967b3f1b34eeaa7e212e7b9bbe8ee072b59Thomas Grafstatic int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n)
13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13803b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki	struct net *net = sock_net(skb->sk);
138102ef22ca4044fe90867f77cba720e4a442122826David S. Miller	struct tcmsg *tcm = nlmsg_data(n);
13821e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	struct nlattr *tca[TCA_MAX + 1];
13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *q = NULL;
138520fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet	const struct Qdisc_class_ops *cops;
13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long cl = 0;
13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long new_cl;
1388de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo	u32 portid;
1389de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo	u32 clid;
1390de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo	u32 qid;
13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1393dfc47ef8639facd77210e74be831943c2fdd9c74Eric W. Biederman	if ((n->nlmsg_type != RTM_GETTCLASS) && !capable(CAP_NET_ADMIN))
1394dfc47ef8639facd77210e74be831943c2fdd9c74Eric W. Biederman		return -EPERM;
1395dfc47ef8639facd77210e74be831943c2fdd9c74Eric W. Biederman
13961e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL);
13971e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	if (err < 0)
13981e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		return err;
13991e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy
1400de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo	dev = __dev_get_by_index(net, tcm->tcm_ifindex);
1401de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo	if (!dev)
1402de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo		return -ENODEV;
1403de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo
14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   parent == TC_H_UNSPEC - unspecified parent.
14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   parent == TC_H_ROOT   - class is root, which has no parent.
14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   parent == X:0	 - parent is root class.
14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   parent == X:Y	 - parent is a node in hierarchy.
14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   parent == 0:Y	 - parent is X:Y, where X:0 is qdisc.
14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   handle == 0:0	 - generate handle from kernel pool.
14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   handle == 0:Y	 - class is X:Y, where X:0 is qdisc.
14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   handle == X:Y	 - clear.
14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   handle == X:0	 - root class.
14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Step 1. Determine qdisc handle X:0 */
14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1419de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo	portid = tcm->tcm_parent;
1420de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo	clid = tcm->tcm_handle;
1421de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo	qid = TC_H_MAJ(clid);
1422de179c8c12e9e5a292269fa59e7c26ca797dc7bfHong zhi guo
142315e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman	if (portid != TC_H_ROOT) {
142415e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman		u32 qid1 = TC_H_MAJ(portid);
14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (qid && qid1) {
14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* If both majors are known, they must be identical. */
14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (qid != qid1)
14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -EINVAL;
14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (qid1) {
14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			qid = qid1;
14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (qid == 0)
1433af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy			qid = dev->qdisc->handle;
14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Now qid is genuine qdisc handle consistent
1436cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet		 * both with parent and child.
1437cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet		 *
143815e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman		 * TC_H_MAJ(portid) still may be unspecified, complete it now.
14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
144015e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman		if (portid)
144115e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman			portid = TC_H_MAKE(qid, portid);
14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (qid == 0)
1444af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy			qid = dev->qdisc->handle;
14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* OK. Locate qdisc */
1448cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	q = qdisc_lookup(dev, qid);
1449cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	if (!q)
14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOENT;
14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* An check that it supports classes */
14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cops = q->ops->cl_ops;
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cops == NULL)
14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Now try to get class */
14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clid == 0) {
145915e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman		if (portid == TC_H_ROOT)
14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			clid = qid;
14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		clid = TC_H_MAKE(qid, clid);
14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clid)
14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cl = cops->get(q, clid);
14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cl == 0) {
14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -ENOENT;
1469cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet		if (n->nlmsg_type != RTM_NEWTCLASS ||
1470cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet		    !(n->nlmsg_flags & NLM_F_CREATE))
14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (n->nlmsg_type) {
147410297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki		case RTM_NEWTCLASS:
14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = -EEXIST;
1476cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet			if (n->nlmsg_flags & NLM_F_EXCL)
14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto out;
14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case RTM_DELTCLASS:
1480de6d5cdf881353f83006d5f3e28ac4fffd42145ePatrick McHardy			err = -EOPNOTSUPP;
1481de6d5cdf881353f83006d5f3e28ac4fffd42145ePatrick McHardy			if (cops->delete)
1482de6d5cdf881353f83006d5f3e28ac4fffd42145ePatrick McHardy				err = cops->delete(q, cl);
14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (err == 0)
14847316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff				tclass_notify(net, skb, n, q, cl, RTM_DELTCLASS);
14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case RTM_GETTCLASS:
14877316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff			err = tclass_notify(net, skb, n, q, cl, RTM_NEWTCLASS);
14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = -EINVAL;
14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	new_cl = cl;
1496de6d5cdf881353f83006d5f3e28ac4fffd42145ePatrick McHardy	err = -EOPNOTSUPP;
1497de6d5cdf881353f83006d5f3e28ac4fffd42145ePatrick McHardy	if (cops->change)
149815e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman		err = cops->change(q, clid, portid, tca, &new_cl);
14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err == 0)
15007316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff		tclass_notify(net, skb, n, q, new_cl, RTM_NEWTCLASS);
15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cl)
15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cops->put(q, cl);
15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_fill_tclass(struct sk_buff *skb, struct Qdisc *q,
15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  unsigned long cl,
151215e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman			  u32 portid, u32 seq, u16 flags, int event)
15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tcmsg *tcm;
15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nlmsghdr  *nlh;
151627a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo	unsigned char *b = skb_tail_pointer(skb);
15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct gnet_dump d;
151820fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazet	const struct Qdisc_class_ops *cl_ops = q->ops->cl_ops;
15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
152015e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman	nlh = nlmsg_put(skb, portid, seq, event, sizeof(*tcm), flags);
152102ef22ca4044fe90867f77cba720e4a442122826David S. Miller	if (!nlh)
152202ef22ca4044fe90867f77cba720e4a442122826David S. Miller		goto out_nlmsg_trim;
152302ef22ca4044fe90867f77cba720e4a442122826David S. Miller	tcm = nlmsg_data(nlh);
15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_family = AF_UNSPEC;
152516ebb5e0b36ceadc8186f71d68b0c4fa4b6e781bEric Dumazet	tcm->tcm__pad1 = 0;
152616ebb5e0b36ceadc8186f71d68b0c4fa4b6e781bEric Dumazet	tcm->tcm__pad2 = 0;
15275ce2d488fe039ddd86a638496cf704df86c74eebDavid S. Miller	tcm->tcm_ifindex = qdisc_dev(q)->ifindex;
15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_parent = q->handle;
15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_handle = q->handle;
15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_info = 0;
15311b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller	if (nla_put_string(skb, TCA_KIND, q->ops->id))
15321b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller		goto nla_put_failure;
15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cl_ops->dump && cl_ops->dump(q, cl, skb, tcm) < 0)
15341e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1536102396ae65108b026e4e1868e30fa013f45a169eJarek Poplawski	if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, TCA_XSTATS,
1537102396ae65108b026e4e1868e30fa013f45a169eJarek Poplawski					 qdisc_root_sleeping_lock(q), &d) < 0)
15381e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cl_ops->dump_stats && cl_ops->dump_stats(q, cl, &d) < 0)
15411e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (gnet_stats_finish_copy(&d) < 0)
15441e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy		goto nla_put_failure;
15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
154627a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return skb->len;
15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
154902ef22ca4044fe90867f77cba720e4a442122826David S. Millerout_nlmsg_trim:
15501e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardynla_put_failure:
1551dc5fc579b90ed0a9a4e55b0218cdbaf0a8cf2e67Arnaldo Carvalho de Melo	nlmsg_trim(skb, b);
15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15557316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic int tclass_notify(struct net *net, struct sk_buff *oskb,
15567316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff			 struct nlmsghdr *n, struct Qdisc *q,
15577316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff			 unsigned long cl, int event)
15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
156015e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman	u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!skb)
15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOBUFS;
15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
156615e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman	if (tc_fill_tclass(skb, q, cl, portid, n->nlmsg_seq, 0, event) < 0) {
15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree_skb(skb);
15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
157115e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman	return rtnetlink_send(skb, net, portid, RTNLGRP_TC,
1572cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet			      n->nlmsg_flags & NLM_F_ECHO);
15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1575cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazetstruct qdisc_dump_args {
1576cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	struct qdisc_walker	w;
1577cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	struct sk_buff		*skb;
1578cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	struct netlink_callback	*cb;
15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int qdisc_class_dump(struct Qdisc *q, unsigned long cl, struct qdisc_walker *arg)
15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct qdisc_dump_args *a = (struct qdisc_dump_args *)arg;
15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
158515e473046cb6e5d18a4d0057e61d76315230382bEric W. Biederman	return tc_fill_tclass(a->skb, q, cl, NETLINK_CB(a->cb->skb).portid,
15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      a->cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWTCLASS);
15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15893072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerstatic int tc_dump_tclass_qdisc(struct Qdisc *q, struct sk_buff *skb,
15903072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller				struct tcmsg *tcm, struct netlink_callback *cb,
15913072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller				int *t_p, int s_t)
15923072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller{
15933072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	struct qdisc_dump_args arg;
15943072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
15953072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	if (tc_qdisc_dump_ignore(q) ||
15963072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	    *t_p < s_t || !q->ops->cl_ops ||
15973072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	    (tcm->tcm_parent &&
15983072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	     TC_H_MAJ(tcm->tcm_parent) != q->handle)) {
15993072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		(*t_p)++;
16003072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		return 0;
16013072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	}
16023072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	if (*t_p > s_t)
16033072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(cb->args[0]));
16043072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	arg.w.fn = qdisc_class_dump;
16053072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	arg.skb = skb;
16063072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	arg.cb = cb;
16073072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	arg.w.stop  = 0;
16083072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	arg.w.skip = cb->args[1];
16093072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	arg.w.count = 0;
16103072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	q->ops->cl_ops->walk(q, &arg.w);
16113072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	cb->args[1] = arg.w.count;
16123072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	if (arg.w.stop)
16133072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		return -1;
16143072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	(*t_p)++;
16153072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	return 0;
16163072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller}
16173072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
16183072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerstatic int tc_dump_tclass_root(struct Qdisc *root, struct sk_buff *skb,
16193072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			       struct tcmsg *tcm, struct netlink_callback *cb,
16203072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			       int *t_p, int s_t)
16213072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller{
16223072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	struct Qdisc *q;
16233072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
16243072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	if (!root)
16253072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		return 0;
16263072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
16273072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	if (tc_dump_tclass_qdisc(root, skb, tcm, cb, t_p, s_t) < 0)
16283072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		return -1;
16293072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
16303072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	list_for_each_entry(q, &root->list, list) {
16313072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		if (tc_dump_tclass_qdisc(q, skb, tcm, cb, t_p, s_t) < 0)
16323072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller			return -1;
16333072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	}
16343072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
16353072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	return 0;
16363072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller}
16373072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb)
16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
164002ef22ca4044fe90867f77cba720e4a442122826David S. Miller	struct tcmsg *tcm = nlmsg_data(cb->nlh);
16413b1e0a655f8eba44ab1ee2a1068d169ccfb853b9YOSHIFUJI Hideaki	struct net *net = sock_net(skb->sk);
16423072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	struct netdev_queue *dev_queue;
16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
16443072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller	int t, s_t;
16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1646573ce260b385a4d14a1ef046558fad9f1daeee42Hong zhi guo	if (nlmsg_len(cb->nlh) < sizeof(*tcm))
16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
1648cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	dev = dev_get_by_index(net, tcm->tcm_ifindex);
1649cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	if (!dev)
16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s_t = cb->args[0];
16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	t = 0;
16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1655af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02aPatrick McHardy	if (tc_dump_tclass_root(dev->qdisc, skb, tcm, cb, &t, s_t) < 0)
16563072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		goto done;
16573072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller
165824824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet	dev_queue = dev_ingress_queue(dev);
165924824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet	if (dev_queue &&
166024824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet	    tc_dump_tclass_root(dev_queue->qdisc_sleeping, skb, tcm, cb,
166124824a09e35402b8d58dcc5be803a5ad3937bdbaEric Dumazet				&t, s_t) < 0)
16623072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Miller		goto done;
16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16643072367300aa8c779e3a14ee8e89de079e90f3adDavid S. Millerdone:
16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cb->args[0] = t;
16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_put(dev);
16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return skb->len;
16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Main classifier routine: scans classifier chain attached
1672cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet * to this qdisc, (optionally) tests for protocol and asks
1673cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet * specific classifiers.
16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1675dc7f9f6e8838556f226c2ebd1da7bb305cb25654Eric Dumazetint tc_classify_compat(struct sk_buff *skb, const struct tcf_proto *tp,
167673ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		       struct tcf_result *res)
167773ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy{
167873ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy	__be16 protocol = skb->protocol;
1679cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	int err;
168073ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy
168173ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy	for (; tp; tp = tp->next) {
1682cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet		if (tp->protocol != protocol &&
1683cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet		    tp->protocol != htons(ETH_P_ALL))
1684cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet			continue;
1685cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet		err = tp->classify(skb, tp, res);
1686cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet
1687cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet		if (err >= 0) {
168873ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy#ifdef CONFIG_NET_CLS_ACT
168973ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy			if (err != TC_ACT_RECLASSIFY && skb->tc_verd)
169073ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy				skb->tc_verd = SET_TC_VERD(skb->tc_verd, 0);
169173ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy#endif
169273ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy			return err;
169373ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		}
169473ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy	}
169573ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy	return -1;
169673ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy}
169773ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardyEXPORT_SYMBOL(tc_classify_compat);
169873ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy
1699dc7f9f6e8838556f226c2ebd1da7bb305cb25654Eric Dumazetint tc_classify(struct sk_buff *skb, const struct tcf_proto *tp,
170073ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		struct tcf_result *res)
17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0;
17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_NET_CLS_ACT
1704dc7f9f6e8838556f226c2ebd1da7bb305cb25654Eric Dumazet	const struct tcf_proto *otp = tp;
17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreclassify:
170652bc97470e22e67f11b054e51a31eee100ef6867Hagen Paul Pfeifer#endif
17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
170873ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy	err = tc_classify_compat(skb, tp, res);
17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_NET_CLS_ACT
171073ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy	if (err == TC_ACT_RECLASSIFY) {
171173ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		u32 verd = G_TC_VERD(skb->tc_verd);
171273ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		tp = otp;
171373ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy
171473ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		if (verd++ >= MAX_REC_LOOP) {
1715e87cc4728f0e2fb663e592a1141742b1d6c63256Joe Perches			net_notice_ratelimited("%s: packet reclassify loop rule prio %u protocol %02x\n",
1716e87cc4728f0e2fb663e592a1141742b1d6c63256Joe Perches					       tp->q->ops->id,
1717e87cc4728f0e2fb663e592a1141742b1d6c63256Joe Perches					       tp->prio & 0xffff,
1718e87cc4728f0e2fb663e592a1141742b1d6c63256Joe Perches					       ntohs(tp->protocol));
171973ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy			return TC_ACT_SHOT;
17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
172173ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		skb->tc_verd = SET_TC_VERD(skb->tc_verd, verd);
172273ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy		goto reclassify;
17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
172473ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy#endif
172573ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardy	return err;
17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
172773ca4918fbb98311421259d82ef4ab44feeace43Patrick McHardyEXPORT_SYMBOL(tc_classify);
17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1729a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardyvoid tcf_destroy(struct tcf_proto *tp)
1730a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy{
1731a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy	tp->ops->destroy(tp);
1732a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy	module_put(tp->ops->owner);
1733a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy	kfree(tp);
1734a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy}
1735a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy
1736ff31ab56c0e900235f653e375fc3b01ba2d8d6a3Patrick McHardyvoid tcf_destroy_chain(struct tcf_proto **fl)
1737a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy{
1738a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy	struct tcf_proto *tp;
1739a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy
1740ff31ab56c0e900235f653e375fc3b01ba2d8d6a3Patrick McHardy	while ((tp = *fl) != NULL) {
1741ff31ab56c0e900235f653e375fc3b01ba2d8d6a3Patrick McHardy		*fl = tp->next;
1742a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy		tcf_destroy(tp);
1743a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy	}
1744a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy}
1745a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardyEXPORT_SYMBOL(tcf_destroy_chain);
1746a48b5a61448899040dfbd2e0cd55b06a2bd2466cPatrick McHardy
17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PROC_FS
17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int psched_show(struct seq_file *seq, void *v)
17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17503c0cfc135829b98f7a4894938652f9ef78e24237Patrick McHardy	struct timespec ts;
17513c0cfc135829b98f7a4894938652f9ef78e24237Patrick McHardy
17523c0cfc135829b98f7a4894938652f9ef78e24237Patrick McHardy	hrtimer_get_res(CLOCK_MONOTONIC, &ts);
17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	seq_printf(seq, "%08x %08x %08x %08x\n",
1754ca44d6e60f9de26281fda203f58b570e1748c015Jarek Poplawski		   (u32)NSEC_PER_USEC, (u32)PSCHED_TICKS2NS(1),
1755514bca322cb9220308d22691ac1e74038bfabac3Patrick McHardy		   1000000,
17563c0cfc135829b98f7a4894938652f9ef78e24237Patrick McHardy		   (u32)NSEC_PER_SEC/(u32)ktime_to_ns(timespec_to_ktime(ts)));
17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int psched_open(struct inode *inode, struct file *file)
17621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17637e5ab157813993356f021757d0b0dcbdca7c55a1Tom Goff	return single_open(file, psched_show, NULL);
17641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1766da7071d7e32d15149cc513f096a3638097b66387Arjan van de Venstatic const struct file_operations psched_fops = {
17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner = THIS_MODULE,
17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.open = psched_open,
17691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read  = seq_read,
17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.llseek = seq_lseek,
17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.release = single_release,
177210297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki};
17737316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff
17747316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic int __net_init psched_net_init(struct net *net)
17757316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff{
17767316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff	struct proc_dir_entry *e;
17777316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff
1778d4beaa66add8aebf83ab16d2fde4e4de8dac36dfGao feng	e = proc_create("psched", 0, net->proc_net, &psched_fops);
17797316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff	if (e == NULL)
17807316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff		return -ENOMEM;
17817316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff
17827316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff	return 0;
17837316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff}
17847316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff
17857316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic void __net_exit psched_net_exit(struct net *net)
17867316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff{
1787ece31ffd539e8e2b586b1ca5f50bc4f4591e3893Gao feng	remove_proc_entry("psched", net->proc_net);
17887316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff}
17897316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff#else
17907316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic int __net_init psched_net_init(struct net *net)
17917316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff{
17927316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff	return 0;
17937316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff}
17947316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff
17957316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic void __net_exit psched_net_exit(struct net *net)
17967316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff{
17977316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff}
17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18007316ae88c43d47f6503f4c29b4973204e33c3411Tom Goffstatic struct pernet_operations psched_net_ops = {
18017316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff	.init = psched_net_init,
18027316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff	.exit = psched_net_exit,
18037316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff};
18047316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff
18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init pktsched_init(void)
18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
18077316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff	int err;
18087316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff
18097316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff	err = register_pernet_subsys(&psched_net_ops);
18107316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff	if (err) {
1811cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet		pr_err("pktsched_init: "
18127316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff		       "cannot initialize per netns operations\n");
18137316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff		return err;
18147316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff	}
18157316ae88c43d47f6503f4c29b4973204e33c3411Tom Goff
18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register_qdisc(&pfifo_qdisc_ops);
18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register_qdisc(&bfifo_qdisc_ops);
181857dbb2d83d100ea601c54fe129bfde0678db5deeHagen Paul Pfeifer	register_qdisc(&pfifo_head_drop_qdisc_ops);
18196ec1c69a8f6492fd25722f4762721921da074c12David S. Miller	register_qdisc(&mq_qdisc_ops);
18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1821c7ac8679bec9397afe8918f788cbcef88c38da54Greg Rose	rtnl_register(PF_UNSPEC, RTM_NEWQDISC, tc_modify_qdisc, NULL, NULL);
1822c7ac8679bec9397afe8918f788cbcef88c38da54Greg Rose	rtnl_register(PF_UNSPEC, RTM_DELQDISC, tc_get_qdisc, NULL, NULL);
1823c7ac8679bec9397afe8918f788cbcef88c38da54Greg Rose	rtnl_register(PF_UNSPEC, RTM_GETQDISC, tc_get_qdisc, tc_dump_qdisc, NULL);
1824c7ac8679bec9397afe8918f788cbcef88c38da54Greg Rose	rtnl_register(PF_UNSPEC, RTM_NEWTCLASS, tc_ctl_tclass, NULL, NULL);
1825c7ac8679bec9397afe8918f788cbcef88c38da54Greg Rose	rtnl_register(PF_UNSPEC, RTM_DELTCLASS, tc_ctl_tclass, NULL, NULL);
1826c7ac8679bec9397afe8918f788cbcef88c38da54Greg Rose	rtnl_register(PF_UNSPEC, RTM_GETTCLASS, tc_ctl_tclass, tc_dump_tclass, NULL);
1827be577ddc2b4aca0849f701222f5bc13cf1b79c9aThomas Graf
18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssubsys_initcall(pktsched_init);
1832